summaryrefslogtreecommitdiffstats
path: root/svl/source/fsstor
diff options
context:
space:
mode:
Diffstat (limited to 'svl/source/fsstor')
-rw-r--r--svl/source/fsstor/fsfactory.cxx160
-rw-r--r--svl/source/fsstor/fsstorage.component27
-rw-r--r--svl/source/fsstor/fsstorage.cxx1102
-rw-r--r--svl/source/fsstor/fsstorage.hxx178
-rw-r--r--svl/source/fsstor/oinputstreamcontainer.cxx260
-rw-r--r--svl/source/fsstor/oinputstreamcontainer.hxx83
-rw-r--r--svl/source/fsstor/ostreamcontainer.cxx451
-rw-r--r--svl/source/fsstor/ostreamcontainer.hxx109
8 files changed, 2370 insertions, 0 deletions
diff --git a/svl/source/fsstor/fsfactory.cxx b/svl/source/fsstor/fsfactory.cxx
new file mode 100644
index 000000000..b611ff530
--- /dev/null
+++ b/svl/source/fsstor/fsfactory.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <fsfactory.hxx>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <ucbhelper/content.hxx>
+
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbhelper.hxx>
+
+#include "fsstorage.hxx"
+
+
+using namespace ::com::sun::star;
+
+
+uno::Reference< uno::XInterface > SAL_CALL FSStorageFactory::createInstance()
+{
+ OUString aTempURL = ::utl::TempFile( nullptr, true ).GetURL();
+
+ if ( aTempURL.isEmpty() )
+ throw uno::RuntimeException("Cannot create tempfile.");
+
+ ::ucbhelper::Content aResultContent(
+ aTempURL, uno::Reference< ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+
+ return uno::Reference< uno::XInterface >(
+ static_cast< OWeakObject* >(
+ new FSStorage( aResultContent,
+ embed::ElementModes::READWRITE,
+ m_xContext ) ),
+ uno::UNO_QUERY );
+}
+
+/**
+ * The request for storage can be done with up to three arguments.
+ * The first argument specifies a source for the storage it must be URL.
+ * The second value is a mode the storage should be open in.
+ * The third value is a media descriptor.
+ */
+uno::Reference< uno::XInterface > SAL_CALL FSStorageFactory::createInstanceWithArguments(
+ const uno::Sequence< uno::Any >& aArguments )
+{
+ sal_Int32 nArgNum = aArguments.getLength();
+ OSL_ENSURE( nArgNum < 4, "Wrong parameter number" );
+
+ if ( !nArgNum )
+ return createInstance();
+
+ // first try to retrieve storage open mode if any
+ // by default the storage will be open in readonly mode
+ sal_Int32 nStorageMode = embed::ElementModes::READ;
+ if ( nArgNum >= 2 )
+ {
+ if( !( aArguments[1] >>= nStorageMode ) )
+ {
+ throw lang::IllegalArgumentException(
+ ("second argument to css.embed.FileSystemStorageFactory."
+ "createInstanceWithArguments must be a"
+ " css.embed.ElementModes"),
+ static_cast< OWeakObject * >(this), -1);
+ }
+ // it's always possible to read written storage in this implementation
+ nStorageMode |= embed::ElementModes::READ;
+ }
+
+ // retrieve storage source URL
+ OUString aURL;
+
+ if ( !( aArguments[0] >>= aURL ) || aURL.isEmpty() )
+ {
+ throw lang::IllegalArgumentException(
+ ("first argument to"
+ " css.embed.FileSystemStorageFactory.createInstanceWithArguments"
+ " must be a (non-empty) URL"),
+ static_cast< OWeakObject * >(this), -1);
+ }
+
+ // allow to use other ucp's
+ // if ( !isLocalNotFile_Impl( aURL ) )
+ if ( aURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:")
+ || aURL.startsWithIgnoreAsciiCase("vnd.sun.star.zip:")
+ || ::utl::UCBContentHelper::IsDocument( aURL ) )
+ {
+ throw lang::IllegalArgumentException(
+ ("URL \"" + aURL + "\" passed as first argument to"
+ " css.embed.FileSystemStorageFactory.createInstanceWithArguments"
+ " must be a file URL denoting a directory"),
+ static_cast< OWeakObject * >(this), -1);
+ }
+
+ if ( ( nStorageMode & embed::ElementModes::WRITE ) && !( nStorageMode & embed::ElementModes::NOCREATE ) )
+ FSStorage::MakeFolderNoUI( aURL );
+ else if ( !::utl::UCBContentHelper::IsFolder( aURL ) )
+ throw io::IOException(
+ ("URL \"" + aURL + "\" passed to"
+ " css.embed.FileSystemStorageFactory.createInstanceWithArguments"
+ " does not denote an existing directory"),
+ static_cast< OWeakObject * >(this));
+
+ ::ucbhelper::Content aResultContent(
+ aURL, uno::Reference< ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+
+ // create storage based on source
+ return uno::Reference< uno::XInterface >(
+ static_cast< OWeakObject* >( new FSStorage( aResultContent,
+ nStorageMode,
+ m_xContext ) ),
+ uno::UNO_QUERY );
+}
+
+OUString SAL_CALL FSStorageFactory::getImplementationName()
+{
+ return "com.sun.star.comp.embed.FileSystemStorageFactory";
+}
+
+sal_Bool SAL_CALL FSStorageFactory::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL FSStorageFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.embed.FileSystemStorageFactory",
+ "com.sun.star.comp.embed.FileSystemStorageFactory" };
+}
+
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+svl_FSStorageFactory_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new FSStorageFactory(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/fsstorage.component b/svl/source/fsstor/fsstorage.component
new file mode 100644
index 000000000..7d20474b3
--- /dev/null
+++ b/svl/source/fsstor/fsstorage.component
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.embed.FileSystemStorageFactory"
+ constructor="svl_FSStorageFactory_get_implementation" single-instance="true">
+ <service name="com.sun.star.comp.embed.FileSystemStorageFactory"/>
+ <service name="com.sun.star.embed.FileSystemStorageFactory"/>
+ </implementation>
+</component>
diff --git a/svl/source/fsstor/fsstorage.cxx b/svl/source/fsstor/fsstorage.cxx
new file mode 100644
index 000000000..8d2da219d
--- /dev/null
+++ b/svl/source/fsstor/fsstorage.cxx
@@ -0,0 +1,1102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/InvalidStorageException.hpp>
+#include <com/sun/star/embed/StorageWrappedTargetException.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/packages/NoEncryptionException.hpp>
+#include <com/sun/star/packages/WrongPasswordException.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+#include <comphelper/fileurl.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+#include <osl/diagnose.h>
+#include <tools/urlobj.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <ucbhelper/content.hxx>
+
+#include "fsstorage.hxx"
+#include "oinputstreamcontainer.hxx"
+#include "ostreamcontainer.hxx"
+
+using namespace ::com::sun::star;
+
+FSStorage::FSStorage( const ::ucbhelper::Content& aContent,
+ sal_Int32 nMode,
+ uno::Reference< uno::XComponentContext > const & xContext )
+: m_aURL( aContent.getURL() )
+, m_aContent( aContent )
+, m_nMode( nMode )
+, m_xContext( xContext )
+{
+ OSL_ENSURE( !m_aURL.isEmpty(), "The URL must not be empty" );
+ // TODO: use properties
+ if ( !xContext.is() )
+ throw uno::RuntimeException();
+
+ GetContent();
+}
+
+FSStorage::~FSStorage()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ osl_atomic_increment(&m_refCount); // to call dispose
+ try {
+ dispose();
+ }
+ catch( uno::RuntimeException& )
+ {}
+}
+
+bool FSStorage::MakeFolderNoUI( std::u16string_view rFolder )
+{
+ INetURLObject aURL( rFolder );
+ OUString aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ aURL.removeSegment();
+ ::ucbhelper::Content aParent;
+ ::ucbhelper::Content aResultContent;
+
+ if ( ::ucbhelper::Content::create( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ uno::Reference< ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext(),
+ aParent ) )
+ return ::utl::UCBContentHelper::MakeFolder( aParent, aTitle, aResultContent );
+
+ return false;
+}
+
+ucbhelper::Content& FSStorage::GetContent()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return m_aContent;
+}
+
+void FSStorage::CopyStreamToSubStream( const OUString& aSourceURL,
+ const uno::Reference< embed::XStorage >& xDest,
+ const OUString& aNewEntryName )
+{
+ if ( !xDest.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
+ ::ucbhelper::Content aSourceContent( aSourceURL, xDummyEnv, comphelper::getProcessComponentContext() );
+ uno::Reference< io::XInputStream > xSourceInput = aSourceContent.openStream();
+
+ if ( !xSourceInput.is() )
+ throw io::IOException(); // TODO: error handling
+
+ uno::Reference< io::XStream > xSubStream = xDest->openStreamElement(
+ aNewEntryName,
+ embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE );
+ if ( !xSubStream.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< io::XOutputStream > xDestOutput = xSubStream->getOutputStream();
+ if ( !xDestOutput.is() )
+ throw uno::RuntimeException();
+
+ ::comphelper::OStorageHelper::CopyInputToOutput( xSourceInput, xDestOutput );
+ xDestOutput->closeOutput();
+}
+
+void FSStorage::CopyContentToStorage_Impl(ucbhelper::Content& rContent,
+ const uno::Reference<embed::XStorage>& xDest)
+{
+ // get list of contents of the Content
+ // create cursor for access to children
+ uno::Sequence< OUString > aProps( 2 );
+ OUString* pProps = aProps.getArray();
+ pProps[0] = "TargetURL";
+ pProps[1] = "IsFolder";
+
+ try
+ {
+ uno::Reference<sdbc::XResultSet> xResultSet
+ = rContent.createCursor(aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS);
+ uno::Reference< sdbc::XRow > xRow( xResultSet, uno::UNO_QUERY );
+ if ( xResultSet.is() )
+ {
+ // go through the list: insert files as streams, insert folders as substorages using recursion
+ while ( xResultSet->next() )
+ {
+ OUString aSourceURL( xRow->getString( 1 ) );
+ bool bIsFolder( xRow->getBoolean(2) );
+
+ // TODO/LATER: not sure whether the entry name must be encoded
+ OUString aNewEntryName( INetURLObject( aSourceURL ).getName( INetURLObject::LAST_SEGMENT,
+ true,
+ INetURLObject::DecodeMechanism::NONE ) );
+ if ( bIsFolder )
+ {
+ uno::Reference< embed::XStorage > xSubStorage = xDest->openStorageElement( aNewEntryName,
+ embed::ElementModes::READWRITE );
+ if ( !xSubStorage.is() )
+ throw uno::RuntimeException();
+
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
+ ::ucbhelper::Content aSourceContent( aSourceURL, xDummyEnv, comphelper::getProcessComponentContext() );
+ CopyContentToStorage_Impl( aSourceContent, xSubStorage );
+ }
+ else
+ {
+ CopyStreamToSubStream( aSourceURL, xDest, aNewEntryName );
+ }
+ }
+ }
+
+ uno::Reference< embed::XTransactedObject > xTransact( xDest, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+ }
+ catch( ucb::InteractiveIOException& r )
+ {
+ if ( r.Code == ucb::IOErrorCode_NOT_EXISTING )
+ OSL_FAIL( "The folder does not exist!" );
+ else
+ throw;
+ }
+}
+
+// XInterface
+
+uno::Any SAL_CALL FSStorage::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<lang::XTypeProvider*> ( this )
+ , static_cast<embed::XStorage*> ( this )
+ , static_cast<embed::XHierarchicalStorageAccess*> ( this )
+ , static_cast<container::XNameAccess*> ( this )
+ , static_cast<container::XElementAccess*> ( this )
+ , static_cast<lang::XComponent*> ( this )
+ , static_cast<beans::XPropertySet*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+
+ return OWeakObject::queryInterface( rType );
+}
+
+void SAL_CALL FSStorage::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL FSStorage::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// XTypeProvider
+
+uno::Sequence< uno::Type > SAL_CALL FSStorage::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes {
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<embed::XStorage>::get(),
+ cppu::UnoType<embed::XHierarchicalStorageAccess>::get(),
+ cppu::UnoType<beans::XPropertySet>::get() };
+ return aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL FSStorage::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XStorage
+
+void SAL_CALL FSStorage::copyToStorage( const uno::Reference< embed::XStorage >& xDest )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !xDest.is() || xDest == uno::Reference< uno::XInterface >( static_cast< OWeakObject*> ( this ), uno::UNO_QUERY ) )
+ throw lang::IllegalArgumentException(); // TODO:
+
+ try
+ {
+ CopyContentToStorage_Impl( GetContent(), xDest );
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+}
+
+uno::Reference< io::XStream > SAL_CALL FSStorage::openStreamElement(
+ const OUString& aStreamName, sal_Int32 nOpenMode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO/LATER: may need possibility to create folder if it was removed, since the folder can not be locked
+ INetURLObject aFileURL( m_aURL );
+ aFileURL.Append( aStreamName );
+
+ if ( ::utl::UCBContentHelper::IsFolder( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw io::IOException();
+
+ if ( ( nOpenMode & embed::ElementModes::NOCREATE )
+ && !::utl::UCBContentHelper::IsDocument( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw io::IOException(); // TODO:
+
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv; // TODO: provide InteractionHandler if any
+ uno::Reference< io::XStream > xResult;
+ try
+ {
+ if ( nOpenMode & embed::ElementModes::WRITE )
+ {
+ if ( aFileURL.GetProtocol() == INetProtocol::File )
+ {
+ uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+ xResult = xSimpleFileAccess->openFileReadWrite( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ else
+ {
+ // TODO: test whether it really works for http and fwp
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ StreamMode::STD_WRITE );
+ if ( pStream && !pStream->GetError() )
+ xResult.set( new ::utl::OStreamWrapper( std::move(pStream) ) );
+ }
+
+ if ( !xResult.is() )
+ throw io::IOException();
+
+ if ( nOpenMode & embed::ElementModes::TRUNCATE )
+ {
+ uno::Reference< io::XTruncate > xTrunc( xResult->getOutputStream(), uno::UNO_QUERY_THROW );
+ xTrunc->truncate();
+ }
+ }
+ else
+ {
+ if ( ( nOpenMode & embed::ElementModes::TRUNCATE )
+ || !::utl::UCBContentHelper::IsDocument( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw io::IOException(); // TODO: access denied
+
+ ::ucbhelper::Content aResultContent( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
+ uno::Reference< io::XInputStream > xInStream = aResultContent.openStream();
+ xResult = new OFSInputStreamContainer(xInStream);
+ }
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( packages::WrongPasswordException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+
+ return xResult;
+}
+
+uno::Reference< io::XStream > SAL_CALL FSStorage::openEncryptedStreamElement(
+ const OUString&, sal_Int32, const OUString& )
+{
+ throw packages::NoEncryptionException();
+}
+
+uno::Reference< embed::XStorage > SAL_CALL FSStorage::openStorageElement(
+ const OUString& aStorName, sal_Int32 nStorageMode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( ( nStorageMode & embed::ElementModes::WRITE )
+ && !( m_nMode & embed::ElementModes::WRITE ) )
+ throw io::IOException(); // TODO: error handling
+
+ // TODO/LATER: may need possibility to create folder if it was removed, since the folder can not be locked
+ INetURLObject aFolderURL( m_aURL );
+ aFolderURL.Append( aStorName );
+
+ bool bFolderExists = ::utl::UCBContentHelper::IsFolder( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ if ( !bFolderExists && ::utl::UCBContentHelper::IsDocument( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw io::IOException(); // TODO:
+
+ if ( ( nStorageMode & embed::ElementModes::NOCREATE ) && !bFolderExists )
+ throw io::IOException(); // TODO:
+
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv; // TODO: provide InteractionHandler if any
+ uno::Reference< embed::XStorage > xResult;
+ try
+ {
+ if ( nStorageMode & embed::ElementModes::WRITE )
+ {
+ if ( ( nStorageMode & embed::ElementModes::TRUNCATE ) && bFolderExists )
+ {
+ ::utl::UCBContentHelper::Kill( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ bFolderExists =
+ MakeFolderNoUI( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); // TODO: not atomic :(
+ }
+ else if ( !bFolderExists )
+ {
+ bFolderExists =
+ MakeFolderNoUI( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); // TODO: not atomic :(
+ }
+ }
+ else if ( nStorageMode & embed::ElementModes::TRUNCATE )
+ throw io::IOException(); // TODO: access denied
+
+ if ( !bFolderExists )
+ throw io::IOException(); // there is no such folder
+
+ ::ucbhelper::Content aResultContent( aFolderURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
+ xResult = new FSStorage( aResultContent, nStorageMode, m_xContext );
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+
+ return xResult;
+}
+
+uno::Reference< io::XStream > SAL_CALL FSStorage::cloneStreamElement( const OUString& aStreamName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO/LATER: may need possibility to create folder if it was removed, since the folder can not be locked
+ INetURLObject aFileURL( m_aURL );
+ aFileURL.Append( aStreamName );
+
+ uno::Reference < io::XStream > xTempResult;
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
+ ::ucbhelper::Content aResultContent( aFileURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
+ uno::Reference< io::XInputStream > xInStream = aResultContent.openStream();
+
+ xTempResult = io::TempFile::create(m_xContext);
+ uno::Reference < io::XOutputStream > xTempOut = xTempResult->getOutputStream();
+ uno::Reference < io::XInputStream > xTempIn = xTempResult->getInputStream();
+
+ if ( !xTempOut.is() || !xTempIn.is() )
+ throw io::IOException();
+
+ ::comphelper::OStorageHelper::CopyInputToOutput( xInStream, xTempOut );
+ xTempOut->closeOutput();
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( packages::WrongPasswordException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+
+ return xTempResult;
+}
+
+uno::Reference< io::XStream > SAL_CALL FSStorage::cloneEncryptedStreamElement(
+ const OUString&,
+ const OUString& )
+{
+ throw packages::NoEncryptionException();
+}
+
+void SAL_CALL FSStorage::copyLastCommitTo(
+ const uno::Reference< embed::XStorage >& xTargetStorage )
+{
+ copyToStorage( xTargetStorage );
+}
+
+void SAL_CALL FSStorage::copyStorageElementLastCommitTo(
+ const OUString& aStorName,
+ const uno::Reference< embed::XStorage >& xTargetStorage )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ uno::Reference< embed::XStorage > xSourceStor( openStorageElement( aStorName, embed::ElementModes::READ ),
+ uno::UNO_SET_THROW );
+ xSourceStor->copyToStorage( xTargetStorage );
+}
+
+sal_Bool SAL_CALL FSStorage::isStreamElement( const OUString& aElementName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INetURLObject aURL( m_aURL );
+ aURL.Append( aElementName );
+
+ return !::utl::UCBContentHelper::IsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+}
+
+sal_Bool SAL_CALL FSStorage::isStorageElement( const OUString& aElementName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INetURLObject aURL( m_aURL );
+ aURL.Append( aElementName );
+
+ return ::utl::UCBContentHelper::IsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+}
+
+void SAL_CALL FSStorage::removeElement( const OUString& aElementName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INetURLObject aURL( m_aURL );
+ aURL.Append( aElementName );
+
+ if ( !::utl::UCBContentHelper::IsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) )
+ && !::utl::UCBContentHelper::IsDocument( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw container::NoSuchElementException(); // TODO:
+
+ ::utl::UCBContentHelper::Kill( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+}
+
+void SAL_CALL FSStorage::renameElement( const OUString& aElementName, const OUString& aNewName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INetURLObject aOldURL( m_aURL );
+ aOldURL.Append( aElementName );
+
+ INetURLObject aNewURL( m_aURL );
+ aNewURL.Append( aNewName );
+
+ if ( !::utl::UCBContentHelper::IsFolder( aOldURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) )
+ && !::utl::UCBContentHelper::IsDocument( aOldURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw container::NoSuchElementException(); // TODO:
+
+ if ( ::utl::UCBContentHelper::IsFolder( aNewURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) )
+ || ::utl::UCBContentHelper::IsDocument( aNewURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw container::ElementExistException(); // TODO:
+
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
+ ::ucbhelper::Content aSourceContent( aOldURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
+
+ GetContent().transferContent(aSourceContent, ::ucbhelper::InsertOperation::Move, aNewName,
+ ucb::NameClash::ERROR);
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( container::NoSuchElementException& )
+ {
+ throw;
+ }
+ catch( container::ElementExistException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+}
+
+void SAL_CALL FSStorage::copyElementTo( const OUString& aElementName,
+ const uno::Reference< embed::XStorage >& xDest,
+ const OUString& aNewName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !xDest.is() )
+ throw uno::RuntimeException();
+
+ INetURLObject aOwnURL( m_aURL );
+ aOwnURL.Append( aElementName );
+
+ if ( xDest->hasByName( aNewName ) )
+ throw container::ElementExistException(); // TODO:
+
+ try
+ {
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv;
+ if ( ::utl::UCBContentHelper::IsFolder( aOwnURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ {
+ ::ucbhelper::Content aSourceContent( aOwnURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDummyEnv, comphelper::getProcessComponentContext() );
+ uno::Reference< embed::XStorage > xDestSubStor(
+ xDest->openStorageElement( aNewName, embed::ElementModes::READWRITE ),
+ uno::UNO_SET_THROW );
+
+ CopyContentToStorage_Impl( aSourceContent, xDestSubStor );
+ }
+ else if ( ::utl::UCBContentHelper::IsDocument( aOwnURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ {
+ CopyStreamToSubStream( aOwnURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xDest, aNewName );
+ }
+ else
+ throw container::NoSuchElementException(); // TODO:
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( container::NoSuchElementException& )
+ {
+ throw;
+ }
+ catch( container::ElementExistException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+}
+
+void SAL_CALL FSStorage::moveElementTo( const OUString& aElementName,
+ const uno::Reference< embed::XStorage >& xDest,
+ const OUString& aNewName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ copyElementTo( aElementName, xDest, aNewName );
+
+ INetURLObject aOwnURL( m_aURL );
+ aOwnURL.Append( aElementName );
+ if ( !::utl::UCBContentHelper::Kill( aOwnURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ throw io::IOException(); // TODO: error handling
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL FSStorage::getByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( aName.isEmpty() )
+ throw lang::IllegalArgumentException();
+
+ uno::Any aResult;
+ try
+ {
+ INetURLObject aURL( m_aURL );
+ aURL.Append( aName );
+
+
+ if ( ::utl::UCBContentHelper::IsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ {
+ aResult <<= openStorageElement( aName, embed::ElementModes::READ );
+ }
+ else if ( ::utl::UCBContentHelper::IsDocument( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) )
+ {
+ aResult <<= openStreamElement( aName, embed::ElementModes::READ );
+ }
+ else
+ throw container::NoSuchElementException(); // TODO:
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw lang::WrappedTargetException( "Can not open element!",
+ static_cast< OWeakObject* >( this ),
+ aCaught );
+ }
+
+ return aResult;
+}
+
+
+uno::Sequence< OUString > SAL_CALL FSStorage::getElementNames()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ uno::Sequence< OUString > aResult;
+
+ try
+ {
+ uno::Sequence<OUString> aProps { "Title" };
+
+ sal_Int32 nSize = 0;
+ uno::Reference<sdbc::XResultSet> xResultSet
+ = GetContent().createCursor(aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS);
+ uno::Reference< sdbc::XRow > xRow( xResultSet, uno::UNO_QUERY );
+ if ( xResultSet.is() )
+ {
+ // go through the list
+ while ( xResultSet->next() )
+ {
+ OUString aName( xRow->getString( 1 ) );
+ aResult.realloc( ++nSize );
+ aResult.getArray()[nSize-1] = aName;
+ }
+ }
+ }
+ catch( const ucb::InteractiveIOException& r )
+ {
+ if ( r.Code == ucb::IOErrorCode_NOT_EXISTING )
+ OSL_FAIL( "The folder does not exist!" );
+ else
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw lang::WrappedTargetRuntimeException( "Can not open storage!",
+ static_cast< OWeakObject* >( this ),
+ aCaught );
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw lang::WrappedTargetRuntimeException( "Can not open storage!",
+ static_cast< OWeakObject* >( this ),
+ aCaught );
+ }
+
+ return aResult;
+}
+
+sal_Bool SAL_CALL FSStorage::hasByName( const OUString& aName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( aName.isEmpty() )
+ throw lang::IllegalArgumentException();
+
+ INetURLObject aURL( m_aURL );
+ aURL.Append( aName );
+
+ return ( ::utl::UCBContentHelper::IsFolder( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) )
+ || ::utl::UCBContentHelper::IsDocument( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
+}
+
+uno::Type SAL_CALL FSStorage::getElementType()
+{
+ // it is a multitype container
+ return uno::Type();
+}
+
+sal_Bool SAL_CALL FSStorage::hasElements()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ try
+ {
+ uno::Sequence<OUString> aProps { "TargetURL" };
+
+ uno::Reference<sdbc::XResultSet> xResultSet
+ = GetContent().createCursor(aProps, ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS);
+ return ( xResultSet.is() && xResultSet->next() );
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception& ex)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx );
+ }
+}
+
+// XDisposable
+void SAL_CALL FSStorage::dispose()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pListenersContainer )
+ {
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
+ m_pListenersContainer->disposeAndClear( aSource );
+ }
+}
+
+void SAL_CALL FSStorage::addEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pListenersContainer )
+ m_pListenersContainer.reset(new ::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener>( m_aMutex ));
+
+ m_pListenersContainer->addInterface( xListener );
+}
+
+void SAL_CALL FSStorage::removeEventListener(
+ const uno::Reference< lang::XEventListener >& xListener )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pListenersContainer )
+ m_pListenersContainer->removeInterface( xListener );
+}
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL FSStorage::getPropertySetInfo()
+{
+ //TODO:
+ return uno::Reference< beans::XPropertySetInfo >();
+}
+
+
+void SAL_CALL FSStorage::setPropertyValue( const OUString& aPropertyName, const uno::Any& )
+{
+ if ( aPropertyName == "URL" || aPropertyName == "OpenMode" )
+ throw beans::PropertyVetoException(); // TODO
+ else
+ throw beans::UnknownPropertyException(aPropertyName); // TODO
+}
+
+
+uno::Any SAL_CALL FSStorage::getPropertyValue( const OUString& aPropertyName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( aPropertyName == "URL" )
+ return uno::Any( m_aURL );
+ else if ( aPropertyName == "OpenMode" )
+ return uno::Any( m_nMode );
+
+ throw beans::UnknownPropertyException(aPropertyName); // TODO
+}
+
+
+void SAL_CALL FSStorage::addPropertyChangeListener(
+ const OUString& /*aPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ )
+{
+ //TODO:
+}
+
+
+void SAL_CALL FSStorage::removePropertyChangeListener(
+ const OUString& /*aPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ )
+{
+ //TODO:
+}
+
+
+void SAL_CALL FSStorage::addVetoableChangeListener(
+ const OUString& /*PropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
+{
+ //TODO:
+}
+
+
+void SAL_CALL FSStorage::removeVetoableChangeListener(
+ const OUString& /*PropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ )
+{
+ //TODO:
+}
+
+// XHierarchicalStorageAccess
+uno::Reference< embed::XExtendedStorageStream > SAL_CALL FSStorage::openStreamElementByHierarchicalName( const OUString& sStreamPath, ::sal_Int32 nOpenMode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( sStreamPath.toChar() == '/' )
+ throw lang::IllegalArgumentException();
+
+ INetURLObject aBaseURL( m_aURL );
+ if ( !aBaseURL.setFinalSlash() )
+ throw uno::RuntimeException();
+
+ OUString aFileURL = INetURLObject::GetAbsURL(
+ aBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ sStreamPath );
+
+ if ( ::utl::UCBContentHelper::IsFolder( aFileURL ) )
+ throw io::IOException();
+
+ if ( ( nOpenMode & embed::ElementModes::NOCREATE )
+ && !::utl::UCBContentHelper::IsDocument( aFileURL ) )
+ throw io::IOException(); // TODO:
+
+ uno::Reference< ucb::XCommandEnvironment > xDummyEnv; // TODO: provide InteractionHandler if any
+ uno::Reference< io::XStream > xResult;
+ try
+ {
+ if ( nOpenMode & embed::ElementModes::WRITE )
+ {
+ if ( comphelper::isFileUrl( aFileURL ) )
+ {
+ uno::Reference<ucb::XSimpleFileAccess3> xSimpleFileAccess(
+ ucb::SimpleFileAccess::create( m_xContext ) );
+ uno::Reference< io::XStream > xStream =
+ xSimpleFileAccess->openFileReadWrite( aFileURL );
+
+ xResult = new OFSStreamContainer(xStream);
+ }
+ else
+ {
+ // TODO: test whether it really works for http and fwp
+ std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream( aFileURL,
+ StreamMode::STD_WRITE );
+ if ( pStream && !pStream->GetError() )
+ {
+ uno::Reference< io::XStream > xStream( new ::utl::OStreamWrapper( std::move(pStream) ) );
+ xResult = new OFSStreamContainer(xStream);
+ }
+ }
+
+ if ( !xResult.is() )
+ throw io::IOException();
+
+ if ( nOpenMode & embed::ElementModes::TRUNCATE )
+ {
+ uno::Reference< io::XTruncate > xTrunc( xResult->getOutputStream(), uno::UNO_QUERY_THROW );
+ xTrunc->truncate();
+ }
+ }
+ else
+ {
+ if ( ( nOpenMode & embed::ElementModes::TRUNCATE )
+ || !::utl::UCBContentHelper::IsDocument( aFileURL ) )
+ throw io::IOException(); // TODO: access denied
+
+ ::ucbhelper::Content aResultContent( aFileURL, xDummyEnv, comphelper::getProcessComponentContext() );
+ uno::Reference< io::XInputStream > xInStream = aResultContent.openStream();
+ xResult = new OFSInputStreamContainer(xInStream);
+ }
+ }
+ catch( embed::InvalidStorageException& )
+ {
+ throw;
+ }
+ catch( lang::IllegalArgumentException& )
+ {
+ throw;
+ }
+ catch( packages::WrongPasswordException& )
+ {
+ throw;
+ }
+ catch( embed::StorageWrappedTargetException& )
+ {
+ throw;
+ }
+ catch( io::IOException& )
+ {
+ throw;
+ }
+ catch( uno::RuntimeException& )
+ {
+ throw;
+ }
+ catch( uno::Exception& )
+ {
+ uno::Any aCaught( ::cppu::getCaughtException() );
+ throw embed::StorageWrappedTargetException("Can't copy raw stream",
+ uno::Reference< io::XInputStream >(),
+ aCaught );
+ }
+
+ return uno::Reference< embed::XExtendedStorageStream >( xResult, uno::UNO_QUERY_THROW );
+}
+
+uno::Reference< embed::XExtendedStorageStream > SAL_CALL FSStorage::openEncryptedStreamElementByHierarchicalName( const OUString& /*sStreamName*/, ::sal_Int32 /*nOpenMode*/, const OUString& /*sPassword*/ )
+{
+ throw packages::NoEncryptionException();
+}
+
+void SAL_CALL FSStorage::removeStreamElementByHierarchicalName( const OUString& sStreamPath )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // TODO/LATER: may need possibility to create folder if it was removed, since the folder can not be locked
+ INetURLObject aBaseURL( m_aURL );
+ if ( !aBaseURL.setFinalSlash() )
+ throw uno::RuntimeException();
+
+ OUString aFileURL = INetURLObject::GetAbsURL(
+ aBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ),
+ sStreamPath );
+
+ if ( !::utl::UCBContentHelper::IsDocument( aFileURL ) )
+ {
+ if ( ::utl::UCBContentHelper::IsFolder( aFileURL ) )
+ throw lang::IllegalArgumentException();
+ else
+ throw container::NoSuchElementException(); // TODO:
+ }
+
+ if ( !::utl::UCBContentHelper::Kill( aFileURL ) )
+ throw io::IOException(); // TODO: error handling
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/fsstorage.hxx b/svl/source/fsstor/fsstorage.hxx
new file mode 100644
index 000000000..1c4ae7030
--- /dev/null
+++ b/svl/source/fsstor/fsstorage.hxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVL_SOURCE_FSSTOR_FSSTORAGE_HXX
+#define INCLUDED_SVL_SOURCE_FSSTOR_FSSTORAGE_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/weak.hxx>
+
+#include <ucbhelper/content.hxx>
+
+class FSStorage : public css::lang::XTypeProvider
+ , public css::embed::XStorage
+ , public css::embed::XHierarchicalStorageAccess
+ , public css::beans::XPropertySet
+ , public ::cppu::OWeakObject
+{
+ ::osl::Mutex m_aMutex;
+ OUString m_aURL;
+ ::ucbhelper::Content m_aContent;
+ sal_Int32 m_nMode;
+ std::unique_ptr<::comphelper::OInterfaceContainerHelper3<css::lang::XEventListener>> m_pListenersContainer; // list of listeners
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+public:
+
+ FSStorage( const ::ucbhelper::Content& aContent,
+ sal_Int32 nMode,
+ css::uno::Reference< css::uno::XComponentContext > const & xContext );
+
+ virtual ~FSStorage() override;
+
+ ucbhelper::Content& GetContent();
+
+ static void CopyStreamToSubStream( const OUString& aSourceURL,
+ const css::uno::Reference< css::embed::XStorage >& xDest,
+ const OUString& aNewEntryName );
+
+ void CopyContentToStorage_Impl(ucbhelper::Content& rContent,
+ const css::uno::Reference<css::embed::XStorage>& xDest);
+
+ static bool MakeFolderNoUI( std::u16string_view rFolder );
+
+ // XInterface
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XStorage
+
+ virtual void SAL_CALL copyToStorage( const css::uno::Reference< css::embed::XStorage >& xDest ) override;
+
+ virtual css::uno::Reference< css::io::XStream > SAL_CALL openStreamElement(
+ const OUString& aStreamName, sal_Int32 nOpenMode ) override;
+
+ virtual css::uno::Reference< css::io::XStream > SAL_CALL openEncryptedStreamElement(
+ const OUString& aStreamName, sal_Int32 nOpenMode, const OUString& aPass ) override;
+
+ virtual css::uno::Reference< css::embed::XStorage > SAL_CALL openStorageElement(
+ const OUString& aStorName, sal_Int32 nStorageMode ) override;
+
+ virtual css::uno::Reference< css::io::XStream > SAL_CALL cloneStreamElement(
+ const OUString& aStreamName ) override;
+
+ virtual css::uno::Reference< css::io::XStream > SAL_CALL cloneEncryptedStreamElement(
+ const OUString& aStreamName, const OUString& aPass ) override;
+
+ virtual void SAL_CALL copyLastCommitTo(
+ const css::uno::Reference< css::embed::XStorage >& xTargetStorage ) override;
+
+ virtual void SAL_CALL copyStorageElementLastCommitTo(
+ const OUString& aStorName,
+ const css::uno::Reference< css::embed::XStorage >& xTargetStorage ) override;
+
+ virtual sal_Bool SAL_CALL isStreamElement( const OUString& aElementName ) override;
+
+ virtual sal_Bool SAL_CALL isStorageElement( const OUString& aElementName ) override;
+
+ virtual void SAL_CALL removeElement( const OUString& aElementName ) override;
+
+ virtual void SAL_CALL renameElement( const OUString& rEleName, const OUString& rNewName ) override;
+
+ virtual void SAL_CALL copyElementTo( const OUString& aElementName,
+ const css::uno::Reference< css::embed::XStorage >& xDest,
+ const OUString& aNewName ) override;
+
+ virtual void SAL_CALL moveElementTo( const OUString& aElementName,
+ const css::uno::Reference< css::embed::XStorage >& xDest,
+ const OUString& rNewName ) override;
+
+ // XNameAccess
+
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ virtual css::uno::Type SAL_CALL getElementType() override;
+
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XComponent
+
+ virtual void SAL_CALL dispose() override;
+
+ virtual void SAL_CALL addEventListener(
+ const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+
+ virtual void SAL_CALL removeEventListener(
+ const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+
+ // XPropertySet
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+
+ virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+
+ virtual void SAL_CALL addPropertyChangeListener(
+ const OUString& aPropertyName,
+ const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override;
+
+ virtual void SAL_CALL removePropertyChangeListener(
+ const OUString& aPropertyName,
+ const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override;
+
+ virtual void SAL_CALL addVetoableChangeListener(
+ const OUString& PropertyName,
+ const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override;
+
+ // XHierarchicalStorageAccess
+
+ virtual css::uno::Reference< css::embed::XExtendedStorageStream > SAL_CALL openStreamElementByHierarchicalName( const OUString& sStreamPath, ::sal_Int32 nOpenMode ) override;
+
+ virtual css::uno::Reference< css::embed::XExtendedStorageStream > SAL_CALL openEncryptedStreamElementByHierarchicalName( const OUString& sStreamName, ::sal_Int32 nOpenMode, const OUString& sPassword ) override;
+
+ virtual void SAL_CALL removeStreamElementByHierarchicalName( const OUString& sElementPath ) override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/oinputstreamcontainer.cxx b/svl/source/fsstor/oinputstreamcontainer.cxx
new file mode 100644
index 000000000..f6481b76f
--- /dev/null
+++ b/svl/source/fsstor/oinputstreamcontainer.cxx
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include "oinputstreamcontainer.hxx"
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+using namespace ::com::sun::star;
+
+OFSInputStreamContainer::OFSInputStreamContainer( const uno::Reference< io::XInputStream >& xStream )
+: m_xInputStream( xStream )
+, m_xSeekable( xStream, uno::UNO_QUERY )
+, m_bSeekable( false )
+, m_bDisposed( false )
+{
+ m_bSeekable = m_xSeekable.is();
+}
+
+OFSInputStreamContainer::~OFSInputStreamContainer()
+{
+}
+
+uno::Sequence< uno::Type > SAL_CALL OFSInputStreamContainer::getTypes()
+{
+ if (m_bSeekable)
+ {
+ static cppu::OTypeCollection aTypeCollection(cppu::UnoType<io::XStream>::get(),
+ cppu::UnoType<io::XInputStream>::get(),
+ cppu::UnoType<io::XSeekable>::get());
+
+ return aTypeCollection.getTypes();
+ }
+ else
+ {
+ static cppu::OTypeCollection aTypeCollection(cppu::UnoType<io::XStream>::get(),
+ cppu::UnoType<io::XInputStream>::get());
+
+ return aTypeCollection.getTypes();
+ }
+}
+
+uno::Any SAL_CALL OFSInputStreamContainer::queryInterface( const uno::Type& rType )
+{
+ // Attention:
+ // Don't use mutex or guard in this method!!! Is a method of XInterface.
+
+ uno::Any aReturn;
+ if ( m_bSeekable )
+ aReturn = ::cppu::queryInterface( rType,
+ static_cast< io::XStream* >( this ),
+ static_cast< io::XInputStream* >( this ),
+ static_cast< io::XSeekable* >( this ) );
+ else
+ aReturn = ::cppu::queryInterface( rType,
+ static_cast< io::XStream* >( this ),
+ static_cast< io::XInputStream* >( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+
+ return ::cppu::OWeakObject::queryInterface( rType ) ;
+}
+
+void SAL_CALL OFSInputStreamContainer::acquire()
+ noexcept
+{
+ ::cppu::OWeakObject::acquire();
+}
+
+void SAL_CALL OFSInputStreamContainer::release()
+ noexcept
+{
+ ::cppu::OWeakObject::release();
+}
+
+sal_Int32 SAL_CALL OFSInputStreamContainer::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->readBytes( aData, nBytesToRead );
+}
+
+sal_Int32 SAL_CALL OFSInputStreamContainer::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->readSomeBytes( aData, nMaxBytesToRead );
+}
+
+void SAL_CALL OFSInputStreamContainer::skipBytes( sal_Int32 nBytesToSkip )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ m_xInputStream->skipBytes( nBytesToSkip );
+}
+
+sal_Int32 SAL_CALL OFSInputStreamContainer::available( )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->available();
+}
+
+void SAL_CALL OFSInputStreamContainer::closeInput( )
+{
+ {
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+ }
+ dispose();
+}
+
+uno::Reference< io::XInputStream > SAL_CALL OFSInputStreamContainer::getInputStream()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ return uno::Reference< io::XInputStream >();
+
+ return this;
+}
+
+uno::Reference< io::XOutputStream > SAL_CALL OFSInputStreamContainer::getOutputStream()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ return uno::Reference< io::XOutputStream >();
+}
+
+void SAL_CALL OFSInputStreamContainer::seek( sal_Int64 location )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ m_xSeekable->seek( location );
+}
+
+sal_Int64 SAL_CALL OFSInputStreamContainer::getPosition()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ return m_xSeekable->getPosition();
+}
+
+sal_Int64 SAL_CALL OFSInputStreamContainer::getLength()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ return m_xSeekable->getLength();
+}
+
+void SAL_CALL OFSInputStreamContainer::dispose( )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ m_xInputStream->closeInput();
+
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) );
+ m_aListenersContainer.disposeAndClear( aGuard, aSource );
+
+ m_bDisposed = true;
+}
+
+void SAL_CALL OFSInputStreamContainer::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ m_aListenersContainer.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL OFSInputStreamContainer::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ m_aListenersContainer.removeInterface( aGuard, xListener );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/oinputstreamcontainer.hxx b/svl/source/fsstor/oinputstreamcontainer.hxx
new file mode 100644
index 000000000..7228bcde5
--- /dev/null
+++ b/svl/source/fsstor/oinputstreamcontainer.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVL_SOURCE_FSSTOR_OINPUTSTREAMCONTAINER_HXX
+#define INCLUDED_SVL_SOURCE_FSSTOR_OINPUTSTREAMCONTAINER_HXX
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/embed/XExtendedStorageStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+
+#include <mutex>
+
+class OFSInputStreamContainer : public cppu::WeakImplHelper < css::io::XInputStream
+ ,css::embed::XExtendedStorageStream >
+ , public css::io::XSeekable
+{
+ std::mutex m_aMutex;
+
+ css::uno::Reference < css::io::XInputStream > m_xInputStream;
+ css::uno::Reference < css::io::XSeekable > m_xSeekable;
+
+ bool m_bSeekable;
+
+ bool m_bDisposed;
+
+ ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aListenersContainer; // list of listeners
+
+public:
+ explicit OFSInputStreamContainer( const css::uno::Reference < css::io::XInputStream >& xStream );
+
+ virtual ~OFSInputStreamContainer() override;
+
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+
+ //XStream
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getInputStream( ) override;
+ virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL getOutputStream( ) override;
+
+ //XSeekable
+ virtual void SAL_CALL seek( sal_Int64 location ) override;
+ virtual sal_Int64 SAL_CALL getPosition() override;
+ virtual sal_Int64 SAL_CALL getLength() override;
+
+ //XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/ostreamcontainer.cxx b/svl/source/fsstor/ostreamcontainer.cxx
new file mode 100644
index 000000000..e02ce1383
--- /dev/null
+++ b/svl/source/fsstor/ostreamcontainer.cxx
@@ -0,0 +1,451 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ostreamcontainer.hxx"
+
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+
+
+using namespace ::com::sun::star;
+
+OFSStreamContainer::OFSStreamContainer( const uno::Reference < io::XStream >& xStream )
+: m_bDisposed( false )
+, m_bInputClosed( false )
+, m_bOutputClosed( false )
+{
+ try
+ {
+ m_xStream = xStream;
+ if ( !m_xStream.is() )
+ throw uno::RuntimeException();
+
+ m_xSeekable.set( xStream, uno::UNO_QUERY );
+ m_xInputStream = xStream->getInputStream();
+ m_xOutputStream = xStream->getOutputStream();
+ m_xTruncate.set( m_xOutputStream, uno::UNO_QUERY );
+ m_xAsyncOutputMonitor.set( m_xOutputStream, uno::UNO_QUERY );
+ }
+ catch( uno::Exception& )
+ {
+ m_xStream.clear();
+ m_xSeekable.clear();
+ m_xInputStream.clear();
+ m_xOutputStream.clear();
+ m_xTruncate.clear();
+ m_xAsyncOutputMonitor.clear();
+ }
+}
+
+OFSStreamContainer::~OFSStreamContainer()
+{
+}
+
+// XInterface
+uno::Any SAL_CALL OFSStreamContainer::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<lang::XTypeProvider*> ( this )
+ , static_cast<io::XStream*> ( this )
+ , static_cast<embed::XExtendedStorageStream*> ( this )
+ , static_cast<lang::XComponent*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+
+ if ( m_xSeekable.is() )
+ {
+ aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<io::XSeekable*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+ }
+
+ if ( m_xInputStream.is() )
+ {
+ aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<io::XInputStream*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+ }
+ if ( m_xOutputStream.is() )
+ {
+ aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<io::XOutputStream*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+ }
+ if ( m_xTruncate.is() )
+ {
+ aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<io::XTruncate*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+ }
+ if ( m_xAsyncOutputMonitor.is() )
+ {
+ aReturn = ::cppu::queryInterface
+ ( rType
+ , static_cast<io::XAsyncOutputMonitor*> ( this ) );
+
+ if ( aReturn.hasValue() )
+ return aReturn ;
+ }
+
+ return OWeakObject::queryInterface( rType );
+}
+
+void SAL_CALL OFSStreamContainer::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL OFSStreamContainer::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+// XTypeProvider
+uno::Sequence< uno::Type > SAL_CALL OFSStreamContainer::getTypes()
+{
+ if ( !m_aTypes.hasElements() )
+ {
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( !m_aTypes.hasElements() )
+ {
+ std::vector<uno::Type> tmp
+ {
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<embed::XExtendedStorageStream>::get()
+ };
+
+ if ( m_xSeekable.is() )
+ tmp.push_back(cppu::UnoType<io::XSeekable>::get());
+ if ( m_xInputStream.is() )
+ tmp.push_back(cppu::UnoType<io::XInputStream>::get());
+ if ( m_xOutputStream.is() )
+ tmp.push_back(cppu::UnoType<io::XOutputStream>::get());
+ if ( m_xTruncate.is() )
+ tmp.push_back(cppu::UnoType<io::XTruncate>::get());
+ if ( m_xAsyncOutputMonitor.is() )
+ tmp.push_back(cppu::UnoType<io::XAsyncOutputMonitor>::get());
+
+ m_aTypes = comphelper::containerToSequence(tmp);
+ }
+ }
+ return m_aTypes;
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL OFSStreamContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XStream
+uno::Reference< io::XInputStream > SAL_CALL OFSStreamContainer::getInputStream()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() )
+ throw uno::RuntimeException();
+
+ if ( m_xInputStream.is() )
+ return uno::Reference< io::XInputStream >( static_cast< io::XInputStream* >( this ) );
+
+ return uno::Reference< io::XInputStream >();
+}
+
+uno::Reference< io::XOutputStream > SAL_CALL OFSStreamContainer::getOutputStream()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() )
+ throw uno::RuntimeException();
+
+ if ( m_xOutputStream.is() )
+ return uno::Reference< io::XOutputStream >( static_cast< io::XOutputStream* >( this ) );
+
+ return uno::Reference< io::XOutputStream >();
+}
+
+// XComponent
+void SAL_CALL OFSStreamContainer::dispose()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() )
+ throw uno::RuntimeException();
+
+ if ( m_xInputStream.is() && !m_bInputClosed )
+ {
+ m_xInputStream->closeInput();
+ m_bInputClosed = true;
+ }
+
+ if ( m_xOutputStream.is() && !m_bOutputClosed )
+ {
+ m_xOutputStream->closeOutput();
+ m_bOutputClosed = true;
+ }
+
+ lang::EventObject aSource( static_cast< ::cppu::OWeakObject*>( this ) );
+ m_aListenersContainer.disposeAndClear( aGuard, aSource );
+ m_bDisposed = true;
+}
+
+void SAL_CALL OFSStreamContainer::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ m_aListenersContainer.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL OFSStreamContainer::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ m_aListenersContainer.removeInterface( aGuard, xListener );
+}
+
+
+// XSeekable
+void SAL_CALL OFSStreamContainer::seek( sal_Int64 location )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ m_xSeekable->seek( location );
+}
+
+sal_Int64 SAL_CALL OFSStreamContainer::getPosition()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ return m_xSeekable->getPosition();
+}
+
+sal_Int64 SAL_CALL OFSStreamContainer::getLength()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xSeekable.is() )
+ throw uno::RuntimeException();
+
+ return m_xSeekable->getLength();
+}
+
+
+// XInputStream
+sal_Int32 SAL_CALL OFSStreamContainer::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->readBytes( aData, nBytesToRead );
+}
+
+sal_Int32 SAL_CALL OFSStreamContainer::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->readSomeBytes( aData, nMaxBytesToRead );
+}
+
+void SAL_CALL OFSStreamContainer::skipBytes( sal_Int32 nBytesToSkip )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ m_xInputStream->skipBytes( nBytesToSkip );
+}
+
+sal_Int32 SAL_CALL OFSStreamContainer::available()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xInputStream->available();
+}
+
+void SAL_CALL OFSStreamContainer::closeInput()
+{
+ {
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xInputStream.is() )
+ throw uno::RuntimeException();
+
+ if ( m_xInputStream.is() )
+ {
+ m_xInputStream->closeInput();
+ m_bInputClosed = true;
+ }
+ if ( !m_bOutputClosed )
+ return;
+ }
+
+ dispose();
+}
+
+// XOutputStream
+void SAL_CALL OFSStreamContainer::writeBytes( const uno::Sequence< sal_Int8 >& aData )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xOutputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xOutputStream->writeBytes( aData );
+}
+
+void SAL_CALL OFSStreamContainer::flush()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xOutputStream.is() )
+ throw uno::RuntimeException();
+
+ return m_xOutputStream->flush();
+}
+
+void SAL_CALL OFSStreamContainer::closeOutput()
+{
+ {
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xOutputStream.is() )
+ throw uno::RuntimeException();
+
+ if ( m_xOutputStream.is() )
+ {
+ m_xOutputStream->closeOutput();
+ m_bOutputClosed = true;
+ }
+ if ( !m_bInputClosed )
+ return;
+ }
+ dispose();
+}
+
+
+// XTruncate
+void SAL_CALL OFSStreamContainer::truncate()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xTruncate.is() )
+ throw uno::RuntimeException();
+
+ m_xTruncate->truncate();
+}
+
+
+// XAsyncOutputMonitor
+void SAL_CALL OFSStreamContainer::waitForCompletion()
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( m_bDisposed )
+ throw lang::DisposedException();
+
+ if ( !m_xStream.is() || !m_xAsyncOutputMonitor.is() )
+ throw uno::RuntimeException();
+
+ m_xAsyncOutputMonitor->waitForCompletion();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/fsstor/ostreamcontainer.hxx b/svl/source/fsstor/ostreamcontainer.hxx
new file mode 100644
index 000000000..7dd821905
--- /dev/null
+++ b/svl/source/fsstor/ostreamcontainer.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_SVL_SOURCE_FSSTOR_OSTREAMCONTAINER_HXX
+#define INCLUDED_SVL_SOURCE_FSSTOR_OSTREAMCONTAINER_HXX
+
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/embed/XExtendedStorageStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/io/XAsyncOutputMonitor.hpp>
+#include <cppuhelper/weak.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <mutex>
+
+class OFSStreamContainer : public cppu::OWeakObject,
+ public css::lang::XTypeProvider,
+ public css::embed::XExtendedStorageStream,
+ public css::io::XSeekable,
+ public css::io::XInputStream,
+ public css::io::XOutputStream,
+ public css::io::XTruncate,
+ public css::io::XAsyncOutputMonitor
+{
+ std::mutex m_aMutex;
+
+ css::uno::Reference< css::io::XStream > m_xStream;
+ css::uno::Reference< css::io::XSeekable > m_xSeekable;
+ css::uno::Reference< css::io::XInputStream > m_xInputStream;
+ css::uno::Reference< css::io::XOutputStream > m_xOutputStream;
+ css::uno::Reference< css::io::XTruncate > m_xTruncate;
+ css::uno::Reference< css::io::XAsyncOutputMonitor > m_xAsyncOutputMonitor;
+
+ bool m_bDisposed;
+ bool m_bInputClosed;
+ bool m_bOutputClosed;
+
+ ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aListenersContainer; // list of listeners
+ css::uno::Sequence<css::uno::Type> m_aTypes;
+
+public:
+ explicit OFSStreamContainer( const css::uno::Reference < css::io::XStream >& xStream );
+ virtual ~OFSStreamContainer() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XStream
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getInputStream( ) override;
+ virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL getOutputStream( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XSeekable
+ virtual void SAL_CALL seek( sal_Int64 location ) override;
+ virtual sal_Int64 SAL_CALL getPosition() override;
+ virtual sal_Int64 SAL_CALL getLength() override;
+
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+
+ // XOutputStream
+ virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override;
+ virtual void SAL_CALL flush( ) override;
+ virtual void SAL_CALL closeOutput( ) override;
+
+ // XTruncate
+ virtual void SAL_CALL truncate() override;
+
+ // XAsyncOutputMonitor
+ virtual void SAL_CALL waitForCompletion( ) override;
+
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */