summaryrefslogtreecommitdiffstats
path: root/ucb/source/core
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /ucb/source/core
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/core')
-rw-r--r--ucb/source/core/FileAccess.cxx694
-rw-r--r--ucb/source/core/cmdenv.cxx117
-rw-r--r--ucb/source/core/cmdenv.hxx65
-rw-r--r--ucb/source/core/identify.cxx63
-rw-r--r--ucb/source/core/identify.hxx40
-rw-r--r--ucb/source/core/providermap.hxx63
-rw-r--r--ucb/source/core/provprox.cxx353
-rw-r--r--ucb/source/core/provprox.hxx126
-rw-r--r--ucb/source/core/ucb.cxx887
-rw-r--r--ucb/source/core/ucb.hxx158
-rw-r--r--ucb/source/core/ucb1.component46
-rw-r--r--ucb/source/core/ucbcmds.cxx1923
-rw-r--r--ucb/source/core/ucbcmds.hxx36
-rw-r--r--ucb/source/core/ucbprops.cxx268
-rw-r--r--ucb/source/core/ucbprops.hxx56
-rw-r--r--ucb/source/core/ucbstore.cxx2205
-rw-r--r--ucb/source/core/ucbstore.hxx248
17 files changed, 7348 insertions, 0 deletions
diff --git a/ucb/source/core/FileAccess.cxx b/ucb/source/core/FileAccess.cxx
new file mode 100644
index 000000000..24674ac07
--- /dev/null
+++ b/ucb/source/core/FileAccess.cxx
@@ -0,0 +1,694 @@
+/* -*- 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 <cppuhelper/exc_hlp.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/streamwrap.hxx>
+#include <tools/stream.hxx>
+
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/CommandFailedException.hpp>
+#include <com/sun/star/ucb/ContentInfo.hpp>
+#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+
+#include <vector>
+
+constexpr OUStringLiteral SERVICE_NAME = u"com.sun.star.ucb.SimpleFileAccess";
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::registry;
+using namespace ::com::sun::star::container;
+
+using ::std::vector;
+
+namespace
+{
+
+// Implementation XSimpleFileAccess
+typedef cppu::WeakImplHelper<XSimpleFileAccess3, css::lang::XServiceInfo>
+ FileAccessHelper;
+class OCommandEnvironment;
+
+class OFileAccess : public FileAccessHelper
+{
+ Reference< XComponentContext > m_xContext;
+ rtl::Reference<OCommandEnvironment> mxEnvironment;
+
+ /// @throws CommandAbortedException
+ /// @throws Exception
+ /// @throws RuntimeException
+ void transferImpl( const OUString& rSource, std::u16string_view rDest, bool bMoveData );
+ /// @throws Exception
+ bool createNewFile( const OUString & rParentURL,
+ const OUString & rTitle,
+ const Reference< XInputStream >& data );
+
+public:
+ explicit OFileAccess( const Reference< XComponentContext > & xContext )
+ : m_xContext( xContext) {}
+ // Methods
+ virtual void SAL_CALL copy( const OUString& SourceURL, const OUString& DestURL ) override;
+ virtual void SAL_CALL move( const OUString& SourceURL, const OUString& DestURL ) override;
+ virtual void SAL_CALL kill( const OUString& FileURL ) override;
+ virtual sal_Bool SAL_CALL isFolder( const OUString& FileURL ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( const OUString& FileURL ) override;
+ virtual void SAL_CALL setReadOnly( const OUString& FileURL, sal_Bool bReadOnly ) override;
+ virtual void SAL_CALL createFolder( const OUString& NewFolderURL ) override;
+ virtual sal_Int32 SAL_CALL getSize( const OUString& FileURL ) override;
+ virtual OUString SAL_CALL getContentType( const OUString& FileURL ) override;
+ virtual css::util::DateTime SAL_CALL getDateTimeModified( const OUString& FileURL ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getFolderContents( const OUString& FolderURL, sal_Bool bIncludeFolders ) override;
+ virtual sal_Bool SAL_CALL exists( const OUString& FileURL ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL openFileRead( const OUString& FileURL ) override;
+ virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL openFileWrite( const OUString& FileURL ) override;
+ virtual css::uno::Reference< css::io::XStream > SAL_CALL openFileReadWrite( const OUString& FileURL ) override;
+ virtual void SAL_CALL setInteractionHandler( const css::uno::Reference< css::task::XInteractionHandler >& Handler ) override;
+ virtual void SAL_CALL writeFile( const OUString& FileURL, const css::uno::Reference< css::io::XInputStream >& data ) override;
+ virtual sal_Bool SAL_CALL isHidden( const OUString& FileURL ) override;
+ virtual void SAL_CALL setHidden( const OUString& FileURL, sal_Bool bHidden ) override;
+
+ OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.ucb.SimpleFileAccess"; }
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+ { return { SERVICE_NAME }; }
+};
+
+// Implementation XActiveDataSink
+
+class OActiveDataSink : public cppu::WeakImplHelper< XActiveDataSink >
+{
+ Reference< XInputStream > mxStream;
+
+public:
+
+ // Methods
+ virtual void SAL_CALL setInputStream( const Reference< XInputStream >& aStream ) override;
+ virtual Reference< XInputStream > SAL_CALL getInputStream( ) override;
+};
+
+// Implementation XActiveDataStreamer
+
+class OActiveDataStreamer : public cppu::WeakImplHelper< XActiveDataStreamer >
+{
+ Reference< XStream > mxStream;
+
+public:
+
+ // Methods
+ virtual void SAL_CALL setStream( const Reference< XStream >& aStream ) override;
+ virtual Reference< XStream > SAL_CALL getStream() override;
+};
+
+// Implementation XCommandEnvironment
+
+class OCommandEnvironment : public cppu::WeakImplHelper< XCommandEnvironment >
+{
+ Reference< XInteractionHandler > mxInteraction;
+
+public:
+ void setHandler( const Reference< XInteractionHandler >& xInteraction_ )
+ {
+ mxInteraction = xInteraction_;
+ }
+
+ // Methods
+ virtual Reference< XInteractionHandler > SAL_CALL getInteractionHandler() override;
+ virtual Reference< XProgressHandler > SAL_CALL getProgressHandler() override;
+};
+
+void OActiveDataSink::setInputStream( const Reference< XInputStream >& aStream )
+{
+ mxStream = aStream;
+}
+
+Reference< XInputStream > OActiveDataSink::getInputStream()
+{
+ return mxStream;
+}
+
+void OActiveDataStreamer::setStream( const Reference< XStream >& aStream )
+{
+ mxStream = aStream;
+}
+
+Reference< XStream > OActiveDataStreamer::getStream()
+{
+ return mxStream;
+}
+
+Reference< XInteractionHandler > OCommandEnvironment::getInteractionHandler()
+{
+ return mxInteraction;
+}
+
+Reference< XProgressHandler > OCommandEnvironment::getProgressHandler()
+{
+ Reference< XProgressHandler > xRet;
+ return xRet;
+}
+
+void OFileAccess::transferImpl( const OUString& rSource,
+ std::u16string_view rDest,
+ bool bMoveData )
+{
+ // SfxContentHelper::Transfer_Impl
+ INetURLObject aSourceObj( rSource, INetProtocol::File );
+ INetURLObject aDestObj( rDest, INetProtocol::File );
+ OUString aName = aDestObj.getName(
+ INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ OUString aDestURL;
+ OUString aSourceURL = aSourceObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if ( aDestObj.removeSegment() )
+ {
+ // hierarchical URL.
+
+ aDestObj.setFinalSlash();
+ aDestURL = aDestObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ }
+ else
+ {
+ // non-hierarchical URL
+
+ // #i29648#
+
+
+ if ( aDestObj.GetProtocol() == INetProtocol::VndSunStarExpand )
+ {
+ // Hack: Expand destination URL using Macro Expander and try again
+ // with the hopefully hierarchical expanded URL...
+
+ try
+ {
+ Reference< XMacroExpander > xExpander = theMacroExpander::get(m_xContext);
+
+ aDestURL = xExpander->expandMacros(
+ aDestObj.GetURLPath( INetURLObject::DecodeMechanism::WithCharset ) );
+ }
+ catch ( Exception const & )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "OFileAccess::transferrImpl - Unable to obtain destination folder URL!",
+ static_cast< cppu::OWeakObject * >( this ), anyEx );
+ }
+
+ transferImpl( rSource, aDestURL, bMoveData );
+ return;
+ }
+
+ throw RuntimeException(
+ "OFileAccess::transferrImpl - Unable to obtain destination folder URL!",
+ static_cast< cppu::OWeakObject * >( this ) );
+
+ }
+
+ ucbhelper::Content aDestPath( aDestURL, mxEnvironment, comphelper::getProcessComponentContext() );
+ ucbhelper::Content aSrc ( aSourceURL, mxEnvironment, comphelper::getProcessComponentContext() );
+
+ try
+ {
+ aDestPath.transferContent(aSrc,
+ bMoveData
+ ? ucbhelper::InsertOperation::Move
+ : ucbhelper::InsertOperation::Copy,
+ aName,
+ css::ucb::NameClash::OVERWRITE);
+ }
+ catch ( css::ucb::CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ }
+}
+
+void OFileAccess::copy( const OUString& SourceURL, const OUString& DestURL )
+{
+ transferImpl( SourceURL, DestURL, false );
+}
+
+void OFileAccess::move( const OUString& SourceURL, const OUString& DestURL )
+{
+ transferImpl( SourceURL, DestURL, true );
+}
+
+void OFileAccess::kill( const OUString& FileURL )
+{
+ // SfxContentHelper::Kill
+ INetURLObject aDeleteObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aDeleteObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ try
+ {
+ aCnt.executeCommand( "delete", Any( true ) );
+ }
+ catch ( css::ucb::CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ }
+}
+
+sal_Bool OFileAccess::isFolder( const OUString& FileURL )
+{
+ bool bRet = false;
+ try
+ {
+ INetURLObject aURLObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ bRet = aCnt.isFolder();
+ }
+ catch (const Exception &) {}
+ return bRet;
+}
+
+sal_Bool OFileAccess::isReadOnly( const OUString& FileURL )
+{
+ INetURLObject aURLObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ Any aRetAny = aCnt.getPropertyValue("IsReadOnly");
+ bool bRet = false;
+ aRetAny >>= bRet;
+ return bRet;
+}
+
+void OFileAccess::setReadOnly( const OUString& FileURL, sal_Bool bReadOnly )
+{
+ INetURLObject aURLObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ aCnt.setPropertyValue("IsReadOnly", Any(bReadOnly) );
+}
+
+void OFileAccess::createFolder( const OUString& NewFolderURL )
+{
+ // Does the folder already exist?
+ if( NewFolderURL.isEmpty() || isFolder( NewFolderURL ) )
+ return;
+
+ // SfxContentHelper::MakeFolder
+ INetURLObject aURL( NewFolderURL, INetProtocol::File );
+ OUString aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset );
+ if ( !aTitle.isEmpty() )
+ {
+ aURL.removeSegment();
+
+ // Does the base folder exist? Otherwise create it first
+ OUString aBaseFolderURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+ if( !isFolder( aBaseFolderURLStr ) )
+ {
+ createFolder( aBaseFolderURLStr );
+ }
+ }
+
+ ucbhelper::Content aCnt( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+
+ const Sequence< ContentInfo > aInfo = aCnt.queryCreatableContentsInfo();
+
+ for ( const ContentInfo & rCurr : aInfo )
+ {
+ // Simply look for the first KIND_FOLDER...
+ if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER )
+ {
+ // Make sure the only required bootstrap property is "Title",
+ const Sequence< Property > & rProps = rCurr.Properties;
+ if ( rProps.getLength() != 1 )
+ continue;
+
+ if ( rProps[ 0 ].Name != "Title" )
+ continue;
+
+ ucbhelper::Content aNew;
+ try
+ {
+ if ( !aCnt.insertNewContent( rCurr.Type, { "Title" }, { Any(aTitle) }, aNew ) )
+ continue;
+
+ // Success. We're done.
+ return;
+ }
+ catch ( css::ucb::CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ continue;
+ }
+ }
+ }
+}
+
+sal_Int32 OFileAccess::getSize( const OUString& FileURL )
+{
+ // SfxContentHelper::GetSize
+ sal_Int32 nSize = 0;
+ sal_Int64 nTemp = 0;
+ INetURLObject aObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ aCnt.getPropertyValue( "Size" ) >>= nTemp;
+ nSize = static_cast<sal_Int32>(nTemp);
+ return nSize;
+}
+
+OUString OFileAccess::getContentType( const OUString& FileURL )
+{
+ INetURLObject aObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+
+ Reference< XContent > xContent = aCnt.get();
+ OUString aTypeStr = xContent->getContentType();
+ return aTypeStr;
+}
+
+css::util::DateTime OFileAccess::getDateTimeModified( const OUString& FileURL )
+{
+ INetURLObject aFileObj( FileURL, INetProtocol::File );
+ css::util::DateTime aDateTime;
+
+ Reference< XCommandEnvironment > aCmdEnv;
+ ucbhelper::Content aYoung( aFileObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aCmdEnv, comphelper::getProcessComponentContext() );
+ aYoung.getPropertyValue("DateModified") >>= aDateTime;
+ return aDateTime;
+}
+
+Sequence< OUString > OFileAccess::getFolderContents( const OUString& FolderURL, sal_Bool bIncludeFolders )
+{
+ // SfxContentHelper::GetFolderContents
+
+ std::vector<OUString> aFiles;
+ INetURLObject aFolderObj( FolderURL, INetProtocol::File );
+
+ ucbhelper::Content aCnt( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ Reference< XResultSet > xResultSet;
+
+ ucbhelper::ResultSetInclude eInclude = bIncludeFolders ? ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS : ucbhelper::INCLUDE_DOCUMENTS_ONLY;
+
+ try
+ {
+ xResultSet = aCnt.createCursor( {}, eInclude );
+ }
+ catch ( css::ucb::CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ }
+
+ if ( xResultSet.is() )
+ {
+ Reference< css::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
+
+ while ( xResultSet->next() )
+ {
+ OUString aId = xContentAccess->queryContentIdentifierString();
+ INetURLObject aURL( aId, INetProtocol::File );
+ aFiles.push_back( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
+ }
+ }
+
+ return comphelper::containerToSequence(aFiles);
+}
+
+sal_Bool OFileAccess::exists( const OUString& FileURL )
+{
+ bool bRet = false;
+ try
+ {
+ bRet = isFolder( FileURL );
+ if( !bRet )
+ {
+ Reference< XInputStream > xStream = openFileRead( FileURL );
+ bRet = xStream.is();
+ if( bRet )
+ xStream->closeInput();
+ }
+ }
+ catch (const Exception &) {}
+ return bRet;
+}
+
+Reference< XInputStream > OFileAccess::openFileRead( const OUString& FileURL )
+{
+ Reference< XInputStream > xRet;
+ INetURLObject aObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+
+ Reference<XActiveDataSink> xSink = new OActiveDataSink;
+
+ try
+ {
+ bool bRet = aCnt.openStream( xSink );
+ if( bRet )
+ xRet = xSink->getInputStream();
+ }
+ catch ( css::ucb::CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ }
+
+ return xRet;
+}
+
+Reference< XOutputStream > OFileAccess::openFileWrite( const OUString& FileURL )
+{
+ Reference< XOutputStream > xRet;
+ Reference< XStream > xStream = OFileAccess::openFileReadWrite( FileURL );
+ if( xStream.is() )
+ xRet = xStream->getOutputStream();
+ return xRet;
+}
+
+Reference< XStream > OFileAccess::openFileReadWrite( const OUString& FileURL )
+{
+ Reference<XActiveDataStreamer> xSink = new OActiveDataStreamer;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xSink;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Any aCmdArg;
+ aCmdArg <<= aArg;
+
+ INetURLObject aFileObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aFileObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+
+ // Be silent...
+ Reference< XInteractionHandler > xIH;
+ if ( mxEnvironment.is() )
+ {
+ xIH = mxEnvironment->getInteractionHandler();
+ mxEnvironment->setHandler( nullptr );
+ }
+
+ try
+ {
+ aCnt.executeCommand( "open", aCmdArg );
+ }
+ catch ( InteractiveIOException const & e )
+ {
+ if ( xIH.is() && mxEnvironment.is() )
+ mxEnvironment->setHandler( xIH );
+
+ if ( e.Code == IOErrorCode_NOT_EXISTING )
+ {
+ // Create file...
+ SvMemoryStream aStream(0,0);
+ rtl::Reference<::utl::OInputStreamWrapper> pInput = new ::utl::OInputStreamWrapper( aStream );
+ InsertCommandArgument aInsertArg;
+ aInsertArg.Data = pInput;
+ aInsertArg.ReplaceExisting = false;
+
+ aCmdArg <<= aInsertArg;
+ aCnt.executeCommand( "insert", aCmdArg );
+
+ // Retry...
+ return openFileReadWrite( FileURL );
+ }
+
+ throw;
+ }
+
+ if ( xIH.is() && mxEnvironment.is() )
+ mxEnvironment->setHandler( xIH );
+
+ Reference< XStream > xRet = xSink->getStream();
+ return xRet;
+}
+
+void OFileAccess::setInteractionHandler( const Reference< XInteractionHandler >& Handler )
+{
+ if( !mxEnvironment.is() )
+ {
+ mxEnvironment = new OCommandEnvironment;
+ }
+ mxEnvironment->setHandler( Handler );
+}
+
+bool OFileAccess::createNewFile( const OUString & rParentURL,
+ const OUString & rTitle,
+ const Reference< XInputStream >& data )
+{
+ ucbhelper::Content aParentCnt( rParentURL, mxEnvironment, comphelper::getProcessComponentContext() );
+
+ const Sequence< ContentInfo > aInfo = aParentCnt.queryCreatableContentsInfo();
+
+ for ( const ContentInfo & rCurr : aInfo )
+ {
+ if ( ( rCurr.Attributes
+ & ContentInfoAttribute::KIND_DOCUMENT ) &&
+ ( rCurr.Attributes
+ & ContentInfoAttribute::INSERT_WITH_INPUTSTREAM ) )
+ {
+ // Make sure the only required bootstrap property is
+ // "Title",
+ const Sequence< Property > & rProps = rCurr.Properties;
+ if ( rProps.getLength() != 1 )
+ continue;
+
+ if ( rProps[ 0 ].Name != "Title" )
+ continue;
+
+ try
+ {
+ ucbhelper::Content aNew;
+ if ( aParentCnt.insertNewContent(
+ rCurr.Type, { "Title" }, { Any(rTitle) }, data, aNew ) )
+ return true; // success.
+ else
+ continue;
+ }
+ catch ( CommandFailedException const & )
+ {
+ // Interaction Handler already handled the
+ // error that has occurred...
+ continue;
+ }
+ }
+ }
+
+ return false;
+}
+
+void SAL_CALL OFileAccess::writeFile( const OUString& FileURL,
+ const Reference< XInputStream >& data )
+{
+ INetURLObject aURL( FileURL, INetProtocol::File );
+ try
+ {
+ ucbhelper::Content aCnt(
+ aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment,
+ comphelper::getProcessComponentContext() );
+
+ try
+ {
+ aCnt.writeStream( data, true /* bReplaceExisting */ );
+ }
+ catch ( CommandFailedException const & )
+ {
+ // Interaction Handler already handled the error that has occurred...
+ }
+ }
+ catch ( ContentCreationException const & e )
+ {
+ // Most probably file does not exist. Try to create.
+ if ( e.eError == ContentCreationError_CONTENT_CREATION_FAILED )
+ {
+ INetURLObject aParentURLObj( aURL );
+ if ( aParentURLObj.removeSegment() )
+ {
+ OUString aParentURL
+ = aParentURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ // ensure all parent folders exist.
+ createFolder( aParentURL );
+
+ // create the new file...
+ OUString aTitle
+ = aURL.getName( INetURLObject::LAST_SEGMENT,
+ true,
+ INetURLObject::DecodeMechanism::WithCharset );
+ if ( createNewFile( aParentURL, aTitle, data ) )
+ {
+ // success
+ return;
+ }
+ }
+ }
+
+ throw;
+ }
+}
+
+sal_Bool OFileAccess::isHidden( const OUString& FileURL )
+{
+ INetURLObject aURLObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ Any aRetAny = aCnt.getPropertyValue("IsHidden");
+ bool bRet = false;
+ aRetAny >>= bRet;
+ return bRet;
+}
+
+void OFileAccess::setHidden( const OUString& FileURL, sal_Bool bHidden )
+{
+ INetURLObject aURLObj( FileURL, INetProtocol::File );
+ ucbhelper::Content aCnt( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), mxEnvironment, comphelper::getProcessComponentContext() );
+ aCnt.setPropertyValue("IsHidden", Any(bHidden) );
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_OFileAccess_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new OFileAccess(context));
+}
+
+}; // namespace end
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/cmdenv.cxx b/ucb/source/core/cmdenv.cxx
new file mode 100644
index 000000000..9189f0e0f
--- /dev/null
+++ b/ucb/source/core/cmdenv.cxx
@@ -0,0 +1,117 @@
+/* -*- 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 <cppuhelper/factory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+#include "cmdenv.hxx"
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+using namespace com::sun::star;
+using namespace ucb_cmdenv;
+
+// UcbCommandEnvironment Implementation.
+
+
+UcbCommandEnvironment::UcbCommandEnvironment()
+{
+}
+
+
+// virtual
+UcbCommandEnvironment::~UcbCommandEnvironment()
+{
+}
+
+// XInitialization methods.
+
+
+// virtual
+void SAL_CALL UcbCommandEnvironment::initialize(
+ const uno::Sequence< uno::Any >& aArguments )
+{
+ if ( ( aArguments.getLength() < 2 ) ||
+ !( aArguments[ 0 ] >>= m_xIH ) ||
+ !( aArguments[ 1 ] >>= m_xPH ))
+ throw lang::IllegalArgumentException();
+}
+
+
+// XServiceInfo methods.
+
+
+// virtual
+OUString SAL_CALL UcbCommandEnvironment::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.CommandEnvironment";
+}
+
+
+// virtual
+sal_Bool SAL_CALL
+UcbCommandEnvironment::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+// virtual
+uno::Sequence< OUString > SAL_CALL
+UcbCommandEnvironment::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.CommandEnvironment" };
+}
+
+
+// XCommandInfo methods.
+
+
+// virtual
+uno::Reference< task::XInteractionHandler > SAL_CALL
+UcbCommandEnvironment::getInteractionHandler()
+{
+ return m_xIH;
+}
+
+
+// virtual
+uno::Reference< ucb::XProgressHandler > SAL_CALL
+UcbCommandEnvironment::getProgressHandler()
+{
+ return m_xPH;
+}
+
+
+// Service factory implementation.
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UcbCommandEnvironment_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UcbCommandEnvironment());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/cmdenv.hxx b/ucb/source/core/cmdenv.hxx
new file mode 100644
index 000000000..0cc4b46f4
--- /dev/null
+++ b/ucb/source/core/cmdenv.hxx
@@ -0,0 +1,65 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <comphelper/compbase.hxx>
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+
+namespace ucb_cmdenv {
+
+using UcbCommandEnvironment_Base = comphelper::WeakComponentImplHelper< css::lang::XInitialization,
+ css::lang::XServiceInfo,
+ css::ucb::XCommandEnvironment >;
+
+class UcbCommandEnvironment : public UcbCommandEnvironment_Base
+{
+ css::uno::Reference< css::task::XInteractionHandler > m_xIH;
+ css::uno::Reference< css::ucb::XProgressHandler > m_xPH;
+
+public:
+ explicit UcbCommandEnvironment();
+ virtual ~UcbCommandEnvironment() override;
+
+ // XInitialization
+ virtual void SAL_CALL
+ initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService( const OUString& ServiceName ) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XCommandEnvironment
+ virtual css::uno::Reference< css::task::XInteractionHandler > SAL_CALL
+ getInteractionHandler() override;
+ virtual css::uno::Reference< css::ucb::XProgressHandler > SAL_CALL
+ getProgressHandler() override;
+};
+
+} // namespace ucb_cmdenv
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/identify.cxx b/ucb/source/core/identify.cxx
new file mode 100644
index 000000000..41f5db735
--- /dev/null
+++ b/ucb/source/core/identify.cxx
@@ -0,0 +1,63 @@
+/* -*- 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 .
+ */
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+
+#include "identify.hxx"
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+
+// ContentIdentifier Implementation.
+ContentIdentifier::ContentIdentifier(const OUString& ContentId)
+ : m_aContentId(ContentId)
+{
+}
+
+// virtual
+ContentIdentifier::~ContentIdentifier() {}
+
+// XContentIdentifier methods.
+// virtual
+OUString SAL_CALL ContentIdentifier::getContentIdentifier() { return m_aContentId; }
+
+// virtual
+OUString SAL_CALL ContentIdentifier::getContentProviderScheme()
+{
+ if (m_aProviderScheme.isEmpty() && !m_aContentId.isEmpty())
+ {
+ // The content provider scheme is the part before the first ':'
+ // within the content id.
+ sal_Int32 nPos = m_aContentId.indexOf(':');
+ if (nPos != -1)
+ {
+ OUString aScheme(m_aContentId.copy(0, nPos));
+ m_aProviderScheme = aScheme.toAsciiLowerCase();
+ }
+ }
+
+ return m_aProviderScheme;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/identify.hxx b/ucb/source/core/identify.hxx
new file mode 100644
index 000000000..357fef39a
--- /dev/null
+++ b/ucb/source/core/identify.hxx
@@ -0,0 +1,40 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/ucb/XContentIdentifier.hpp>
+#include <cppuhelper/implbase.hxx>
+
+class ContentIdentifier : public cppu::WeakImplHelper<css::ucb::XContentIdentifier>
+{
+public:
+ explicit ContentIdentifier(const OUString& ContentId);
+ virtual ~ContentIdentifier() override;
+
+ // XContentIdentifier
+ virtual OUString SAL_CALL getContentIdentifier() override;
+ virtual OUString SAL_CALL getContentProviderScheme() override;
+
+private:
+ OUString m_aContentId;
+ OUString m_aProviderScheme;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/providermap.hxx b/ucb/source/core/providermap.hxx
new file mode 100644
index 000000000..1d4c65aa5
--- /dev/null
+++ b/ucb/source/core/providermap.hxx
@@ -0,0 +1,63 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <deque>
+#include <com/sun/star/uno/Reference.h>
+#include <regexpmap.hxx>
+
+namespace com::sun::star::ucb {
+ class XContentProvider;
+}
+
+
+class ProviderListEntry_Impl
+{
+ css::uno::Reference<
+ css::ucb::XContentProvider > m_xProvider;
+ mutable css::uno::Reference<
+ css::ucb::XContentProvider > m_xResolvedProvider;
+
+private:
+ css::uno::Reference< css::ucb::XContentProvider > const & resolveProvider() const;
+
+public:
+ explicit ProviderListEntry_Impl(
+ const css::uno::Reference< css::ucb::XContentProvider >& xProvider )
+ : m_xProvider( xProvider ) {}
+
+ const css::uno::Reference< css::ucb::XContentProvider >& getProvider() const
+ { return m_xProvider; }
+ inline css::uno::Reference< css::ucb::XContentProvider > const & getResolvedProvider() const;
+};
+
+inline css::uno::Reference< css::ucb::XContentProvider > const &
+ProviderListEntry_Impl::getResolvedProvider() const
+{
+ return m_xResolvedProvider.is() ? m_xResolvedProvider : resolveProvider();
+}
+
+
+typedef std::deque< ProviderListEntry_Impl > ProviderList_Impl;
+
+
+typedef ucb_impl::RegexpMap< ProviderList_Impl > ProviderMap_Impl;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/provprox.cxx b/ucb/source/core/provprox.cxx
new file mode 100644
index 000000000..7af7ba28a
--- /dev/null
+++ b/ucb/source/core/provprox.cxx
@@ -0,0 +1,353 @@
+/* -*- 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 <osl/diagnose.h>
+#include <osl/thread.h>
+#include <rtl/strbuf.hxx>
+#include <tools/diagnose_ex.h>
+#include "provprox.hxx"
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/weak.hxx>
+#include <ucbhelper/macros.hxx>
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+
+// UcbContentProviderProxyFactory Implementation.
+
+
+UcbContentProviderProxyFactory::UcbContentProviderProxyFactory(
+ const Reference< XComponentContext >& rxContext )
+: m_xContext( rxContext )
+{
+}
+
+
+// virtual
+UcbContentProviderProxyFactory::~UcbContentProviderProxyFactory()
+{
+}
+
+// XServiceInfo methods.
+
+OUString SAL_CALL UcbContentProviderProxyFactory::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UcbContentProviderProxyFactory";
+}
+sal_Bool SAL_CALL UcbContentProviderProxyFactory::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+css::uno::Sequence< OUString > SAL_CALL UcbContentProviderProxyFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.ContentProviderProxyFactory" };
+}
+
+// Service factory implementation.
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UcbContentProviderProxyFactory_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UcbContentProviderProxyFactory(context));
+}
+
+
+// XContentProviderFactory methods.
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+UcbContentProviderProxyFactory::createContentProvider(
+ const OUString& Service )
+{
+ return Reference< XContentProvider >(
+ new UcbContentProviderProxy( m_xContext, Service ) );
+}
+
+
+// UcbContentProviderProxy Implementation.
+
+
+UcbContentProviderProxy::UcbContentProviderProxy(
+ const Reference< XComponentContext >& rxContext,
+ const OUString& Service )
+: m_aService( Service ),
+ m_bReplace( false ),
+ m_bRegister( false ),
+ m_xContext( rxContext )
+{
+}
+
+
+// virtual
+UcbContentProviderProxy::~UcbContentProviderProxy()
+{
+}
+
+
+// XInterface methods.
+void SAL_CALL UcbContentProviderProxy::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL UcbContentProviderProxy::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+// virtual
+Any SAL_CALL
+UcbContentProviderProxy::queryInterface( const Type & rType )
+{
+ Any aRet = cppu::queryInterface( rType,
+ static_cast< XTypeProvider * >( this ),
+ static_cast< XServiceInfo * >( this ),
+ static_cast< XContentProvider * >( this ),
+ static_cast< XParameterizedContentProvider * >( this ),
+ static_cast< XContentProviderSupplier * >( this ) );
+
+ if ( !aRet.hasValue() )
+ aRet = OWeakObject::queryInterface( rType );
+
+ if ( !aRet.hasValue() )
+ {
+ // Get original provider and forward the call...
+ Reference< XContentProvider > xProvider = getContentProvider();
+ if ( xProvider.is() )
+ aRet = xProvider->queryInterface( rType );
+ }
+
+ return aRet;
+}
+
+
+// XTypeProvider methods.
+
+
+XTYPEPROVIDER_COMMON_IMPL( UcbContentProviderProxy );
+
+
+Sequence< Type > SAL_CALL UcbContentProviderProxy::getTypes()
+{
+ // Get original provider and forward the call...
+ Reference< XTypeProvider > xProvider( getContentProvider(), UNO_QUERY );
+ if ( xProvider.is() )
+ {
+ return xProvider->getTypes();
+ }
+ else
+ {
+ static cppu::OTypeCollection s_aCollection(
+ CPPU_TYPE_REF( XTypeProvider ),
+ CPPU_TYPE_REF( XServiceInfo ),
+ CPPU_TYPE_REF( XContentProvider ),
+ CPPU_TYPE_REF( XParameterizedContentProvider ),
+ CPPU_TYPE_REF( XContentProviderSupplier ) );
+ return s_aCollection.getTypes();
+ }
+}
+
+
+// XServiceInfo methods.
+
+OUString SAL_CALL UcbContentProviderProxy::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UcbContentProviderProxy";
+}
+
+sal_Bool SAL_CALL UcbContentProviderProxy::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL UcbContentProviderProxy::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.ContentProviderProxy" };
+}
+
+
+// XContentProvider methods.
+
+
+// virtual
+Reference< XContent > SAL_CALL UcbContentProviderProxy::queryContent(
+ const Reference< XContentIdentifier >& Identifier )
+{
+ // Get original provider and forward the call...
+
+ Reference< XContentProvider > xProvider = getContentProvider();
+ if ( xProvider.is() )
+ return xProvider->queryContent( Identifier );
+
+ return Reference< XContent >();
+}
+
+
+// virtual
+sal_Int32 SAL_CALL UcbContentProviderProxy::compareContentIds(
+ const Reference< XContentIdentifier >& Id1,
+ const Reference< XContentIdentifier >& Id2 )
+{
+ // Get original provider and forward the call...
+
+ Reference< XContentProvider > xProvider = getContentProvider();
+ if ( xProvider.is() )
+ return xProvider->compareContentIds( Id1, Id2 );
+
+ // OSL_FAIL( // "UcbContentProviderProxy::compareContentIds - No provider!" );
+
+ // @@@ What else?
+ return 0;
+}
+
+
+// XParameterizedContentProvider methods.
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+UcbContentProviderProxy::registerInstance( const OUString& Template,
+ const OUString& Arguments,
+ sal_Bool ReplaceExisting )
+{
+ // Just remember that this method was called ( and the params ).
+
+ std::scoped_lock aGuard( m_aMutex );
+
+ if ( !m_bRegister )
+ {
+// m_xTargetProvider = 0;
+ m_aTemplate = Template;
+ m_aArguments = Arguments;
+ m_bReplace = ReplaceExisting;
+
+ m_bRegister = true;
+ }
+ return this;
+}
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+UcbContentProviderProxy::deregisterInstance( const OUString& Template,
+ const OUString& Arguments )
+{
+ std::scoped_lock aGuard( m_aMutex );
+
+ // registerInstance called at proxy and at original?
+ if ( m_bRegister && m_xTargetProvider.is() )
+ {
+ m_bRegister = false;
+ m_xTargetProvider = nullptr;
+
+ Reference< XParameterizedContentProvider >
+ xParamProvider( m_xProvider, UNO_QUERY );
+ if ( xParamProvider.is() )
+ {
+ try
+ {
+ xParamProvider->deregisterInstance( Template, Arguments );
+ }
+ catch ( IllegalIdentifierException const & )
+ {
+ OSL_FAIL( "UcbContentProviderProxy::deregisterInstance - "
+ "Caught IllegalIdentifierException!" );
+ }
+ }
+ }
+
+ return this;
+}
+
+
+// XContentProviderSupplier methods.
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+UcbContentProviderProxy::getContentProvider()
+{
+ std::scoped_lock aGuard( m_aMutex );
+ if ( !m_xProvider.is() )
+ {
+ try
+ {
+ m_xProvider.set( m_xContext->getServiceManager()->createInstanceWithContext( m_aService,m_xContext ), UNO_QUERY );
+ if ( m_aArguments == "NoConfig" )
+ {
+ Reference<XInitialization> xInit(m_xProvider,UNO_QUERY);
+ if(xInit.is()) {
+ xInit->initialize({ Any(m_aArguments) });
+ }
+ }
+ }
+ catch ( RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( Exception const & )
+ {
+ TOOLS_INFO_EXCEPTION( "ucb.core", "Exception getting content provider");
+ }
+
+ // registerInstance called at proxy, but not yet at original?
+ if ( m_xProvider.is() && m_bRegister )
+ {
+ Reference< XParameterizedContentProvider >
+ xParamProvider( m_xProvider, UNO_QUERY );
+ if ( xParamProvider.is() )
+ {
+ try
+ {
+ m_xTargetProvider
+ = xParamProvider->registerInstance( m_aTemplate,
+ m_aArguments,
+ m_bReplace );
+ }
+ catch ( IllegalIdentifierException const & )
+ {
+ OSL_FAIL( "UcbContentProviderProxy::getContentProvider - "
+ "Caught IllegalIdentifierException!" );
+ }
+
+ OSL_ENSURE( m_xTargetProvider.is(),
+ "UcbContentProviderProxy::getContentProvider - "
+ "No provider!" );
+ }
+ }
+ if ( !m_xTargetProvider.is() )
+ m_xTargetProvider = m_xProvider;
+ }
+
+ OSL_ENSURE( m_xProvider.is(),
+ OStringBuffer("UcbContentProviderProxy::getContentProvider - No provider for '" +
+ OUStringToOString(m_aService, osl_getThreadTextEncoding()) +
+ ".").getStr() );
+ return m_xTargetProvider;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/provprox.hxx b/ucb/source/core/provprox.hxx
new file mode 100644
index 000000000..1654fa342
--- /dev/null
+++ b/ucb/source/core/provprox.hxx
@@ -0,0 +1,126 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ucb/XContentProviderFactory.hpp>
+#include <com/sun/star/ucb/XContentProvider.hpp>
+#include <com/sun/star/ucb/XParameterizedContentProvider.hpp>
+#include <com/sun/star/ucb/XContentProviderSupplier.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <comphelper/compbase.hxx>
+#include <cppuhelper/weak.hxx>
+
+
+
+using UcbContentProviderProxyFactory_Base = comphelper::WeakComponentImplHelper <
+ css::lang::XServiceInfo,
+ css::ucb::XContentProviderFactory >;
+class UcbContentProviderProxyFactory : public UcbContentProviderProxyFactory_Base
+{
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+public:
+ explicit UcbContentProviderProxyFactory(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+ virtual ~UcbContentProviderProxyFactory() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XContentProviderFactory
+ virtual css::uno::Reference< css::ucb::XContentProvider > SAL_CALL
+ createContentProvider( const OUString& Service ) override;
+};
+
+
+
+
+class UcbContentProviderProxy :
+ public cppu::OWeakObject,
+ public css::lang::XTypeProvider,
+ public css::lang::XServiceInfo,
+ public css::ucb::XContentProviderSupplier,
+ public css::ucb::XContentProvider,
+ public css::ucb::XParameterizedContentProvider
+{
+ std::mutex m_aMutex;
+ OUString m_aService;
+ OUString m_aTemplate;
+ OUString m_aArguments;
+ bool m_bReplace;
+ bool m_bRegister;
+
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+ css::uno::Reference< css::ucb::XContentProvider >
+ m_xProvider;
+ css::uno::Reference< css::ucb::XContentProvider >
+ m_xTargetProvider;
+
+public:
+ UcbContentProviderProxy(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const OUString& Service );
+ virtual ~UcbContentProviderProxy() 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< sal_Int8 > SAL_CALL getImplementationId() override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XContentProviderSupplier
+ virtual css::uno::Reference<
+ css::ucb::XContentProvider > SAL_CALL
+ getContentProvider() override;
+
+ // XContentProvider
+ virtual css::uno::Reference<
+ css::ucb::XContent > SAL_CALL
+ queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override;
+ virtual sal_Int32 SAL_CALL
+ compareContentIds( const css::uno::Reference< css::ucb::XContentIdentifier >& Id1,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Id2 ) override;
+
+ // XParameterizedContentProvider
+ virtual css::uno::Reference< css::ucb::XContentProvider > SAL_CALL
+ registerInstance( const OUString& Template,
+ const OUString& Arguments,
+ sal_Bool ReplaceExisting ) override;
+ virtual css::uno::Reference< css::ucb::XContentProvider > SAL_CALL
+ deregisterInstance( const OUString& Template,
+ const OUString& Arguments ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucb.cxx b/ucb/source/core/ucb.cxx
new file mode 100644
index 000000000..4e41e8cff
--- /dev/null
+++ b/ucb/source/core/ucb.cxx
@@ -0,0 +1,887 @@
+/* -*- 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 .
+ */
+
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ucb/DuplicateProviderException.hpp>
+#include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/ucb/XContentProviderSupplier.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <tools/diagnose_ex.h>
+#include "identify.hxx"
+#include "ucbcmds.hxx"
+
+#include "ucb.hxx"
+
+using namespace comphelper;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace ucb_impl;
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+namespace {
+
+bool fillPlaceholders(OUString const & rInput,
+ uno::Sequence< uno::Any > const & rReplacements,
+ OUString * pOutput)
+{
+ sal_Unicode const * p = rInput.getStr();
+ sal_Unicode const * pEnd = p + rInput.getLength();
+ sal_Unicode const * pCopy = p;
+ OUStringBuffer aBuffer;
+ while (p != pEnd)
+ switch (*p++)
+ {
+ case '&':
+ if (pEnd - p >= 4
+ && p[0] == 'a' && p[1] == 'm' && p[2] == 'p'
+ && p[3] == ';')
+ {
+ aBuffer.append(pCopy, p - 1 - pCopy);
+ aBuffer.append('&');
+ p += 4;
+ pCopy = p;
+ }
+ else if (pEnd - p >= 3
+ && p[0] == 'l' && p[1] == 't' && p[2] == ';')
+ {
+ aBuffer.append(pCopy, p - 1 - pCopy);
+ aBuffer.append('<');
+ p += 3;
+ pCopy = p;
+ }
+ else if (pEnd - p >= 3
+ && p[0] == 'g' && p[1] == 't' && p[2] == ';')
+ {
+ aBuffer.append(pCopy, p - 1 - pCopy);
+ aBuffer.append('>');
+ p += 3;
+ pCopy = p;
+ }
+ break;
+
+ case '<':
+ sal_Unicode const * q = p;
+ while (q != pEnd && *q != '>')
+ ++q;
+ if (q == pEnd)
+ break;
+ OUString aKey(p, q - p);
+ OUString aValue;
+ bool bFound = false;
+ for (sal_Int32 i = 2; i + 1 < rReplacements.getLength();
+ i += 2)
+ {
+ OUString aReplaceKey;
+ if ((rReplacements[i] >>= aReplaceKey)
+ && aReplaceKey == aKey
+ && (rReplacements[i + 1] >>= aValue))
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ return false;
+ aBuffer.append(pCopy, p - 1 - pCopy);
+ aBuffer.append(aValue);
+ p = q + 1;
+ pCopy = p;
+ break;
+ }
+ aBuffer.append(pCopy, pEnd - pCopy);
+ *pOutput = aBuffer.makeStringAndClear();
+ return true;
+}
+
+void makeAndAppendXMLName(
+ OUStringBuffer & rBuffer, const OUString & rIn )
+{
+ sal_Int32 nCount = rIn.getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const sal_Unicode c = rIn[ n ];
+ switch ( c )
+ {
+ case '&':
+ rBuffer.append( "&amp;" );
+ break;
+
+ case '"':
+ rBuffer.append( "&quot;" );
+ break;
+
+ case '\'':
+ rBuffer.append( "&apos;" );
+ break;
+
+ case '<':
+ rBuffer.append( "&lt;" );
+ break;
+
+ case '>':
+ rBuffer.append( "&gt;" );
+ break;
+
+ default:
+ rBuffer.append( c );
+ break;
+ }
+ }
+}
+
+bool createContentProviderData(
+ std::u16string_view rProvider,
+ const uno::Reference< container::XHierarchicalNameAccess >& rxHierNameAccess,
+ ContentProviderData & rInfo)
+{
+ // Obtain service name.
+
+ OUString aValue;
+ try
+ {
+ if ( !( rxHierNameAccess->getByHierarchicalName(
+ OUString::Concat(rProvider) + "/ServiceName" ) >>= aValue ) )
+ {
+ OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
+ "Error getting item value!" );
+ }
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ return false;
+ }
+
+ rInfo.ServiceName = aValue;
+
+ // Obtain URL Template.
+
+ if ( !( rxHierNameAccess->getByHierarchicalName(
+ OUString::Concat(rProvider) + "/URLTemplate" ) >>= aValue ) )
+ {
+ OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
+ "Error getting item value!" );
+ }
+
+ rInfo.URLTemplate = aValue;
+
+ // Obtain Arguments.
+
+ if ( !( rxHierNameAccess->getByHierarchicalName(
+ OUString::Concat(rProvider) + "/Arguments" ) >>= aValue ) )
+ {
+ OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
+ "Error getting item value!" );
+ }
+
+ rInfo.Arguments = aValue;
+ return true;
+}
+
+}
+
+
+// UniversalContentBroker Implementation.
+
+
+UniversalContentBroker::UniversalContentBroker(
+ const Reference< css::uno::XComponentContext >& xContext )
+: m_xContext( xContext ),
+ m_nCommandId( 0 )
+{
+ OSL_ENSURE( m_xContext.is(),
+ "UniversalContentBroker ctor: No service manager" );
+}
+
+
+// virtual
+UniversalContentBroker::~UniversalContentBroker()
+{
+}
+
+
+// XComponent methods.
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::dispose()
+{
+ if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XComponent* >(this);
+ m_pDisposeEventListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_xNotifier.is() )
+ m_xNotifier->removeChangesListener( this );
+}
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::addEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( !m_pDisposeEventListeners )
+ m_pDisposeEventListeners.reset( new OInterfaceContainerHelper3<css::lang::XEventListener>( m_aMutex ) );
+
+ m_pDisposeEventListeners->addInterface( Listener );
+}
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::removeEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( m_pDisposeEventListeners )
+ m_pDisposeEventListeners->removeInterface( Listener );
+
+ // Note: Don't want to delete empty container here -> performance.
+}
+
+
+// XServiceInfo methods.
+
+OUString SAL_CALL UniversalContentBroker::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UniversalContentBroker";
+}
+sal_Bool SAL_CALL UniversalContentBroker::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+css::uno::Sequence< OUString > SAL_CALL UniversalContentBroker::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.UniversalContentBroker" };
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UniversalContentBroker_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UniversalContentBroker(context));
+}
+
+
+// XInitialization methods.
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::initialize( const css::uno::Sequence< Any >& aArguments )
+{
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_aArguments.hasElements())
+ {
+ if (aArguments.hasElements()
+ && !(m_aArguments.getLength() == 2
+ && aArguments.getLength() == 2
+ && m_aArguments[0] == aArguments[0]
+ && m_aArguments[1] == aArguments[1]))
+ {
+ throw IllegalArgumentException(
+ "UCB reinitialized with different arguments",
+ static_cast< cppu::OWeakObject * >(this), 0);
+ }
+ return;
+ }
+ if (!aArguments.hasElements())
+ {
+ m_aArguments = { Any(OUString("Local")), Any(OUString("Office")) };
+ }
+ else
+ {
+ m_aArguments = aArguments;
+ }
+ }
+ configureUcb();
+}
+
+
+// XContentProviderManager methods.
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+UniversalContentBroker::registerContentProvider(
+ const Reference< XContentProvider >& Provider,
+ const OUString& Scheme,
+ sal_Bool ReplaceExisting )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ProviderMap_Impl::iterator aIt;
+ try
+ {
+ aIt = m_aProviders.find(Scheme);
+ }
+ catch (const IllegalArgumentException&)
+ {
+ return nullptr; //@@@
+ }
+
+ Reference< XContentProvider > xPrevious;
+ if (aIt == m_aProviders.end())
+ {
+ ProviderList_Impl aList;
+ aList.push_front( ProviderListEntry_Impl(Provider) );
+ try
+ {
+ m_aProviders.add(Scheme, aList);
+ }
+ catch (const IllegalArgumentException&)
+ {
+ return nullptr; //@@@
+ }
+ }
+ else
+ {
+ if (!ReplaceExisting)
+ throw DuplicateProviderException();
+
+ ProviderList_Impl & rList = aIt->getValue();
+ xPrevious = rList.front().getProvider();
+ rList.push_front( ProviderListEntry_Impl(Provider) );
+ }
+
+ return xPrevious;
+}
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::deregisterContentProvider(
+ const Reference< XContentProvider >& Provider,
+ const OUString& Scheme )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ ProviderMap_Impl::iterator aMapIt;
+ try
+ {
+ aMapIt = m_aProviders.find(Scheme);
+ }
+ catch (const IllegalArgumentException&)
+ {
+ return; //@@@
+ }
+
+ if (aMapIt != m_aProviders.end())
+ {
+ ProviderList_Impl & rList = aMapIt->getValue();
+
+ auto aListIt = std::find_if(rList.begin(), rList.end(),
+ [&Provider](const ProviderListEntry_Impl& rEntry) { return rEntry.getProvider() == Provider; });
+ if (aListIt != rList.end())
+ rList.erase(aListIt);
+
+ if (rList.empty())
+ m_aProviders.erase(aMapIt);
+ }
+}
+
+
+// virtual
+css::uno::Sequence< ContentProviderInfo > SAL_CALL
+ UniversalContentBroker::queryContentProviders()
+{
+ // Return a list with information about active(!) content providers.
+
+ osl::MutexGuard aGuard(m_aMutex);
+
+ css::uno::Sequence< ContentProviderInfo > aSeq( m_aProviders.size() );
+ ContentProviderInfo* pInfo = aSeq.getArray();
+
+ ProviderMap_Impl::const_iterator end = m_aProviders.end();
+ for (ProviderMap_Impl::const_iterator it(m_aProviders.begin()); it != end;
+ ++it)
+ {
+ // Note: Active provider is always the first list element.
+ pInfo->ContentProvider = it->getValue().front().getProvider();
+ pInfo->Scheme = it->getRegexp();
+ ++pInfo;
+ }
+
+ return aSeq;
+}
+
+
+// virtual
+Reference< XContentProvider > SAL_CALL
+ UniversalContentBroker::queryContentProvider( const OUString&
+ Identifier )
+{
+ return queryContentProvider( Identifier, false );
+}
+
+
+// XContentProvider methods.
+
+
+// virtual
+Reference< XContent > SAL_CALL UniversalContentBroker::queryContent(
+ const Reference< XContentIdentifier >& Identifier )
+{
+
+ // Let the content provider for the scheme given with the content
+ // identifier create the XContent instance.
+
+
+ if ( !Identifier.is() )
+ return Reference< XContent >();
+
+ Reference< XContentProvider > xProv =
+ queryContentProvider( Identifier->getContentIdentifier(), true );
+ if ( xProv.is() )
+ return xProv->queryContent( Identifier );
+
+ return Reference< XContent >();
+}
+
+
+// virtual
+sal_Int32 SAL_CALL UniversalContentBroker::compareContentIds(
+ const Reference< XContentIdentifier >& Id1,
+ const Reference< XContentIdentifier >& Id2 )
+{
+ OUString aURI1( Id1->getContentIdentifier() );
+ OUString aURI2( Id2->getContentIdentifier() );
+
+ Reference< XContentProvider > xProv1
+ = queryContentProvider( aURI1, true );
+ Reference< XContentProvider > xProv2
+ = queryContentProvider( aURI2, true );
+
+ // When both identifiers belong to the same provider, let that provider
+ // compare them; otherwise, simply compare the URI strings (which must
+ // be different):
+ if ( xProv1.is() && ( xProv1 == xProv2 ) )
+ return xProv1->compareContentIds( Id1, Id2 );
+ else
+ return aURI1.compareTo( aURI2 );
+}
+
+
+// XContentIdentifierFactory methods.
+
+
+// virtual
+Reference< XContentIdentifier > SAL_CALL
+ UniversalContentBroker::createContentIdentifier(
+ const OUString& ContentId )
+{
+
+ // Let the content provider for the scheme given with content
+ // identifier create the XContentIdentifier instance, if he supports
+ // the XContentIdentifierFactory interface. Otherwise create standard
+ // implementation object for XContentIdentifier.
+
+
+ Reference< XContentIdentifier > xIdentifier;
+
+ Reference< XContentProvider > xProv
+ = queryContentProvider( ContentId, true );
+ if ( xProv.is() )
+ {
+ Reference< XContentIdentifierFactory > xFac( xProv, UNO_QUERY );
+ if ( xFac.is() )
+ xIdentifier = xFac->createContentIdentifier( ContentId );
+ }
+
+ if ( !xIdentifier.is() )
+ xIdentifier = new ContentIdentifier( ContentId );
+
+ return xIdentifier;
+}
+
+
+// XCommandProcessor methods.
+
+
+// virtual
+sal_Int32 SAL_CALL UniversalContentBroker::createCommandIdentifier()
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // Just increase counter on every call to generate an identifier.
+ return ++m_nCommandId;
+}
+
+
+// virtual
+Any SAL_CALL UniversalContentBroker::execute(
+ const Command& aCommand,
+ sal_Int32,
+ const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+
+
+ // Note: Don't forget to adapt ucb_commands::CommandProcessorInfo
+ // ctor in ucbcmds.cxx when adding new commands!
+
+
+ if ( ( aCommand.Handle == GETCOMMANDINFO_HANDLE ) || aCommand.Name == GETCOMMANDINFO_NAME )
+ {
+
+ // getCommandInfo
+
+
+ aRet <<= getCommandInfo();
+ }
+ else if ( ( aCommand.Handle == GLOBALTRANSFER_HANDLE ) || aCommand.Name == GLOBALTRANSFER_NAME )
+ {
+
+ // globalTransfer
+
+
+ GlobalTransferCommandArgument2 aTransferArg;
+ if ( !( aCommand.Argument >>= aTransferArg ) )
+ {
+ GlobalTransferCommandArgument aArg;
+ if ( !( aCommand.Argument >>= aArg ) )
+ {
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+
+ // Copy infos into the new structure
+ aTransferArg.Operation = aArg.Operation;
+ aTransferArg.SourceURL = aArg.SourceURL;
+ aTransferArg.TargetURL = aArg.TargetURL;
+ aTransferArg.NewTitle = aArg.NewTitle;
+ aTransferArg.NameClash = aArg.NameClash;
+ }
+
+ globalTransfer( aTransferArg, Environment );
+ }
+ else if ( ( aCommand.Handle == CHECKIN_HANDLE ) || aCommand.Name == CHECKIN_NAME )
+ {
+ ucb::CheckinArgument aCheckinArg;
+ if ( !( aCommand.Argument >>= aCheckinArg ) )
+ {
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ aRet = checkIn( aCheckinArg, Environment );
+ }
+ else
+ {
+
+ // Unknown command
+
+
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedCommandException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ Environment );
+ // Unreachable
+ }
+
+ return aRet;
+}
+
+
+// XCommandProcessor2 methods.
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::releaseCommandIdentifier(sal_Int32 /*aCommandId*/)
+{
+ // @@@ Not implemented ( yet).
+}
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::abort( sal_Int32 )
+{
+ // @@@ Not implemented ( yet).
+}
+
+
+// XChangesListener methods
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::changesOccurred( const util::ChangesEvent& Event )
+{
+ if ( !Event.Changes.hasElements() )
+ return;
+
+ uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess;
+ Event.Base >>= xHierNameAccess;
+
+ OSL_ASSERT( xHierNameAccess.is() );
+
+ ContentProviderDataList aData;
+ for ( const util::ElementChange& rElem : Event.Changes )
+ {
+ OUString aKey;
+ rElem.Accessor >>= aKey;
+
+ ContentProviderData aInfo;
+
+ // Removal of UCPs from the configuration leads to changesOccurred
+ // notifications, too, but it is hard to tell for a given
+ // ElementChange whether it is an addition or a removal, so as a
+ // heuristic consider as removals those that cause a
+ // NoSuchElementException in createContentProviderData.
+
+ // For now, removal of UCPs from the configuration is simply ignored
+ // (and not reflected in the UCB's data structures):
+ if (createContentProviderData(aKey, xHierNameAccess, aInfo))
+ {
+ aData.push_back(aInfo);
+ }
+ }
+
+ prepareAndRegister(aData);
+}
+
+
+// XEventListener methods
+
+
+// virtual
+void SAL_CALL UniversalContentBroker::disposing(const lang::EventObject&)
+{
+ if ( m_xNotifier.is() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( m_xNotifier.is() )
+ m_xNotifier.clear();
+ }
+}
+
+
+// Non-interface methods
+
+
+Reference< XContentProvider > UniversalContentBroker::queryContentProvider(
+ const OUString& Identifier,
+ bool bResolved )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ProviderList_Impl const * pList = m_aProviders.map( Identifier );
+ return pList ? bResolved ? pList->front().getResolvedProvider()
+ : pList->front().getProvider()
+ : Reference< XContentProvider >();
+}
+
+void UniversalContentBroker::configureUcb()
+{
+ OUString aKey1;
+ OUString aKey2;
+ if (m_aArguments.getLength() < 2
+ || !(m_aArguments[0] >>= aKey1) || !(m_aArguments[1] >>= aKey2))
+ {
+ OSL_FAIL("UniversalContentBroker::configureUcb(): Bad arguments");
+ return;
+ }
+
+ ContentProviderDataList aData;
+ if (!getContentProviderData(aKey1, aKey2, aData))
+ {
+ SAL_WARN( "ucb", "No configuration");
+ return;
+ }
+
+ prepareAndRegister(aData);
+}
+
+void UniversalContentBroker::prepareAndRegister(
+ const ContentProviderDataList& rData)
+{
+ for (const auto& rContentProviderData : rData)
+ {
+ OUString aProviderArguments;
+ if (fillPlaceholders(rContentProviderData.Arguments,
+ m_aArguments,
+ &aProviderArguments))
+ {
+ registerAtUcb(this,
+ m_xContext,
+ rContentProviderData.ServiceName,
+ aProviderArguments,
+ rContentProviderData.URLTemplate);
+
+ }
+ else
+ OSL_FAIL("UniversalContentBroker::prepareAndRegister(): Bad argument placeholders");
+ }
+}
+
+
+bool UniversalContentBroker::getContentProviderData(
+ const OUString & rKey1,
+ const OUString & rKey2,
+ ContentProviderDataList & rListToFill )
+{
+ if ( !m_xContext.is() || rKey1.isEmpty() || rKey2.isEmpty() )
+ {
+ OSL_FAIL( "UniversalContentBroker::getContentProviderData - Invalid argument!" );
+ return false;
+ }
+
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xConfigProv =
+ configuration::theDefaultProvider::get( m_xContext );
+
+ OUStringBuffer aFullPath(128);
+ aFullPath.append(
+ "/org.openoffice.ucb.Configuration/ContentProviders"
+ "/['" );
+ makeAndAppendXMLName( aFullPath, rKey1 );
+ aFullPath.append( "']/SecondaryKeys/['" );
+ makeAndAppendXMLName( aFullPath, rKey2 );
+ aFullPath.append( "']/ProviderData" );
+
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", uno::Any(aFullPath.makeStringAndClear())}
+ }));
+
+ uno::Reference< uno::XInterface > xInterface(
+ xConfigProv->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments ) );
+
+ if ( !m_xNotifier.is() )
+ {
+ m_xNotifier.set( xInterface, uno::UNO_QUERY_THROW );
+
+ m_xNotifier->addChangesListener( this );
+ }
+
+ uno::Reference< container::XNameAccess > xNameAccess(
+ xInterface, uno::UNO_QUERY_THROW );
+
+ const uno::Sequence< OUString > aElems = xNameAccess->getElementNames();
+
+ if ( aElems.hasElements() )
+ {
+ uno::Reference< container::XHierarchicalNameAccess >
+ xHierNameAccess( xInterface, uno::UNO_QUERY_THROW );
+
+ // Iterate over children.
+ for ( const auto& rElem : aElems )
+ {
+
+ try
+ {
+
+ ContentProviderData aInfo;
+
+ OUStringBuffer aElemBuffer;
+ aElemBuffer.append( "['" );
+ makeAndAppendXMLName( aElemBuffer, rElem );
+ aElemBuffer.append( "']" );
+
+ OSL_VERIFY(
+ createContentProviderData(
+ aElemBuffer.makeStringAndClear(), xHierNameAccess,
+ aInfo));
+
+ rListToFill.push_back( aInfo );
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ // getByHierarchicalName
+ OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
+ "caught NoSuchElementException!" );
+ }
+ }
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION( "ucb", "" );
+ return false;
+ }
+ catch (const uno::Exception&)
+ {
+ // createInstance, createInstanceWithArguments
+
+ TOOLS_WARN_EXCEPTION( "ucb", "" );
+ return false;
+ }
+
+ return true;
+}
+
+
+// ProviderListEntry_Impl implementation.
+
+
+Reference< XContentProvider > const & ProviderListEntry_Impl::resolveProvider() const
+{
+ if ( !m_xResolvedProvider.is() )
+ {
+ Reference< XContentProviderSupplier > xSupplier(
+ m_xProvider, UNO_QUERY );
+ if ( xSupplier.is() )
+ m_xResolvedProvider = xSupplier->getContentProvider();
+
+ if ( !m_xResolvedProvider.is() )
+ m_xResolvedProvider = m_xProvider;
+ }
+
+ return m_xResolvedProvider;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucb.hxx b/ucb/source/core/ucb.hxx
new file mode 100644
index 000000000..49c6e0b37
--- /dev/null
+++ b/ucb/source/core/ucb.hxx
@@ -0,0 +1,158 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+
+#include <com/sun/star/ucb/CheckinArgument.hpp>
+#include <com/sun/star/ucb/XUniversalContentBroker.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include "providermap.hxx"
+#include <ucbhelper/registerucb.hxx>
+
+#include <memory>
+
+
+namespace com::sun::star::ucb {
+ class XCommandInfo;
+ struct GlobalTransferCommandArgument2;
+}
+
+class UniversalContentBroker :
+ public cppu::WeakImplHelper<
+ css::ucb::XUniversalContentBroker,
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::util::XChangesListener>
+{
+public:
+ explicit UniversalContentBroker( const css::uno::Reference< css::uno::XComponentContext >& xContext );
+ virtual ~UniversalContentBroker() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL
+ dispose() override;
+ virtual void SAL_CALL
+ addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override;
+ virtual void SAL_CALL
+ removeEventListener( const css::uno::Reference<
+ css::lang::XEventListener >& Listener ) override;
+
+ // XInitialization
+ virtual void SAL_CALL
+ initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XContentProviderManager
+ virtual css::uno::Reference< css::ucb::XContentProvider > SAL_CALL
+ registerContentProvider( const css::uno::Reference< css::ucb::XContentProvider >& Provider,
+ const OUString& Scheme,
+ sal_Bool ReplaceExisting ) override;
+ virtual void SAL_CALL
+ deregisterContentProvider( const css::uno::Reference< css::ucb::XContentProvider >& Provider,
+ const OUString& Scheme ) override;
+ virtual css::uno::Sequence< css::ucb::ContentProviderInfo > SAL_CALL
+ queryContentProviders() override;
+ virtual css::uno::Reference< css::ucb::XContentProvider > SAL_CALL
+ queryContentProvider( const OUString& Identifier ) override;
+
+ // XContentProvider
+ virtual css::uno::Reference< css::ucb::XContent > SAL_CALL
+ queryContent( const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override;
+ virtual sal_Int32 SAL_CALL
+ compareContentIds( const css::uno::Reference< css::ucb::XContentIdentifier >& Id1,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Id2 ) override;
+
+ // XContentIdentifierFactory
+ virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL
+ createContentIdentifier( const OUString& ContentId ) override;
+
+ // XCommandProcessor
+ virtual sal_Int32 SAL_CALL
+ createCommandIdentifier() override;
+ virtual css::uno::Any SAL_CALL
+ execute( const css::ucb::Command& aCommand,
+ sal_Int32 CommandId,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override;
+ virtual void SAL_CALL
+ abort( sal_Int32 CommandId ) override;
+
+ // XCommandProcessor2
+ virtual void SAL_CALL releaseCommandIdentifier(sal_Int32 aCommandId) override;
+
+ // XChangesListener
+ virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& Event ) override;
+
+ // XEventListener ( base of XChangesLisetenr )
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+private:
+ css::uno::Reference< css::ucb::XContentProvider >
+ queryContentProvider( const OUString& Identifier,
+ bool bResolved );
+
+ static css::uno::Reference< css::ucb::XCommandInfo >
+ getCommandInfo();
+
+ /// @throws css::uno::Exception
+ void
+ globalTransfer(
+ const css::ucb::GlobalTransferCommandArgument2 & rArg,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv );
+
+ /// @throws css::uno::Exception
+ css::uno::Any checkIn( const css::ucb::CheckinArgument& rArg,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv );
+
+
+ /// @throws css::uno::RuntimeException
+ void configureUcb();
+
+ bool getContentProviderData(
+ const OUString & rKey1,
+ const OUString & rKey2,
+ ucbhelper::ContentProviderDataList & rListToFill);
+
+ void prepareAndRegister( const ucbhelper::ContentProviderDataList& rData);
+
+ css::uno::Reference<
+ css::uno::XComponentContext > m_xContext;
+
+ css::uno::Reference<
+ css::util::XChangesNotifier > m_xNotifier;
+
+ css::uno::Sequence< css::uno::Any > m_aArguments;
+ ProviderMap_Impl m_aProviders;
+ osl::Mutex m_aMutex;
+ std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::lang::XEventListener>> m_pDisposeEventListeners;
+ sal_Int32 m_nCommandId;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucb1.component b/ucb/source/core/ucb1.component
new file mode 100644
index 000000000..952d37406
--- /dev/null
+++ b/ucb/source/core/ucb1.component
@@ -0,0 +1,46 @@
+<?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.ucb.CommandEnvironment"
+ constructor="ucb_UcbCommandEnvironment_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.CommandEnvironment"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ucb.UcbContentProviderProxyFactory"
+ constructor="ucb_UcbContentProviderProxyFactory_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.ContentProviderProxyFactory"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ucb.UcbPropertiesManager"
+ constructor="ucb_UcbPropertiesManager_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.PropertiesManager"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ucb.UcbStore"
+ constructor="ucb_UcbStore_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.Store"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ucb.UniversalContentBroker"
+ constructor="ucb_UniversalContentBroker_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.UniversalContentBroker"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ucb.SimpleFileAccess"
+ constructor="ucb_OFileAccess_get_implementation">
+ <service name="com.sun.star.ucb.SimpleFileAccess"/>
+ </implementation>
+</component>
diff --git a/ucb/source/core/ucbcmds.cxx b/ucb/source/core/ucbcmds.cxx
new file mode 100644
index 000000000..f0e45b7cb
--- /dev/null
+++ b/ucb/source/core/ucbcmds.cxx
@@ -0,0 +1,1923 @@
+/* -*- 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 <osl/diagnose.h>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/Pipe.hpp>
+#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/ucb/CommandEnvironment.hpp>
+#include <com/sun/star/ucb/CommandFailedException.hpp>
+#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
+#include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument2.hpp>
+#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/ucb/NameClashException.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/ucb/TransferInfo2.hpp>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/ucb/UnsupportedNameClashException.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+#include <com/sun/star/ucb/XContentCreator.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <com/sun/star/ucb/XInteractionSupplyName.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <ucbhelper/simplenameclashresolverequest.hxx>
+#include "ucbcmds.hxx"
+#include "ucb.hxx"
+
+using namespace com::sun::star;
+
+namespace
+{
+// Helper to provide defaults for type and attributes (save some typing)
+beans::Property makeProperty(const OUString& n, sal_Int32 h, uno::Type t = {}, sal_Int16 a = {})
+{
+ return { n, h, t, a };
+}
+
+// struct TransferCommandContext.
+
+
+struct TransferCommandContext
+{
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< ucb::XCommandProcessor > xProcessor;
+ uno::Reference< ucb::XCommandEnvironment > xEnv;
+ uno::Reference< ucb::XCommandEnvironment > xOrigEnv;
+ ucb::GlobalTransferCommandArgument2 aArg;
+
+ TransferCommandContext(
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< ucb::XCommandProcessor > & rxProcessor,
+ const uno::Reference< ucb::XCommandEnvironment > & rxEnv,
+ const uno::Reference< ucb::XCommandEnvironment > & rxOrigEnv,
+ const ucb::GlobalTransferCommandArgument2 & rArg )
+ : m_xContext( xContext ), xProcessor( rxProcessor ), xEnv( rxEnv ),
+ xOrigEnv( rxOrigEnv ), aArg( rArg ) {}
+};
+
+
+
+
+class InteractionHandlerProxy :
+ public cppu::WeakImplHelper< task::XInteractionHandler >
+{
+ uno::Reference< task::XInteractionHandler > m_xOrig;
+
+public:
+ explicit InteractionHandlerProxy(
+ const uno::Reference< task::XInteractionHandler > & xOrig )
+ : m_xOrig( xOrig ) {}
+
+ // XInteractionHandler methods.
+ virtual void SAL_CALL handle(
+ const uno::Reference< task::XInteractionRequest >& Request ) override;
+};
+
+
+// virtual
+void SAL_CALL InteractionHandlerProxy::handle(
+ const uno::Reference< task::XInteractionRequest >& Request )
+{
+ if ( !m_xOrig.is() )
+ return;
+
+ // Filter unwanted requests by just not handling them.
+ uno::Any aRequest = Request->getRequest();
+
+ // "transfer"
+ ucb::InteractiveBadTransferURLException aBadTransferURLEx;
+ if ( aRequest >>= aBadTransferURLEx )
+ {
+ return;
+ }
+ else
+ {
+ // "transfer"
+ ucb::UnsupportedNameClashException aUnsupportedNameClashEx;
+ if ( aRequest >>= aUnsupportedNameClashEx )
+ {
+ if ( aUnsupportedNameClashEx.NameClash
+ != ucb::NameClash::ERROR )
+ return;
+ }
+ else
+ {
+ // "insert"
+ ucb::NameClashException aNameClashEx;
+ if ( aRequest >>= aNameClashEx )
+ {
+ return;
+ }
+ else
+ {
+ // "transfer"
+ ucb::UnsupportedCommandException aUnsupportedCommandEx;
+ if ( aRequest >>= aUnsupportedCommandEx )
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ // not filtered; let the original handler do the work.
+ m_xOrig->handle( Request );
+}
+
+
+
+
+class ActiveDataSink : public cppu::WeakImplHelper< io::XActiveDataSink >
+{
+ uno::Reference< io::XInputStream > m_xStream;
+
+public:
+ // XActiveDataSink methods.
+ virtual void SAL_CALL setInputStream(
+ const uno::Reference< io::XInputStream >& aStream ) override;
+ virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream() override;
+};
+
+
+// virtual
+void SAL_CALL ActiveDataSink::setInputStream(
+ const uno::Reference< io::XInputStream >& aStream )
+{
+ m_xStream = aStream;
+}
+
+
+// virtual
+uno::Reference< io::XInputStream > SAL_CALL ActiveDataSink::getInputStream()
+{
+ return m_xStream;
+}
+
+
+
+
+class CommandProcessorInfo :
+ public cppu::WeakImplHelper< ucb::XCommandInfo >
+{
+ uno::Sequence< ucb::CommandInfo > m_xInfo;
+
+public:
+ CommandProcessorInfo();
+
+ // XCommandInfo methods
+ virtual uno::Sequence< ucb::CommandInfo > SAL_CALL getCommands() override;
+ virtual ucb::CommandInfo SAL_CALL
+ getCommandInfoByName( const OUString& Name ) override;
+ virtual ucb::CommandInfo SAL_CALL
+ getCommandInfoByHandle( sal_Int32 Handle ) override;
+ virtual sal_Bool SAL_CALL hasCommandByName( const OUString& Name ) override;
+ virtual sal_Bool SAL_CALL hasCommandByHandle( sal_Int32 Handle ) override;
+};
+
+
+CommandProcessorInfo::CommandProcessorInfo()
+ : m_xInfo{
+ ucb::CommandInfo(
+ GETCOMMANDINFO_NAME, // Name
+ GETCOMMANDINFO_HANDLE, // Handle
+ cppu::UnoType<void>::get() ), // ArgType
+ ucb::CommandInfo(
+ GLOBALTRANSFER_NAME, // Name
+ GLOBALTRANSFER_HANDLE, // Handle
+ cppu::UnoType<ucb::GlobalTransferCommandArgument>::get() ), // ArgType
+ ucb::CommandInfo(
+ CHECKIN_NAME, // Name
+ CHECKIN_HANDLE, // Handle
+ cppu::UnoType<ucb::CheckinArgument>::get() ) } // ArgType
+{
+}
+
+
+// virtual
+uno::Sequence< ucb::CommandInfo > SAL_CALL
+CommandProcessorInfo::getCommands()
+{
+ return m_xInfo;
+}
+
+
+// virtual
+ucb::CommandInfo SAL_CALL
+CommandProcessorInfo::getCommandInfoByName( const OUString& Name )
+{
+ auto pInfo = std::find_if(std::cbegin(m_xInfo), std::cend(m_xInfo),
+ [&Name](const ucb::CommandInfo& rInfo) { return rInfo.Name == Name; });
+ if (pInfo != std::cend(m_xInfo))
+ return *pInfo;
+
+ throw ucb::UnsupportedCommandException();
+}
+
+
+// virtual
+ucb::CommandInfo SAL_CALL
+CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
+{
+ auto pInfo = std::find_if(std::cbegin(m_xInfo), std::cend(m_xInfo),
+ [&Handle](const ucb::CommandInfo& rInfo) { return rInfo.Handle == Handle; });
+ if (pInfo != std::cend(m_xInfo))
+ return *pInfo;
+
+ throw ucb::UnsupportedCommandException();
+}
+
+
+// virtual
+sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
+ const OUString& Name )
+{
+ return std::any_of(std::cbegin(m_xInfo), std::cend(m_xInfo),
+ [&Name](const ucb::CommandInfo& rInfo) { return rInfo.Name == Name; });
+}
+
+
+// virtual
+sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
+{
+ return std::any_of(std::cbegin(m_xInfo), std::cend(m_xInfo),
+ [&Handle](const ucb::CommandInfo& rInfo) { return rInfo.Handle == Handle; });
+}
+
+
+OUString createDesiredName(
+ const OUString & rSourceURL, const OUString & rNewTitle )
+{
+ OUString aName( rNewTitle );
+ if ( aName.isEmpty() )
+ {
+ // calculate name using source URL
+
+ // @@@ It's not guaranteed that slashes contained in the URL are
+ // actually path separators. This depends on the fact whether the
+ // URL is hierarchical. Only then the slashes are path separators.
+ // Therefore this algorithm is not guaranteed to work! But, ATM
+ // I don't know a better solution. It would have been better to
+ // have a member for the clashing name in
+ // UnsupportedNameClashException...
+
+ sal_Int32 nLastSlash = rSourceURL.lastIndexOf( '/' );
+ bool bTrailingSlash = false;
+ if ( nLastSlash == rSourceURL.getLength() - 1 )
+ {
+ nLastSlash = rSourceURL.lastIndexOf( '/', nLastSlash );
+ bTrailingSlash = true;
+ }
+
+ if ( nLastSlash != -1 )
+ {
+ if ( bTrailingSlash )
+ aName = rSourceURL.copy(
+ nLastSlash + 1,
+ rSourceURL.getLength() - nLastSlash - 2 );
+ else
+ aName = rSourceURL.copy( nLastSlash + 1 );
+ }
+ else
+ {
+ aName = rSourceURL;
+ }
+
+ // query, fragment present?
+ sal_Int32 nPos = aName.indexOf( '?' );
+ if ( nPos == -1 )
+ nPos = aName.indexOf( '#' );
+
+ if ( nPos != -1 )
+ aName = aName.copy( 0, nPos );
+ }
+ return aName;
+}
+
+OUString createDesiredName(
+ const ucb::GlobalTransferCommandArgument & rArg )
+{
+ return createDesiredName( rArg.SourceURL, rArg.NewTitle );
+}
+
+OUString createDesiredName(
+ const ucb::TransferInfo & rArg )
+{
+ return createDesiredName( rArg.SourceURL, rArg.NewTitle );
+}
+
+
+enum NameClashContinuation { NOT_HANDLED, ABORT, OVERWRITE, NEW_NAME, UNKNOWN };
+
+NameClashContinuation interactiveNameClashResolve(
+ const uno::Reference< ucb::XCommandEnvironment > & xEnv,
+ const OUString & rTargetURL,
+ const OUString & rClashingName,
+ /* [out] */ uno::Any & rException,
+ /* [out] */ OUString & rNewName )
+{
+ rtl::Reference< ucbhelper::SimpleNameClashResolveRequest > xRequest(
+ new ucbhelper::SimpleNameClashResolveRequest(
+ rTargetURL, // target folder URL
+ rClashingName
+ ) );
+
+ rException = xRequest->getRequest();
+ if ( xEnv.is() )
+ {
+ uno::Reference< task::XInteractionHandler > xIH
+ = xEnv->getInteractionHandler();
+ if ( xIH.is() )
+ {
+
+ xIH->handle( xRequest );
+
+ rtl::Reference< ucbhelper::InteractionContinuation >
+ xSelection( xRequest->getSelection() );
+
+ if ( xSelection.is() )
+ {
+ // Handler handled the request.
+ uno::Reference< task::XInteractionAbort > xAbort(
+ xSelection.get(), uno::UNO_QUERY );
+ if ( xAbort.is() )
+ {
+ // Abort.
+ return ABORT;
+ }
+ else
+ {
+ uno::Reference<
+ ucb::XInteractionReplaceExistingData >
+ xReplace(
+ xSelection.get(), uno::UNO_QUERY );
+ if ( xReplace.is() )
+ {
+ // Try again: Replace existing data.
+ return OVERWRITE;
+ }
+ else
+ {
+ uno::Reference<
+ ucb::XInteractionSupplyName >
+ xSupplyName(
+ xSelection.get(), uno::UNO_QUERY );
+ if ( xSupplyName.is() )
+ {
+ // Try again: Use new name.
+ rNewName = xRequest->getNewName();
+ return NEW_NAME;
+ }
+ else
+ {
+ OSL_FAIL( "Unknown interaction continuation!" );
+ return UNKNOWN;
+ }
+ }
+ }
+ }
+ }
+ }
+ return NOT_HANDLED;
+}
+
+/// @throws uno::RuntimeException
+bool setTitle(
+ const uno::Reference< ucb::XCommandProcessor > & xCommandProcessor,
+ const uno::Reference< ucb::XCommandEnvironment > & xEnv,
+ const OUString & rNewTitle )
+{
+ try
+ {
+ uno::Sequence< beans::PropertyValue > aPropValues{ { /* Name */ "Title",
+ /* Handle */ -1,
+ /* Value */ uno::Any(rNewTitle),
+ /* State */ {} } };
+
+ ucb::Command aSetPropsCommand(
+ "setPropertyValues",
+ -1,
+ uno::Any( aPropValues ) );
+
+ uno::Any aResult
+ = xCommandProcessor->execute( aSetPropsCommand, 0, xEnv );
+
+ uno::Sequence< uno::Any > aErrors;
+ aResult >>= aErrors;
+
+ OSL_ENSURE( aErrors.getLength() == 1,
+ "getPropertyValues return value invalid!" );
+
+ if ( aErrors[ 0 ].hasValue() )
+ {
+ // error occurred.
+ OSL_FAIL( "error setting Title property!" );
+ return false;
+ }
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+/// @throws uno::Exception
+uno::Reference< ucb::XContent > createNew(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XContent > & xTarget,
+ bool bSourceIsFolder,
+ bool bSourceIsDocument,
+ bool bSourceIsLink )
+{
+
+
+ // (1) Obtain creatable types from target.
+
+
+ // First, try it using "CreatabeleContentsInfo" property and
+ // "createNewContent" command -> the "new" way.
+
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessorT(
+ xTarget, uno::UNO_QUERY );
+ if ( !xCommandProcessorT.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Folder", uno::Any(rContext.aArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_CREATE,
+ aArgs,
+ rContext.xOrigEnv,
+ "Target is no XCommandProcessor!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ uno::Sequence< beans::Property > aPropsToObtain{ makeProperty("CreatableContentsInfo", -1) };
+
+ ucb::Command aGetPropsCommand(
+ "getPropertyValues",
+ -1,
+ uno::Any( aPropsToObtain ) );
+
+ uno::Reference< sdbc::XRow > xRow;
+ xCommandProcessorT->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
+
+ uno::Sequence< ucb::ContentInfo > aTypesInfo;
+ bool bGotTypesInfo = false;
+
+ if ( xRow.is() )
+ {
+ uno::Any aValue = xRow->getObject(
+ 1, uno::Reference< container::XNameAccess >() );
+ if ( aValue.hasValue() && ( aValue >>= aTypesInfo ) )
+ {
+ bGotTypesInfo = true;
+ }
+ }
+
+ uno::Reference< ucb::XContentCreator > xCreator;
+
+ if ( !bGotTypesInfo )
+ {
+ // Second, try it using XContentCreator interface -> the "old" way (not
+ // providing the chance to supply an XCommandEnvironment.
+
+ xCreator.set( xTarget, uno::UNO_QUERY );
+
+ if ( !xCreator.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Folder", uno::Any(rContext.aArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_CREATE,
+ aArgs,
+ rContext.xOrigEnv,
+ "Target is no XContentCreator!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ aTypesInfo = xCreator->queryCreatableContentsInfo();
+ }
+
+ if ( !aTypesInfo.hasElements() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Folder", uno::Any(rContext.aArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_CREATE,
+ aArgs,
+ rContext.xOrigEnv,
+ "No types creatable!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ // (2) Try to find a matching target type for the source object.
+
+ std::function<bool(const sal_Int32)> lCompare;
+
+ if ( rContext.aArg.Operation == ucb::TransferCommandOperation_LINK )
+ {
+ // Create link
+ lCompare = [](const sal_Int32 nAttribs) { return !!( nAttribs & ucb::ContentInfoAttribute::KIND_LINK ); };
+ }
+ else if ( ( rContext.aArg.Operation == ucb::TransferCommandOperation_COPY ) ||
+ ( rContext.aArg.Operation == ucb::TransferCommandOperation_MOVE ) )
+ {
+ // Copy / Move
+ // Is source a link? Create link in target folder then.
+ if ( bSourceIsLink )
+ {
+ lCompare = [](const sal_Int32 nAttribs) { return !!( nAttribs & ucb::ContentInfoAttribute::KIND_LINK ); };
+ }
+ else
+ {
+ // (not a and not b) or (a and b)
+ // not( a or b) or (a and b)
+ lCompare = [bSourceIsFolder, bSourceIsDocument](const sal_Int32 nAttribs) {
+ return ( bSourceIsFolder == !!( nAttribs & ucb::ContentInfoAttribute::KIND_FOLDER ) )
+ && ( bSourceIsDocument == !!( nAttribs & ucb::ContentInfoAttribute::KIND_DOCUMENT ) ) ;
+ };
+ }
+ }
+ else
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any( lang::IllegalArgumentException(
+ "Unknown transfer operation!",
+ rContext.xProcessor,
+ -1 ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+
+ uno::Reference< ucb::XContent > xNew;
+ auto pTypeInfo = std::find_if(std::cbegin(aTypesInfo), std::cend(aTypesInfo),
+ [&lCompare](const ucb::ContentInfo& rTypeInfo) { return lCompare(rTypeInfo.Attributes); });
+ if (pTypeInfo != std::cend(aTypesInfo))
+ {
+ // (3) Create a new, empty object of matched type.
+
+ if ( !xCreator.is() )
+ {
+ // First, try it using "CreatabeleContentsInfo" property and
+ // "createNewContent" command -> the "new" way.
+ ucb::Command aCreateNewCommand(
+ "createNewContent",
+ -1,
+ uno::Any( *pTypeInfo ) );
+
+ xCommandProcessorT->execute( aCreateNewCommand, 0, rContext.xEnv )
+ >>= xNew;
+ }
+ else
+ {
+ // Second, try it using XContentCreator interface -> the "old"
+ // way (not providing the chance to supply an XCommandEnvironment.
+
+ xNew = xCreator->createNewContent( *pTypeInfo );
+ }
+
+ if ( !xNew.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Folder", uno::Any(rContext.aArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_CREATE,
+ aArgs,
+ rContext.xOrigEnv,
+ "createNewContent failed!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+ }
+
+ return xNew;
+}
+
+/// @throws uno::Exception
+void transferProperties(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS,
+ const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorN )
+{
+ ucb::Command aGetPropertySetInfoCommand(
+ "getPropertySetInfo",
+ -1,
+ uno::Any() );
+
+ uno::Reference< beans::XPropertySetInfo > xInfo;
+ xCommandProcessorS->execute( aGetPropertySetInfoCommand, 0, rContext.xEnv )
+ >>= xInfo;
+
+ if ( !xInfo.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rContext.aArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Unable to get propertyset info from source object!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ uno::Sequence< beans::Property > aAllProps = xInfo->getProperties();
+
+ ucb::Command aGetPropsCommand1(
+ "getPropertyValues",
+ -1,
+ uno::Any( aAllProps ) );
+
+ uno::Reference< sdbc::XRow > xRow1;
+ xCommandProcessorS->execute(
+ aGetPropsCommand1, 0, rContext.xEnv ) >>= xRow1;
+
+ if ( !xRow1.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rContext.aArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Unable to get properties from source object!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ // Assemble data structure for setPropertyValues command.
+
+ // Note: Make room for additional Title and TargetURL too. -> + 2
+ uno::Sequence< beans::PropertyValue > aPropValues(
+ aAllProps.getLength() + 2 );
+ auto pPropValues = aPropValues.getArray();
+
+ bool bHasTitle = rContext.aArg.NewTitle.isEmpty();
+ bool bHasTargetURL = ( rContext.aArg.Operation
+ != ucb::TransferCommandOperation_LINK );
+
+ sal_Int32 nWritePos = 0;
+ for ( sal_Int32 m = 0; m < aAllProps.getLength(); ++m )
+ {
+ const beans::Property & rCurrProp = aAllProps[ m ];
+ beans::PropertyValue & rCurrValue = pPropValues[ nWritePos ];
+
+ uno::Any aValue;
+
+ if ( rCurrProp.Name == "Title" )
+ {
+ // Supply new title, if given.
+ if ( !bHasTitle )
+ {
+ bHasTitle = true;
+ aValue <<= rContext.aArg.NewTitle;
+ }
+ }
+ else if ( rCurrProp.Name == "TargetURL" )
+ {
+ // Supply source URL as link target for the new link to create.
+ if ( !bHasTargetURL )
+ {
+ bHasTargetURL = true;
+ aValue <<= rContext.aArg.SourceURL;
+ }
+ }
+
+ if ( !aValue.hasValue() )
+ {
+ try
+ {
+ aValue = xRow1->getObject(
+ m + 1, uno::Reference< container::XNameAccess >() );
+ }
+ catch ( sdbc::SQLException const & )
+ {
+ // Argh! But try to bring things to an end. Perhaps the
+ // mad property is not really important...
+ }
+ }
+
+ if ( aValue.hasValue() )
+ {
+ rCurrValue.Name = rCurrProp.Name;
+ rCurrValue.Handle = rCurrProp.Handle;
+ rCurrValue.Value = aValue;
+// rCurrValue.State =
+
+ nWritePos++;
+ }
+ }
+
+ // Title needed, but not set yet?
+ if ( !bHasTitle && !rContext.aArg.NewTitle.isEmpty() )
+ {
+ pPropValues[ nWritePos ].Name = "Title";
+ pPropValues[ nWritePos ].Handle = -1;
+ pPropValues[ nWritePos ].Value <<= rContext.aArg.NewTitle;
+
+ nWritePos++;
+ }
+
+ // TargetURL needed, but not set yet?
+ if ( !bHasTargetURL && ( rContext.aArg.Operation
+ == ucb::TransferCommandOperation_LINK ) )
+ {
+ pPropValues[ nWritePos ].Name = "TargetURL";
+ pPropValues[ nWritePos ].Handle = -1;
+ pPropValues[ nWritePos ].Value <<= rContext.aArg.SourceURL;
+
+ nWritePos++;
+ }
+
+ aPropValues.realloc( nWritePos );
+
+ // Set properties at new object.
+
+ ucb::Command aSetPropsCommand(
+ "setPropertyValues",
+ -1,
+ uno::Any( aPropValues ) );
+
+ xCommandProcessorN->execute( aSetPropsCommand, 0, rContext.xEnv );
+
+ // @@@ What to do with source props that are not supported by the
+ // new object? addProperty ???
+}
+
+/// @throws uno::Exception
+uno::Reference< io::XInputStream > getInputStream(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
+{
+ uno::Reference< io::XInputStream > xInputStream;
+
+
+ // (1) Try to get data as XInputStream via XActiveDataSink.
+
+
+ try
+ {
+ uno::Reference< io::XActiveDataSink > xSink = new ActiveDataSink;
+
+ ucb::OpenCommandArgument2 aArg;
+ aArg.Mode = ucb::OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xSink;
+ aArg.Properties = uno::Sequence< beans::Property >( 0 ); // unused
+
+ ucb::Command aOpenCommand(
+ "open",
+ -1,
+ uno::Any( aArg ) );
+
+ xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
+ xInputStream = xSink->getInputStream();
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ // will be handled below.
+ }
+
+ if ( !xInputStream.is() )
+ {
+
+
+ // (2) Try to get data via XOutputStream.
+
+
+ try
+ {
+ uno::Reference< io::XOutputStream > xOutputStream( io::Pipe::create(rContext.m_xContext), uno::UNO_QUERY_THROW );
+
+ ucb::OpenCommandArgument2 aArg;
+ aArg.Mode = ucb::OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xOutputStream;
+ aArg.Properties = uno::Sequence< beans::Property >( 0 );
+
+ ucb::Command aOpenCommand(
+ "open",
+ -1,
+ uno::Any( aArg ) );
+
+ xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv );
+
+ xInputStream.set( xOutputStream, uno::UNO_QUERY );
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ OSL_FAIL( "unable to get input stream from document!" );
+ }
+ }
+
+ return xInputStream;
+}
+
+/// @throws uno::Exception
+uno::Reference< sdbc::XResultSet > getResultSet(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XCommandProcessor > & xCommandProcessorS )
+{
+ uno::Reference< sdbc::XResultSet > xResultSet;
+
+ uno::Sequence< beans::Property > aProps{ makeProperty("IsFolder", -1 /* unknown */),
+ makeProperty("IsDocument", -1 /* unknown */),
+ makeProperty("TargetURL", -1 /* unknown */) };
+
+ ucb::OpenCommandArgument2 aArg;
+ aArg.Mode = ucb::OpenMode::ALL;
+ aArg.Priority = 0; // unused
+ aArg.Sink = nullptr;
+ aArg.Properties = aProps;
+
+ ucb::Command aOpenCommand( "open",
+ -1,
+ uno::Any( aArg ) );
+ try
+ {
+ uno::Reference< ucb::XDynamicResultSet > xSet;
+ xCommandProcessorS->execute( aOpenCommand, 0, rContext.xEnv ) >>= xSet;
+
+ if ( xSet.is() )
+ xResultSet = xSet->getStaticResultSet();
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ OSL_FAIL( "unable to get result set from folder!" );
+ }
+
+ return xResultSet;
+}
+
+/// @throws uno::Exception
+void handleNameClashRename(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XContent > & xNew,
+ const uno::Reference<
+ ucb::XCommandProcessor > & xCommandProcessorN,
+ const uno::Reference<
+ ucb::XCommandProcessor > & xCommandProcessorS,
+ /* [inout] */ uno::Reference< io::XInputStream > & xInputStream )
+{
+ sal_Int32 nTry = 0;
+
+ // Obtain old title.
+ uno::Sequence< beans::Property > aProps{ makeProperty("Title", -1) };
+
+ ucb::Command aGetPropsCommand(
+ "getPropertyValues",
+ -1,
+ uno::Any( aProps ) );
+
+ uno::Reference< sdbc::XRow > xRow;
+ xCommandProcessorN->execute( aGetPropsCommand, 0, rContext.xEnv ) >>= xRow;
+
+ if ( !xRow.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(xNew->getIdentifier()->getContentIdentifier())}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Unable to get properties from new object!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ OUString aOldTitle = xRow->getString( 1 );
+ if ( aOldTitle.isEmpty() )
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any( beans::UnknownPropertyException(
+ "Unable to get property 'Title' from new object!",
+ rContext.xProcessor ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+
+ // Some pseudo-intelligence for not destroying file extensions.
+ OUString aOldTitlePre;
+ OUString aOldTitlePost;
+ sal_Int32 nPos = aOldTitle.lastIndexOf( '.' );
+ if ( nPos != -1 )
+ {
+ aOldTitlePre = aOldTitle.copy( 0, nPos );
+ aOldTitlePost = aOldTitle.copy( nPos );
+ }
+ else
+ aOldTitlePre = aOldTitle;
+
+ if ( nPos > 0 )
+ aOldTitlePre += "_";
+
+ bool bContinue = true;
+ do
+ {
+ nTry++;
+
+ OUString aNewTitle = aOldTitlePre + OUString::number( nTry ) +
+ aOldTitlePost;
+
+ // Set new title
+ setTitle( xCommandProcessorN, rContext.xEnv, aNewTitle );
+
+ // Retry inserting the content.
+ try
+ {
+ // Previous try may have read from stream. Seek to begin (if
+ // optional interface XSeekable is supported) or get a new stream.
+ if ( xInputStream.is() )
+ {
+ uno::Reference< io::XSeekable > xSeekable(
+ xInputStream, uno::UNO_QUERY );
+ if ( xSeekable.is() )
+ {
+ try
+ {
+ xSeekable->seek( 0 );
+ }
+ catch ( lang::IllegalArgumentException const & )
+ {
+ xInputStream.clear();
+ }
+ catch ( io::IOException const & )
+ {
+ xInputStream.clear();
+ }
+ }
+ else
+ xInputStream.clear();
+
+ if ( !xInputStream.is() )
+ {
+ xInputStream
+ = getInputStream( rContext, xCommandProcessorS );
+ if ( !xInputStream.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(xNew->getIdentifier()->getContentIdentifier())}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Got no data stream from source!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+ }
+ }
+
+ ucb::InsertCommandArgument2 aArg;
+ aArg.Data = xInputStream;
+ aArg.ReplaceExisting = false;
+
+ ucb::Command aInsertCommand(
+ "insert",
+ -1,
+ uno::Any( aArg ) );
+
+ xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
+
+ // Success!
+ bContinue = false;
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ }
+ }
+ while ( bContinue && ( nTry < 50 ) );
+
+ if ( nTry == 50 )
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any(
+ ucb::UnsupportedNameClashException(
+ "Unable to resolve name clash!",
+ rContext.xProcessor,
+ ucb::NameClash::RENAME ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+}
+
+/// @throws uno::Exception
+void globalTransfer_(
+ const TransferCommandContext & rContext,
+ const uno::Reference< ucb::XContent > & xSource,
+ const uno::Reference< ucb::XContent > & xTarget,
+ const uno::Reference< sdbc::XRow > & xSourceProps )
+{
+ // IsFolder: property is required.
+ bool bSourceIsFolder = xSourceProps->getBoolean( 1 );
+ if ( !bSourceIsFolder && xSourceProps->wasNull() )
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any( beans::UnknownPropertyException(
+ "Unable to get property 'IsFolder' from source object!",
+ rContext.xProcessor ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+
+ // IsDocument: property is required.
+ bool bSourceIsDocument = xSourceProps->getBoolean( 2 );
+ if ( !bSourceIsDocument && xSourceProps->wasNull() )
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any( beans::UnknownPropertyException(
+ "Unable to get property 'IsDocument' from source object!",
+ rContext.xProcessor ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+
+ // TargetURL: property is optional.
+ bool bSourceIsLink = !xSourceProps->getString( 3 ).isEmpty();
+
+
+ // (1) Try to find a matching target type for the source object and
+ // create a new, empty object of that type.
+
+
+ uno::Reference< ucb::XContent > xNew = createNew( rContext,
+ xTarget,
+ bSourceIsFolder,
+ bSourceIsDocument,
+ bSourceIsLink );
+ if ( !xNew.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Folder", uno::Any(rContext.aArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_CREATE,
+ aArgs,
+ rContext.xOrigEnv,
+ "No matching content type at target!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+
+ // (2) Transfer property values from source to new object.
+
+
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessorN(
+ xNew, uno::UNO_QUERY );
+ if ( !xCommandProcessorN.is() )
+ {
+ uno::Any aProps(beans::PropertyValue(
+ "Uri",
+ -1,
+ uno::Any(
+ xNew->getIdentifier()->
+ getContentIdentifier()),
+ beans::PropertyState_DIRECT_VALUE));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_WRITE,
+ uno::Sequence< uno::Any >(&aProps, 1),
+ rContext.xOrigEnv,
+ "New content is not a XCommandProcessor!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ // Obtain all properties from source.
+
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessorS(
+ xSource, uno::UNO_QUERY );
+ if ( !xCommandProcessorS.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rContext.aArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Source content is not a XCommandProcessor!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ transferProperties( rContext, xCommandProcessorS, xCommandProcessorN );
+
+
+ // (3) Try to obtain a data stream from source.
+
+
+ uno::Reference< io::XInputStream > xInputStream;
+
+ if ( bSourceIsDocument && ( rContext.aArg.Operation
+ != ucb::TransferCommandOperation_LINK ) )
+ xInputStream = getInputStream( rContext, xCommandProcessorS );
+
+
+ // (4) Try to obtain a resultset (children) from source.
+
+
+ uno::Reference< sdbc::XResultSet > xResultSet;
+
+ if ( bSourceIsFolder && ( rContext.aArg.Operation
+ != ucb::TransferCommandOperation_LINK ) )
+ xResultSet = getResultSet( rContext, xCommandProcessorS );
+
+
+ // (5) Insert (store) new content.
+
+
+ ucb::InsertCommandArgument2 aArg;
+ aArg.Data = xInputStream;
+ aArg.MimeType = rContext.aArg.MimeType;
+ aArg.DocumentId = rContext.aArg.DocumentId;
+
+ switch ( rContext.aArg.NameClash )
+ {
+ case ucb::NameClash::OVERWRITE:
+ aArg.ReplaceExisting = true;
+ break;
+
+ case ucb::NameClash::ERROR:
+ case ucb::NameClash::RENAME:
+ case ucb::NameClash::KEEP: // deprecated
+ case ucb::NameClash::ASK:
+ aArg.ReplaceExisting = false;
+ break;
+
+ default:
+ aArg.ReplaceExisting = false;
+ OSL_FAIL( "Unknown nameclash directive!" );
+ break;
+ }
+
+ OUString aDesiredName = createDesiredName( rContext.aArg );
+
+ bool bRetry;
+ do
+ {
+ bRetry = false;
+
+ try
+ {
+ ucb::Command aInsertCommand(
+ "insert",
+ -1,
+ uno::Any( aArg ) );
+
+ xCommandProcessorN->execute( aInsertCommand, 0, rContext.xEnv );
+ }
+ catch ( ucb::UnsupportedNameClashException const & exc )
+ {
+ OSL_ENSURE( !aArg.ReplaceExisting,
+ "BUG: UnsupportedNameClashException not allowed here!" );
+
+ if (exc.NameClash != ucb::NameClash::ERROR) {
+ OSL_FAIL( "BUG: NameClash::ERROR expected!" );
+ }
+
+ // No chance to solve name clashes, because I'm not able to detect
+ // whether there is one.
+ throw ucb::UnsupportedNameClashException(
+ "Unable to resolve name clashes, no chance to detect "
+ "that there is one!",
+ rContext.xProcessor,
+ rContext.aArg.NameClash );
+ }
+ catch ( ucb::NameClashException const & )
+ {
+ // The 'insert' command throws a NameClashException if the parameter
+ // ReplaceExisting of the command's argument was set to false and
+ // there exists a resource with a clashing name in the target folder
+ // of the operation.
+
+ // 'insert' command has no direct support for name clashes other
+ // than ERROR ( ReplaceExisting == false ) and OVERWRITE
+ // ( ReplaceExisting == true ). So we have to implement the
+ // other name clash handling directives on top of the content.
+
+ // @@@ 'insert' command should be extended that it accepts a
+ // name clash handling directive, exactly like 'transfer' command.
+
+ switch ( rContext.aArg.NameClash )
+ {
+ case ucb::NameClash::OVERWRITE:
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any(
+ ucb::UnsupportedNameClashException(
+ "BUG: insert + replace == true MUST NOT "
+ "throw NameClashException.",
+ rContext.xProcessor,
+ rContext.aArg.NameClash ) ),
+ rContext.xOrigEnv );
+ [[fallthrough]]; // Unreachable
+ }
+
+ case ucb::NameClash::ERROR:
+ throw;
+
+ case ucb::NameClash::RENAME:
+ {
+ // "invent" a new valid title.
+ handleNameClashRename( rContext,
+ xNew,
+ xCommandProcessorN,
+ xCommandProcessorS,
+ xInputStream );
+ break;
+ }
+
+ case ucb::NameClash::ASK:
+ {
+ uno::Any aExc;
+ OUString aNewTitle;
+ NameClashContinuation eCont
+ = interactiveNameClashResolve(
+ rContext.xOrigEnv, // always use original environment!
+ rContext.aArg.TargetURL, // target folder URL
+ aDesiredName,
+ aExc,
+ aNewTitle );
+
+ switch ( eCont )
+ {
+ case NOT_HANDLED:
+ // Not handled.
+ cppu::throwException( aExc );
+ [[fallthrough]]; // break;
+
+ case UNKNOWN:
+ // Handled, but not clear, how...
+ // fall through intended.
+
+ case ABORT:
+ throw ucb::CommandFailedException(
+ "abort requested via interaction "
+ "handler",
+ uno::Reference< uno::XInterface >(),
+ aExc );
+ // break;
+
+ case OVERWRITE:
+ OSL_ENSURE( !aArg.ReplaceExisting,
+ "Hu? ReplaceExisting already true?"
+ );
+ aArg.ReplaceExisting = true;
+ bRetry = true;
+ break;
+
+ case NEW_NAME:
+ {
+ // set new name -> set "Title" property...
+ if ( setTitle( xCommandProcessorN,
+ rContext.xEnv,
+ aNewTitle ) )
+ {
+ // remember suggested title...
+ aDesiredName = aNewTitle;
+
+ // ... and try again.
+ bRetry = true;
+ }
+ else
+ {
+ // error setting title. Abort.
+ throw ucb::CommandFailedException(
+ "error setting Title property!",
+ uno::Reference< uno::XInterface >(),
+ aExc );
+ }
+ break;
+ }
+ }
+
+ OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
+ }
+ break;
+
+ case ucb::NameClash::KEEP: // deprecated
+ default:
+ {
+ ucbhelper::cancelCommandExecution(
+ uno::Any(
+ ucb::UnsupportedNameClashException(
+ "default action, don't know how to "
+ "handle name clash",
+ rContext.xProcessor,
+ rContext.aArg.NameClash ) ),
+ rContext.xOrigEnv );
+ // Unreachable
+ }
+ }
+ }
+ }
+ while ( bRetry );
+
+
+ // (6) Process children of source.
+
+
+ if ( xResultSet.is() )
+ {
+ try
+ {
+ // Iterate over children...
+
+ uno::Reference< sdbc::XRow > xChildRow(
+ xResultSet, uno::UNO_QUERY );
+
+ if ( !xChildRow.is() )
+ {
+ uno::Any aProps(
+ beans::PropertyValue(
+ "Uri",
+ -1,
+ uno::Any(rContext.aArg.SourceURL),
+ beans::PropertyState_DIRECT_VALUE));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ uno::Sequence< uno::Any >(&aProps, 1),
+ rContext.xOrigEnv,
+ "Unable to get properties from children of source!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ uno::Reference< ucb::XContentAccess > xChildAccess(
+ xResultSet, uno::UNO_QUERY );
+
+ if ( !xChildAccess.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rContext.aArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ rContext.xOrigEnv,
+ "Unable to get children of source!",
+ rContext.xProcessor );
+ // Unreachable
+ }
+
+ if ( xResultSet->first() )
+ {
+ ucb::GlobalTransferCommandArgument2 aTransArg(
+ rContext.aArg.Operation,
+ OUString(), // SourceURL; filled later
+ xNew->getIdentifier()
+ ->getContentIdentifier(), // TargetURL
+ OUString(), // NewTitle;
+ rContext.aArg.NameClash,
+ rContext.aArg.MimeType,
+ rContext.aArg.DocumentId);
+
+ TransferCommandContext aSubCtx(
+ rContext.m_xContext,
+ rContext.xProcessor,
+ rContext.xEnv,
+ rContext.xOrigEnv,
+ aTransArg );
+ do
+ {
+ uno::Reference< ucb::XContent > xChild
+ = xChildAccess->queryContent();
+ if ( xChild.is() )
+ {
+ // Recursion!
+
+ aSubCtx.aArg.SourceURL
+ = xChild->getIdentifier()->getContentIdentifier();
+
+ globalTransfer_( aSubCtx,
+ xChild,
+ xNew,
+ xChildRow );
+ }
+ }
+ while ( xResultSet->next() );
+ }
+ }
+ catch ( sdbc::SQLException const & )
+ {
+ }
+ }
+
+ try {
+ uno::Reference< ucb::XCommandProcessor > xcp(
+ xTarget, uno::UNO_QUERY );
+
+ uno::Any aAny;
+ uno::Reference< ucb::XCommandInfo > xci;
+ if(xcp.is())
+ aAny =
+ xcp->execute(
+ ucb::Command(
+ "getCommandInfo",
+ -1,
+ uno::Any()),
+ 0,
+ rContext.xEnv );
+
+ static const OUStringLiteral cmdName(u"flush");
+ if((aAny >>= xci) && xci->hasCommandByName(cmdName))
+ xcp->execute(
+ ucb::Command(
+ cmdName,
+ -1,
+ uno::Any()) ,
+ 0,
+ rContext.xEnv );
+ }
+ catch( uno::Exception const & )
+ {
+ }
+}
+
+} /* namespace */
+
+
+// UniversalContentBroker implementation ( XCommandProcessor commands ).
+
+
+uno::Reference< ucb::XCommandInfo >
+UniversalContentBroker::getCommandInfo()
+{
+ return uno::Reference< ucb::XCommandInfo >( new CommandProcessorInfo() );
+}
+
+
+void UniversalContentBroker::globalTransfer(
+ const ucb::GlobalTransferCommandArgument2 & rArg,
+ const uno::Reference< ucb::XCommandEnvironment > & xEnv )
+{
+ // Use own command environment with own interaction handler intercepting
+ // some interaction requests that shall not be handled by the user-supplied
+ // interaction handler.
+ uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
+ if (xEnv.is())
+ {
+ xLocalEnv.set( ucb::CommandEnvironment::create(
+ m_xContext,
+ new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
+ xEnv->getProgressHandler() ) );
+ }
+
+
+ // (1) Try to transfer the content using 'transfer' command.
+
+
+ uno::Reference< ucb::XContent > xTarget;
+ uno::Reference< ucb::XContentIdentifier > xId
+ = createContentIdentifier( rArg.TargetURL );
+ if ( xId.is() )
+ {
+ try
+ {
+ xTarget = queryContent( xId );
+ }
+ catch ( ucb::IllegalIdentifierException const & )
+ {
+ }
+ }
+
+ if ( !xTarget.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Can't instantiate target object!",
+ this );
+ // Unreachable
+ }
+
+ if ( ( rArg.Operation == ucb::TransferCommandOperation_COPY ) ||
+ ( rArg.Operation == ucb::TransferCommandOperation_MOVE ) )
+ {
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
+ xTarget, uno::UNO_QUERY );
+ if ( !xCommandProcessor.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Target content is not a XCommandProcessor!",
+ this );
+ // Unreachable
+ }
+
+ ucb::TransferInfo2 aTransferArg(
+ ( rArg.Operation
+ == ucb::TransferCommandOperation_MOVE ), // MoveData
+ rArg.SourceURL,
+ rArg.NewTitle,
+ rArg.NameClash,
+ rArg.MimeType );
+
+ bool bRetry;
+ do
+ {
+ bRetry = false;
+
+ try
+ {
+ ucb::Command aCommand(
+ "transfer", // Name
+ -1, // Handle
+ uno::Any( aTransferArg ) ); // Argument
+
+ xCommandProcessor->execute( aCommand, 0, xLocalEnv );
+
+ // Command succeeded. We're done.
+ return;
+ }
+ catch ( ucb::InteractiveBadTransferURLException const & )
+ {
+ // Source URL is not supported by target. Try to transfer
+ // the content "manually".
+ }
+ catch ( ucb::UnsupportedCommandException const & )
+ {
+ // 'transfer' command is not supported by commandprocessor.
+ // Try to transfer manually.
+ }
+ catch ( ucb::UnsupportedNameClashException const & exc )
+ {
+ OSL_ENSURE( aTransferArg.NameClash == exc.NameClash,
+ "nameclash mismatch!" );
+ if ( exc.NameClash == ucb::NameClash::ASK )
+ {
+ // Try to detect a name clash by invoking "transfer" with
+ // NameClash::ERROR.
+ try
+ {
+ ucb::TransferInfo2 aTransferArg1(
+ aTransferArg.MoveData,
+ aTransferArg.SourceURL,
+ aTransferArg.NewTitle,
+ ucb::NameClash::ERROR,
+ aTransferArg.MimeType );
+
+ ucb::Command aCommand1(
+ "transfer",
+ -1,
+ uno::Any( aTransferArg1 ) );
+
+ xCommandProcessor->execute( aCommand1, 0, xLocalEnv );
+
+ // Command succeeded. We're done.
+ return;
+ }
+ catch ( ucb::UnsupportedNameClashException const & )
+ {
+ // No chance to solve name clashes, because I'm not
+ // able to detect whether there is one.
+ throw exc; // Not just 'throw;'!
+ }
+ catch ( ucb::NameClashException const & )
+ {
+ // There's a clash. Use interaction handler to solve it.
+
+ uno::Any aExc;
+ OUString aNewTitle;
+ NameClashContinuation eCont
+ = interactiveNameClashResolve(
+ xEnv, // always use original environment!
+ rArg.TargetURL, // target folder URL
+ createDesiredName(
+ aTransferArg ), // clashing name
+ aExc,
+ aNewTitle );
+
+ switch ( eCont )
+ {
+ case NOT_HANDLED:
+ // Not handled.
+ cppu::throwException( aExc );
+ [[fallthrough]]; // break;
+
+ case UNKNOWN:
+ // Handled, but not clear, how...
+ // fall through intended.
+
+ case ABORT:
+ throw ucb::CommandFailedException(
+ "abort requested via interaction "
+ "handler",
+ uno::Reference< uno::XInterface >(),
+ aExc );
+// break;
+
+ case OVERWRITE:
+ aTransferArg.NameClash
+ = ucb::NameClash::OVERWRITE;
+ bRetry = true;
+ break;
+
+ case NEW_NAME:
+ aTransferArg.NewTitle = aNewTitle;
+ bRetry = true;
+ break;
+ }
+
+ OSL_ENSURE( bRetry, "bRetry must be true here!!!" );
+ }
+ }
+ else
+ {
+ throw;
+ }
+ }
+ }
+ while ( bRetry );
+ }
+
+
+ // (2) Try to transfer the content "manually".
+
+
+ uno::Reference< ucb::XContent > xSource;
+ try
+ {
+ uno::Reference< ucb::XContentIdentifier > xId2
+ = createContentIdentifier( rArg.SourceURL );
+ if ( xId2.is() )
+ xSource = queryContent( xId2 );
+ }
+ catch ( ucb::IllegalIdentifierException const & )
+ {
+ // Error handling via "if ( !xSource.is() )" below.
+ }
+
+ if ( !xSource.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Can't instantiate source object!",
+ this );
+ // Unreachable
+ }
+
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
+ xSource, uno::UNO_QUERY );
+ if ( !xCommandProcessor.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Source content is not a XCommandProcessor!",
+ this );
+ // Unreachable
+ }
+
+ // Obtain interesting property values from source...
+
+ uno::Sequence< beans::Property > aProps{ makeProperty("IsFolder", -1 /* unknown */),
+ makeProperty("IsDocument", -1 /* unknown */),
+ makeProperty("TargetURL", -1 /* unknown */),
+ makeProperty("BaseURI", -1 /* unknown */) };
+
+ ucb::Command aGetPropsCommand(
+ "getPropertyValues",
+ -1,
+ uno::Any( aProps ) );
+
+ uno::Reference< sdbc::XRow > xRow;
+ xCommandProcessor->execute( aGetPropsCommand, 0, xLocalEnv ) >>= xRow;
+
+ if ( !xRow.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.SourceURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Unable to get properties from source object!",
+ this );
+ // Unreachable
+ }
+
+ TransferCommandContext aTransferCtx(
+ m_xContext, this, xLocalEnv, xEnv, rArg );
+
+ if ( rArg.NewTitle.isEmpty() )
+ {
+ // BaseURI: property is optional.
+ OUString aBaseURI( xRow->getString( 4 ) );
+ if ( !aBaseURI.isEmpty() )
+ {
+ aTransferCtx.aArg.NewTitle
+ = createDesiredName( aBaseURI, OUString() );
+ }
+ }
+
+ // Do it!
+ globalTransfer_( aTransferCtx, xSource, xTarget, xRow );
+
+
+ // (3) Delete source, if operation is MOVE.
+
+
+ if ( rArg.Operation != ucb::TransferCommandOperation_MOVE )
+ return;
+
+ try
+ {
+ ucb::Command aCommand(
+ "delete", // Name
+ -1, // Handle
+ uno::Any( true ) ); // Argument
+
+ xCommandProcessor->execute( aCommand, 0, xLocalEnv );
+ }
+ catch ( uno::Exception const & )
+ {
+ OSL_FAIL( "Cannot delete source object!" );
+ throw;
+ }
+}
+
+uno::Any UniversalContentBroker::checkIn( const ucb::CheckinArgument& rArg,
+ const uno::Reference< ucb::XCommandEnvironment >& xEnv )
+{
+ uno::Any aRet;
+ // Use own command environment with own interaction handler intercepting
+ // some interaction requests that shall not be handled by the user-supplied
+ // interaction handler.
+ uno::Reference< ucb::XCommandEnvironment > xLocalEnv;
+ if (xEnv.is())
+ {
+ xLocalEnv.set( ucb::CommandEnvironment::create(
+ m_xContext,
+ new InteractionHandlerProxy( xEnv->getInteractionHandler() ),
+ xEnv->getProgressHandler() ) );
+ }
+
+ uno::Reference< ucb::XContent > xTarget;
+ uno::Reference< ucb::XContentIdentifier > xId
+ = createContentIdentifier( rArg.TargetURL );
+ if ( xId.is() )
+ {
+ try
+ {
+ xTarget = queryContent( xId );
+ }
+ catch ( ucb::IllegalIdentifierException const & )
+ {
+ }
+ }
+
+ if ( !xTarget.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Can't instantiate target object!",
+ this );
+ // Unreachable
+ }
+
+ uno::Reference< ucb::XCommandProcessor > xCommandProcessor(
+ xTarget, uno::UNO_QUERY );
+ if ( !xCommandProcessor.is() )
+ {
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"Uri", uno::Any(rArg.TargetURL)}
+ }));
+ ucbhelper::cancelCommandExecution(
+ ucb::IOErrorCode_CANT_READ,
+ aArgs,
+ xEnv,
+ "Target content is not a XCommandProcessor!",
+ this );
+ // Unreachable
+ }
+
+ try
+ {
+ ucb::Command aCommand(
+ "checkin", -1,
+ uno::Any( rArg ) );
+
+ aRet = xCommandProcessor->execute( aCommand, 0, xLocalEnv );
+ }
+ catch ( ucb::UnsupportedCommandException const & )
+ {
+ // 'checkin' command is not supported by commandprocessor:
+ // ignore.
+ }
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucbcmds.hxx b/ucb/source/core/ucbcmds.hxx
new file mode 100644
index 000000000..063c79e5f
--- /dev/null
+++ b/ucb/source/core/ucbcmds.hxx
@@ -0,0 +1,36 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+// Definitions for the commands supported by the UCB.
+
+
+inline constexpr OUStringLiteral GETCOMMANDINFO_NAME = u"getCommandInfo";
+#define GETCOMMANDINFO_HANDLE 1024
+
+inline constexpr OUStringLiteral GLOBALTRANSFER_NAME = u"globalTransfer";
+#define GLOBALTRANSFER_HANDLE 1025
+
+inline constexpr OUStringLiteral CHECKIN_NAME = u"checkin";
+#define CHECKIN_HANDLE 1026
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucbprops.cxx b/ucb/source/core/ucbprops.cxx
new file mode 100644
index 000000000..808923ada
--- /dev/null
+++ b/ucb/source/core/ucbprops.cxx
@@ -0,0 +1,268 @@
+/* -*- 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 <sal/config.h>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/ucb/CrossReference.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/ucb/DocumentHeaderField.hpp>
+#include <com/sun/star/ucb/DocumentStoreMode.hpp>
+#include <com/sun/star/ucb/Priority.hpp>
+#include <com/sun/star/ucb/RecipientInfo.hpp>
+#include <com/sun/star/ucb/RuleSet.hpp>
+#include <com/sun/star/ucb/SendInfo.hpp>
+#include <com/sun/star/ucb/SendMediaTypes.hpp>
+#include <com/sun/star/ucb/SynchronizePolicy.hpp>
+#include <com/sun/star/ucb/VerificationMode.hpp>
+#include <com/sun/star/ucb/XDataContainer.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+
+#include "ucbprops.hxx"
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::uno;
+
+#define ATTR_DEFAULT ( PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID | PropertyAttribute::MAYBEDEFAULT )
+
+UcbPropertiesManager::UcbPropertiesManager()
+: m_pProps({
+ { "Account", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "AutoUpdateInterval", -1, cppu::UnoType<sal_Int32>::get(), ATTR_DEFAULT },
+ { "ConfirmEmpty", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "ConnectionLimit", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "ConnectionMode", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "ContentCountLimit", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "ContentType", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Cookie", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "CrossReferences", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::CrossReference>>::get(),
+ ATTR_DEFAULT },
+ { "DateCreated", -1, cppu::UnoType<css::util::DateTime>::get(),
+ ATTR_DEFAULT },
+ { "DateModified", -1, cppu::UnoType<css::util::DateTime>::get(),
+ ATTR_DEFAULT },
+ { "DeleteOnServer", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "DocumentBody", -1, cppu::UnoType<css::uno::Sequence<sal_Int8>>::get(),
+ ATTR_DEFAULT },
+ { "DocumentCount", -1, cppu::UnoType<sal_Int32>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "DocumentCountMarked", -1, cppu::UnoType<sal_Int32>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "DocumentHeader", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::DocumentHeaderField>>::get(),
+ ATTR_DEFAULT },
+ { "DocumentStoreMode", -1,
+ cppu::UnoType<css::ucb::DocumentStoreMode>::get(), ATTR_DEFAULT },
+ { "DocumentViewMode", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "FTPAccount", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Flags", -1, cppu::UnoType<sal_Int32>::get(), ATTR_DEFAULT },
+ { "FolderCount", -1, cppu::UnoType<sal_Int32>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "FolderViewMode", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "FreeSpace", -1, cppu::UnoType<sal_Int64>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "HasDocuments", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "HasFolders", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "IsAutoDelete", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsAutoUpdate", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsDocument", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "IsFolder", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "IsKeepExpired", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsLimitedContentCount", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsMarked", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsRead", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsReadOnly", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsSubscribed", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "IsTimeLimitedStore", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "Keywords", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "LocalBase", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageBCC", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageBody", -1, cppu::UnoType<css::ucb::XDataContainer>::get(),
+ ATTR_DEFAULT },
+ { "MessageCC", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageFrom", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageId", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageInReplyTo", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageReplyTo", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "MessageTo", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "NewsGroups", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "NoCacheList", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Origin", -1, cppu::UnoType<OUString>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "OutgoingMessageRecipients", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::RecipientInfo>>::get(),
+ ATTR_DEFAULT },
+ { "OutgoingMessageState", -1,
+ cppu::UnoType<css::ucb::OutgoingMessageState>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "OutgoingMessageViewMode", -1, cppu::UnoType<sal_Int16>::get(),
+ ATTR_DEFAULT },
+ { "Password", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Priority", -1, cppu::UnoType<css::ucb::Priority>::get(), ATTR_DEFAULT },
+ { "References", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Referer", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "Rules", -1, cppu::UnoType<css::ucb::RuleSet>::get(), ATTR_DEFAULT },
+ { "SearchCriteria", -1, cppu::UnoType<css::ucb::RuleSet>::get(),
+ ATTR_DEFAULT },
+ { "SearchIndirections", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "SearchLocations", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "SearchRecursive", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "SeenCount", -1, cppu::UnoType<sal_Int32>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "SendCopyTarget", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendFormats", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendMediaTypes>>::get(),
+ ATTR_DEFAULT },
+ { "SendFroms", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendPasswords", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendProtocolPrivate", -1, cppu::UnoType<sal_Int16>::get(),
+ ATTR_DEFAULT },
+ { "SendProtocolPublic", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "SendReplyTos", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendServerNames", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendUserNames", -1,
+ cppu::UnoType<css::uno::Sequence<css::ucb::SendInfo>>::get(),
+ ATTR_DEFAULT },
+ { "SendVIMPostOfficePath", -1, cppu::UnoType<OUString>::get(),
+ ATTR_DEFAULT },
+ { "ServerBase", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "ServerName", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "ServerPort", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "Size", -1, cppu::UnoType<sal_Int64>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "SizeLimit", -1, cppu::UnoType<sal_Int64>::get(), ATTR_DEFAULT },
+ { "SubscribedCount", -1, cppu::UnoType<sal_Int32>::get(),
+ ATTR_DEFAULT | PropertyAttribute::READONLY },
+ { "SynchronizePolicy", -1,
+ cppu::UnoType<css::ucb::SynchronizePolicy>::get(), ATTR_DEFAULT },
+ { "TargetFrames", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "TargetURL", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "TimeLimitStore", -1, cppu::UnoType<sal_Int16>::get(), ATTR_DEFAULT },
+ { "Title", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "UpdateOnOpen", -1, cppu::UnoType<bool>::get(), ATTR_DEFAULT },
+ { "UseOutBoxPrivateProtocolSettings", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT },
+ { "UseOutBoxPublicProtocolSettings", -1, cppu::UnoType<bool>::get(),
+ ATTR_DEFAULT },
+ { "UserName", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "UserSortCriterium", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "VIMPostOfficePath", -1, cppu::UnoType<OUString>::get(), ATTR_DEFAULT },
+ { "VerificationMode", -1, cppu::UnoType<css::ucb::VerificationMode>::get(),
+ ATTR_DEFAULT }})
+{
+}
+
+
+// virtual
+UcbPropertiesManager::~UcbPropertiesManager()
+{
+}
+
+// XServiceInfo methods.
+
+OUString SAL_CALL UcbPropertiesManager::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UcbPropertiesManager";
+}
+sal_Bool SAL_CALL UcbPropertiesManager::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+css::uno::Sequence< OUString > SAL_CALL UcbPropertiesManager::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.PropertiesManager" };
+}
+
+
+
+// Service factory implementation.
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UcbPropertiesManager_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UcbPropertiesManager());
+}
+
+// XPropertySetInfo methods.
+
+
+// virtual
+Sequence< Property > SAL_CALL UcbPropertiesManager::getProperties()
+{
+ return m_pProps;
+}
+
+
+// virtual
+Property SAL_CALL UcbPropertiesManager::getPropertyByName( const OUString& aName )
+{
+ Property aProp;
+ if ( queryProperty( aName, aProp ) )
+ return aProp;
+
+ throw UnknownPropertyException(aName);
+}
+
+
+// virtual
+sal_Bool SAL_CALL UcbPropertiesManager::hasPropertyByName( const OUString& Name )
+{
+ Property aProp;
+ return queryProperty( Name, aProp );
+}
+
+
+// Non-Interface methods.
+
+
+bool UcbPropertiesManager::queryProperty(
+ const OUString& rName, Property& rProp )
+{
+ auto pProp = std::find_if(std::cbegin(m_pProps), std::cend(m_pProps),
+ [&rName](const Property& rCurrProp) { return rCurrProp.Name == rName; });
+ if (pProp != std::cend(m_pProps))
+ {
+ rProp = *pProp;
+ return true;
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucbprops.hxx b/ucb/source/core/ucbprops.hxx
new file mode 100644
index 000000000..a78222317
--- /dev/null
+++ b/ucb/source/core/ucbprops.hxx
@@ -0,0 +1,56 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+using UcbPropertiesManager_Base = cppu::WeakImplHelper <
+ css::lang::XServiceInfo,
+ css::beans::XPropertySetInfo >;
+
+class UcbPropertiesManager : public UcbPropertiesManager_Base
+{
+ css::uno::Sequence< css::beans::Property > m_pProps;
+
+private:
+ bool queryProperty( const OUString& rName,
+ css::beans::Property& rProp );
+
+public:
+ explicit UcbPropertiesManager();
+ virtual ~UcbPropertiesManager() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySetInfo
+ virtual css::uno::Sequence< css::beans::Property > SAL_CALL
+ getProperties() override;
+ virtual css::beans::Property SAL_CALL
+ getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL
+ hasPropertyByName( const OUString& Name ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucbstore.cxx b/ucb/source/core/ucbstore.cxx
new file mode 100644
index 000000000..01f7c70b5
--- /dev/null
+++ b/ucb/source/core/ucbstore.cxx
@@ -0,0 +1,2205 @@
+/* -*- 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 .
+ */
+
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ *************************************************************************/
+
+#include <optional>
+#include <unordered_map>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ref.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/NotRemoveableException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyExistException.hpp>
+#include <com/sun/star/beans/PropertySetInfoChange.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/util/XChangesBatch.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weak.hxx>
+#include "ucbstore.hxx"
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::configuration;
+using namespace com::sun::star::container;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+using namespace comphelper;
+using namespace cppu;
+
+static OUString makeHierarchalNameSegment( const OUString & rIn )
+{
+ OUStringBuffer aBuffer;
+ aBuffer.append( "['" );
+
+ sal_Int32 nCount = rIn.getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const sal_Unicode c = rIn[ n ];
+ switch ( c )
+ {
+ case '&':
+ aBuffer.append( "&amp;" );
+ break;
+
+ case '"':
+ aBuffer.append( "&quot;" );
+ break;
+
+ case '\'':
+ aBuffer.append( "&apos;" );
+ break;
+
+ case '<':
+ aBuffer.append( "&lt;" );
+ break;
+
+ case '>':
+ aBuffer.append( "&gt;" );
+ break;
+
+ default:
+ aBuffer.append( c );
+ break;
+ }
+ }
+
+ aBuffer.append( "']" );
+ return aBuffer.makeStringAndClear();
+}
+
+constexpr OUStringLiteral STORE_CONTENTPROPERTIES_KEY = u"/org.openoffice.ucb.Store/ContentProperties";
+
+// describe path of cfg entry
+constexpr OUStringLiteral CFGPROPERTY_NODEPATH = u"nodepath";
+
+class PropertySetInfo_Impl : public cppu::WeakImplHelper < XPropertySetInfo >
+{
+ std::optional<Sequence< Property >>
+ m_xProps;
+ PersistentPropertySet* m_pOwner;
+
+public:
+ explicit PropertySetInfo_Impl(PersistentPropertySet* pOwner);
+
+ // XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties() override;
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+
+ // Non-interface methods.
+ void reset() { m_xProps.reset(); }
+};
+
+
+// UcbStore Implementation.
+
+
+UcbStore::UcbStore( const Reference< XComponentContext >& xContext )
+: m_xContext( xContext )
+{
+}
+
+
+// virtual
+UcbStore::~UcbStore()
+{
+}
+
+OUString SAL_CALL UcbStore::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.UcbStore";
+}
+sal_Bool SAL_CALL UcbStore::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+css::uno::Sequence< OUString > SAL_CALL UcbStore::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.Store" };
+}
+
+// Service factory implementation.
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_UcbStore_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new UcbStore(context));
+}
+
+
+// XPropertySetRegistryFactory methods.
+
+
+// virtual
+Reference< XPropertySetRegistry > SAL_CALL
+UcbStore::createPropertySetRegistry( const OUString& )
+{
+ // The URL parameter is ignored by this interface implementation. It always
+ // uses the configuration server as storage medium.
+
+ if ( !m_xTheRegistry.is() )
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if ( !m_xTheRegistry.is() )
+ m_xTheRegistry = new PropertySetRegistry( m_xContext, m_aInitArgs );
+ }
+
+ return m_xTheRegistry;
+}
+
+
+// XInitialization methods.
+
+
+// virtual
+void SAL_CALL UcbStore::initialize( const Sequence< Any >& aArguments )
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_aInitArgs = aArguments;
+}
+
+
+
+// PropertySetRegistry Implementation.
+
+
+PropertySetRegistry::PropertySetRegistry(
+ const Reference< XComponentContext >& xContext,
+ const Sequence< Any > &rInitArgs )
+: m_xContext( xContext )
+, m_aInitArgs(rInitArgs)
+, m_bTriedToGetRootReadAccess(false)
+, m_bTriedToGetRootWriteAccess(false)
+{
+}
+
+
+// virtual
+PropertySetRegistry::~PropertySetRegistry()
+{
+}
+
+
+// XServiceInfo methods.
+
+
+OUString SAL_CALL PropertySetRegistry::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.PropertySetRegistry";
+}
+
+sal_Bool SAL_CALL PropertySetRegistry::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL PropertySetRegistry::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.PropertySetRegistry" };
+}
+
+
+// XPropertySetRegistry methods.
+
+
+// virtual
+Reference< XPersistentPropertySet > SAL_CALL
+PropertySetRegistry::openPropertySet( const OUString& key, sal_Bool create )
+{
+ if ( !key.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ PropertySetMap_Impl& rSets = m_aPropSets;
+
+ PropertySetMap_Impl::const_iterator it = rSets.find( key );
+ if ( it != rSets.end() )
+ {
+ // Already instantiated.
+ return Reference< XPersistentPropertySet >( (*it).second );
+ }
+ else
+ {
+ // Create new instance.
+ Reference< XNameAccess > xRootNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Propertyset in registry?
+ if ( xRootNameAccess->hasByName( key ) )
+ {
+ // Yep!
+ return Reference< XPersistentPropertySet >(
+ new PersistentPropertySet(
+ *this, key ) );
+ }
+ else if ( create )
+ {
+ // No. Create entry for propertyset.
+
+ Reference< XSingleServiceFactory > xFac(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch( xFac, UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PropertySetRegistry::openPropertySet - "
+ "No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Create new "Properties" config item.
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Fill new item...
+
+ // Insert new item.
+ xContainer->insertByName(
+ key, Any( xNameReplace ) );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ return Reference< XPersistentPropertySet >(
+ new PersistentPropertySet(
+ *this, key ) );
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught IllegalArgumentException!" );
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught ElementExistException!" );
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught WrappedTargetException!" );
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught RuntimeException!" );
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::openPropertySet - "
+ "caught Exception!" );
+ }
+ }
+ }
+ else
+ {
+ // No entry. Fail, but no error.
+ return Reference< XPersistentPropertySet >();
+ }
+ }
+
+ SAL_WARN( "ucb", "no root access" );
+ }
+ }
+
+ return Reference< XPersistentPropertySet >();
+}
+
+
+// virtual
+void SAL_CALL PropertySetRegistry::removePropertySet( const OUString& key )
+{
+ if ( key.isEmpty() )
+ return;
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xRootNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Propertyset in registry?
+ if ( !xRootNameAccess->hasByName( key ) )
+ return;
+ Reference< XChangesBatch > xBatch(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ Reference< XNameContainer > xContainer( xBatch, UNO_QUERY );
+
+ if ( xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Remove item.
+ xContainer->removeByName( key );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PropertySetRegistry::removePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::removePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+
+ return;
+ }
+
+ SAL_WARN( "ucb", "no root access" );
+}
+
+
+// XElementAccess methods.
+
+
+// virtual
+css::uno::Type SAL_CALL PropertySetRegistry::getElementType()
+{
+ return cppu::UnoType<XPersistentPropertySet>::get();
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetRegistry::hasElements()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XElementAccess > xElemAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xElemAccess.is() )
+ return xElemAccess->hasElements();
+
+ return false;
+}
+
+
+// XNameAccess methods.
+
+
+// virtual
+Any SAL_CALL PropertySetRegistry::getByName( const OUString& aName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+
+ try
+ {
+ return xNameAccess->getByName( aName );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // getByName
+ }
+ }
+
+ return Any();
+}
+
+
+// virtual
+Sequence< OUString > SAL_CALL PropertySetRegistry::getElementNames()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ return xNameAccess->getElementNames();
+ }
+ return Sequence< OUString >( 0 );
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetRegistry::hasByName( const OUString& aName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XNameAccess > xNameAccess(
+ getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ return xNameAccess->hasByName( aName );
+ }
+
+ return false;
+}
+
+
+void PropertySetRegistry::add( PersistentPropertySet* pSet )
+{
+ OUString key( pSet->getKey() );
+
+ if ( !key.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ m_aPropSets[ key ] = pSet;
+ }
+}
+
+
+void PropertySetRegistry::remove( PersistentPropertySet* pSet )
+{
+ OUString key( pSet->getKey() );
+
+ if ( key.isEmpty() )
+ return;
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ PropertySetMap_Impl& rSets = m_aPropSets;
+
+ PropertySetMap_Impl::iterator it = rSets.find( key );
+ if ( it != rSets.end() )
+ {
+ // Found.
+ rSets.erase( it );
+ }
+}
+
+
+void PropertySetRegistry::renamePropertySet( const OUString& rOldKey,
+ const OUString& rNewKey )
+{
+ if ( rOldKey == rNewKey )
+ return;
+
+ Reference< XNameAccess > xRootNameAccess(
+ getConfigWriteAccess( OUString() ), UNO_QUERY );
+ if ( xRootNameAccess.is() )
+ {
+ // Old key present?
+ if ( xRootNameAccess->hasByName( rOldKey ) )
+ {
+ // New key not present?
+ if ( xRootNameAccess->hasByName( rNewKey ) )
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "New key exists!" );
+ return;
+ }
+ Reference< XSingleServiceFactory > xFac(
+ xRootNameAccess, UNO_QUERY );
+ Reference< XChangesBatch > xBatch( xFac, UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PropertySetRegistry::renamePropertySet - "
+ "No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+
+ // Create new "Properties" config item.
+
+
+ try
+ {
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Insert new item.
+ xContainer->insertByName(
+ rNewKey, Any( xNameReplace ) );
+ // Commit changes.
+ xBatch->commitChanges();
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught RuntimeException!" );
+ return;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught Exception!" );
+ return;
+ }
+
+
+ // Copy data...
+
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ xRootNameAccess, UNO_QUERY );
+ if ( !xRootHierNameAccess.is() )
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "No hierarchical name access!" );
+ return;
+ }
+
+ try
+ {
+ OUString aOldValuesKey
+ = makeHierarchalNameSegment( rOldKey ) + "/Values";
+
+ Reference< XNameAccess > xOldNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(
+ aOldValuesKey )
+ >>= xOldNameAccess;
+ if ( !xOldNameAccess.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No old name access!" );
+ return;
+ }
+
+ // Obtain property names.
+ const Sequence< OUString > aElems
+ = xOldNameAccess->getElementNames();
+ if ( aElems.hasElements() )
+ {
+ OUString aNewValuesKey
+ = makeHierarchalNameSegment( rNewKey ) + "/Values";
+
+ Reference< XSingleServiceFactory > xNewFac;
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewValuesKey )
+ >>= xNewFac;
+ if ( !xNewFac.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new factory!" );
+ return;
+ }
+
+ Reference< XNameContainer > xNewContainer(
+ xNewFac, UNO_QUERY );
+ if ( !xNewContainer.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new container!" );
+ return;
+ }
+
+ aOldValuesKey += "/";
+
+ OUString const aHandleKey("/Handle");
+ OUString const aValueKey("/Value");
+ OUString const aStateKey("/State");
+ OUString const aAttrKey("/Attributes");
+
+ for ( const OUString& rPropName : aElems )
+ {
+ // Create new item.
+ Reference< XNameReplace > xNewPropNameReplace(
+ xNewFac->createInstance(), UNO_QUERY );
+
+ if ( !xNewPropNameReplace.is() )
+ {
+ OSL_FAIL( "PersistentPropertySet::renamePropertySet - "
+ "No new prop name replace!" );
+ return;
+ }
+
+ // Fill new item...
+
+ // Set Values
+ OUString aKey = aOldValuesKey;
+ aKey += makeHierarchalNameSegment( rPropName );
+
+ // ... handle
+ OUString aNewKey1 = aKey + aHandleKey;
+ Any aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Handle", aAny );
+
+ // ... value
+ aNewKey1 = aKey + aValueKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Value", aAny );
+
+ // ... state
+ aNewKey1 = aKey + aStateKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "State", aAny );
+
+ // ... attributes
+ aNewKey1 = aKey + aAttrKey;
+ aAny =
+ xRootHierNameAccess->getByHierarchicalName(
+ aNewKey1 );
+ xNewPropNameReplace->replaceByName( "Attributes", aAny );
+
+ // Insert new item.
+ xNewContainer->insertByName(
+ rPropName, Any( xNewPropNameReplace ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+ }
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName, replaceByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // insertByName, replaceByName, commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught RuntimeException!" );
+ return;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught Exception!" );
+ return;
+ }
+
+
+ // Remove old entry...
+
+
+ try
+ {
+ // Remove item.
+ xContainer->removeByName( rOldKey );
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+ }
+ }
+
+ OSL_FAIL( "PropertySetRegistry::renamePropertySet - Error!" );
+}
+
+
+Reference< XMultiServiceFactory > PropertySetRegistry::getConfigProvider()
+{
+ if ( !m_xConfigProvider.is() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ if ( !m_xConfigProvider.is() )
+ {
+ const Sequence< Any >& rInitArgs = m_aInitArgs;
+
+ if ( rInitArgs.hasElements() )
+ {
+ // Extract config provider from service init args.
+ rInitArgs[ 0 ] >>= m_xConfigProvider;
+
+ OSL_ENSURE( m_xConfigProvider.is(),
+ "PropertySetRegistry::getConfigProvider - "
+ "No config provider!" );
+ }
+ else
+ {
+ try
+ {
+ m_xConfigProvider = theDefaultProvider::get( m_xContext );
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "ucb", "");
+ }
+ }
+ }
+ }
+
+ return m_xConfigProvider;
+}
+
+
+Reference< XInterface > PropertySetRegistry::getRootConfigReadAccess()
+{
+ try
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_xRootReadAccess.is() )
+ {
+ if ( m_bTriedToGetRootReadAccess )
+ {
+ OSL_FAIL( "PropertySetRegistry::getRootConfigReadAccess - "
+ "Unable to read any config data! -> #82494#" );
+ return Reference< XInterface >();
+ }
+
+ getConfigProvider();
+
+ if ( m_xConfigProvider.is() )
+ {
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {CFGPROPERTY_NODEPATH, Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
+ }));
+
+ m_bTriedToGetRootReadAccess = true;
+
+ m_xRootReadAccess =
+ m_xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments );
+
+ if ( m_xRootReadAccess.is() )
+ return m_xRootReadAccess;
+ }
+ }
+ else
+ return m_xRootReadAccess;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ // createInstance, createInstanceWithArguments
+
+ TOOLS_WARN_EXCEPTION("ucb", "");
+ return Reference< XInterface >();
+ }
+
+ SAL_WARN( "ucb", "Error!" );
+ return Reference< XInterface >();
+}
+
+
+Reference< XInterface > PropertySetRegistry::getConfigWriteAccess(
+ const OUString& rPath )
+{
+ try
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_xRootWriteAccess.is() )
+ {
+ if ( m_bTriedToGetRootWriteAccess )
+ {
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "Unable to write any config data! -> #82494#" );
+ return Reference< XInterface >();
+ }
+
+ getConfigProvider();
+
+ if ( m_xConfigProvider.is() )
+ {
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {CFGPROPERTY_NODEPATH, Any(OUString( STORE_CONTENTPROPERTIES_KEY ))}
+ }));
+
+ m_bTriedToGetRootWriteAccess = true;
+
+ m_xRootWriteAccess =
+ m_xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationUpdateAccess",
+ aArguments );
+
+ OSL_ENSURE( m_xRootWriteAccess.is(),
+ "PropertySetRegistry::getConfigWriteAccess - "
+ "No config update access!" );
+ }
+ }
+
+ if ( m_xRootWriteAccess.is() )
+ {
+ if ( !rPath.isEmpty() )
+ {
+ Reference< XHierarchicalNameAccess > xNA(
+ m_xRootWriteAccess, UNO_QUERY );
+ if ( xNA.is() )
+ {
+ Reference< XInterface > xInterface;
+ xNA->getByHierarchicalName( rPath ) >>= xInterface;
+
+ if ( xInterface.is() )
+ return xInterface;
+ }
+ }
+ else
+ return m_xRootWriteAccess;
+ }
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "caught NoSuchElementException!" );
+ return Reference< XInterface >();
+ }
+ catch (const Exception&)
+ {
+ // createInstance, createInstanceWithArguments
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - "
+ "caught Exception!" );
+ return Reference< XInterface >();
+ }
+
+ OSL_FAIL( "PropertySetRegistry::getConfigWriteAccess - Error!" );
+ return Reference< XInterface >();
+}
+
+
+// PersistentPropertySet Implementation.
+
+
+PersistentPropertySet::PersistentPropertySet(
+ PropertySetRegistry& rCreator,
+ const OUString& rKey )
+: m_pCreator( &rCreator ), m_aKey( rKey )
+{
+ // register at creator.
+ rCreator.add( this );
+}
+
+
+// virtual
+PersistentPropertySet::~PersistentPropertySet()
+{
+ // deregister at creator.
+ m_pCreator->remove( this );
+}
+
+// XServiceInfo methods.
+
+OUString SAL_CALL PersistentPropertySet::getImplementationName()
+{
+ return "com.sun.star.comp.ucb.PersistentPropertySet";
+}
+
+sal_Bool SAL_CALL PersistentPropertySet::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL PersistentPropertySet::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.PersistentPropertySet" };
+}
+
+
+// XComponent methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::dispose()
+{
+ if ( m_pDisposeEventListeners &&
+ m_pDisposeEventListeners->getLength() )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XComponent * >( this );
+ m_pDisposeEventListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XPropertySetInfoChangeNotifier * >( this );
+ m_pPropSetChangeListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pPropertyChangeListeners )
+ {
+ EventObject aEvt;
+ aEvt.Source = static_cast< XPropertySet * >( this );
+ m_pPropertyChangeListeners->disposeAndClear( aEvt );
+ }
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( !m_pDisposeEventListeners )
+ m_pDisposeEventListeners.reset(
+ new OInterfaceContainerHelper3<css::lang::XEventListener>( m_aMutex ) );
+
+ m_pDisposeEventListeners->addInterface( Listener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeEventListener(
+ const Reference< XEventListener >& Listener )
+{
+ if ( m_pDisposeEventListeners )
+ m_pDisposeEventListeners->removeInterface( Listener );
+
+ // Note: Don't want to delete empty container here -> performance.
+}
+
+
+// XPropertySet methods.
+
+
+// virtual
+Reference< XPropertySetInfo > SAL_CALL PersistentPropertySet::getPropertySetInfo()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( !m_pInfo.is() )
+ {
+ m_pInfo = new PropertySetInfo_Impl( this );
+ }
+ return m_pInfo;
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setPropertyValue( const OUString& aPropertyName,
+ const Any& aValue )
+{
+ osl::ClearableGuard< osl::Mutex > aCGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( aPropertyName );
+
+ // Does property exist?
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ Reference< XNameReplace > xNameReplace(
+ m_pCreator->getConfigWriteAccess(
+ aFullPropName ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess(
+ OUString() ), UNO_QUERY );
+
+ if ( xNameReplace.is() && xBatch.is() )
+ {
+ try
+ {
+ // Obtain old value
+ OUString aValueName = aFullPropName + "/Value";
+ Any aOldValue
+ = xRootHierNameAccess->getByHierarchicalName(
+ aValueName );
+ // Check value type.
+ if ( aOldValue.getValueType() != aValue.getValueType() )
+ {
+ aCGuard.clear();
+ throw IllegalArgumentException();
+ }
+
+ // Write value
+ xNameReplace->replaceByName( "Value", aValue );
+
+ // Write state ( Now it is a directly set value )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DIRECT_VALUE ) ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ PropertyChangeEvent aEvt;
+ if ( m_pPropertyChangeListeners )
+ {
+ // Obtain handle
+ aValueName = aFullPropName + "/Handle";
+ sal_Int32 nHandle = -1;
+ xRootHierNameAccess->getByHierarchicalName( aValueName )
+ >>= nHandle;
+
+ aEvt.Source = static_cast<OWeakObject*>(this);
+ aEvt.PropertyName = aPropertyName;
+ aEvt.PropertyHandle = nHandle;
+ aEvt.Further = false;
+ aEvt.OldValue = aOldValue;
+ aEvt.NewValue = aValue;
+
+ // Callback follows!
+ aCGuard.clear();
+
+ notifyPropertyChangeEvent( aEvt );
+ }
+ return;
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // replaceByName
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, commitChanges
+ }
+ }
+ }
+ }
+
+ throw UnknownPropertyException(aPropertyName);
+}
+
+
+// virtual
+Any SAL_CALL PersistentPropertySet::getPropertyValue(
+ const OUString& PropertyName )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ OUString aFullPropName( getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( PropertyName ) + "/Value";
+ try
+ {
+ return xNameAccess->getByHierarchicalName( aFullPropName );
+ }
+ catch (const NoSuchElementException&)
+ {
+ throw UnknownPropertyException(aFullPropName);
+ }
+ }
+
+ throw UnknownPropertyException(PropertyName);
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addPropertyChangeListener(
+ const OUString& aPropertyName,
+ const Reference< XPropertyChangeListener >& xListener )
+{
+// load();
+
+ if ( !m_pPropertyChangeListeners )
+ m_pPropertyChangeListeners.reset(
+ new PropertyListeners_Impl( m_aMutex ) );
+
+ m_pPropertyChangeListeners->addInterface(
+ aPropertyName, xListener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removePropertyChangeListener(
+ const OUString& aPropertyName,
+ const Reference< XPropertyChangeListener >& aListener )
+{
+// load();
+
+ if ( m_pPropertyChangeListeners )
+ m_pPropertyChangeListeners->removeInterface(
+ aPropertyName, aListener );
+
+ // Note: Don't want to delete empty container here -> performance.
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addVetoableChangeListener(
+ const OUString&,
+ const Reference< XVetoableChangeListener >& )
+{
+// load();
+// OSL_FAIL( // "PersistentPropertySet::addVetoableChangeListener - N.Y.I." );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeVetoableChangeListener(
+ const OUString&,
+ const Reference< XVetoableChangeListener >& )
+{
+// load();
+// OSL_FAIL( // "PersistentPropertySet::removeVetoableChangeListener - N.Y.I." );
+}
+
+
+// XPersistentPropertySet methods.
+
+
+// virtual
+Reference< XPropertySetRegistry > SAL_CALL PersistentPropertySet::getRegistry()
+{
+ return m_pCreator;
+}
+
+
+// virtual
+OUString SAL_CALL PersistentPropertySet::getKey()
+{
+ return m_aKey;
+}
+
+
+// XNamed methods.
+
+
+// virtual
+OUString SAL_CALL PersistentPropertySet::getName()
+{
+ // same as getKey()
+ return m_aKey;
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setName( const OUString& aName )
+{
+ if ( aName != m_aKey )
+ m_pCreator->renamePropertySet( m_aKey, aName );
+}
+
+
+// XPropertyContainer methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addProperty(
+ const OUString& Name, sal_Int16 Attributes, const Any& DefaultValue )
+{
+ if ( Name.isEmpty() )
+ throw IllegalArgumentException();
+
+ // @@@ What other types can't be written to config server?
+
+ // Check type class ( Not all types can be written to storage )
+ TypeClass eTypeClass = DefaultValue.getValueTypeClass();
+ if ( eTypeClass == TypeClass_INTERFACE )
+ throw IllegalTypeException();
+
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ // Property already in set?
+
+ OUString aFullValuesName;
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ aFullValuesName = getFullKey();
+ OUString aFullPropName = aFullValuesName + "/";
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ // Already in set.
+ throw PropertyExistException();
+ }
+ }
+
+ // Property is always removable.
+ Attributes |= PropertyAttribute::REMOVABLE;
+
+ // Add property.
+
+ Reference< XSingleServiceFactory > xFac(
+ m_pCreator->getConfigWriteAccess( aFullValuesName ),
+ UNO_QUERY );
+ Reference< XNameContainer > xContainer( xFac, UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess( OUString() ),
+ UNO_QUERY );
+
+ OSL_ENSURE( xFac.is(),
+ "PersistentPropertySet::addProperty - No factory!" );
+
+ OSL_ENSURE( xBatch.is(),
+ "PersistentPropertySet::addProperty - No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PersistentPropertySet::addProperty - No container!" );
+
+ if ( xFac.is() && xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ // Create new "PropertyValue" config item.
+ Reference< XNameReplace > xNameReplace(
+ xFac->createInstance(), UNO_QUERY );
+
+ if ( xNameReplace.is() )
+ {
+ // Fill new item...
+
+ // Set handle
+ xNameReplace->replaceByName(
+ "Handle",
+ Any( sal_Int32( -1 ) ) );
+
+ // Set default value
+ xNameReplace->replaceByName(
+ "Value",
+ DefaultValue );
+
+ // Set state ( always "default" )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DEFAULT_VALUE ) ) );
+
+ // Set attributes
+ xNameReplace->replaceByName(
+ "Attributes",
+ Any( sal_Int32( Attributes ) ) );
+
+ // Insert new item.
+ xContainer->insertByName( Name, Any( xNameReplace ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ // Property set info is invalid.
+ if ( m_pInfo.is() )
+ m_pInfo->reset();
+
+ // Notify propertyset info change listeners.
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ PropertySetInfoChangeEvent evt(
+ static_cast< OWeakObject * >( this ),
+ Name,
+ -1,
+ PropertySetInfoChange::PROPERTY_INSERTED );
+ notifyPropertySetInfoChange( evt );
+ }
+
+ // Success.
+ return;
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught IllegalArgumentException!" );
+ return;
+ }
+ catch (const ElementExistException&)
+ {
+ // insertByName
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught ElementExistException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, insertByName, commitChanges
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const Exception&)
+ {
+ // createInstance
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - "
+ "caught Exception!" );
+ return;
+ }
+ }
+
+ OSL_FAIL( "PersistentPropertySet::addProperty - Error!" );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removeProperty( const OUString& Name )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullValuesName = getFullKey();
+ OUString aFullPropName = aFullValuesName + "/";
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ // Property in set?
+ if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ throw UnknownPropertyException(aFullPropName);
+
+ // Property removable?
+ try
+ {
+ OUString aFullAttrName = aFullPropName + "/Attributes";
+
+ sal_Int32 nAttribs = 0;
+ if ( xRootHierNameAccess->getByHierarchicalName( aFullAttrName )
+ >>= nAttribs )
+ {
+ if ( !( nAttribs & PropertyAttribute::REMOVABLE ) )
+ {
+ // Not removable!
+ throw NotRemoveableException();
+ }
+ }
+ else
+ {
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "No attributes!" );
+ return;
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ }
+
+ // Remove property...
+
+ Reference< XNameContainer > xContainer(
+ m_pCreator->getConfigWriteAccess( aFullValuesName ),
+ UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess( OUString() ),
+ UNO_QUERY );
+
+ OSL_ENSURE( xBatch.is(),
+ "PersistentPropertySet::removeProperty - No batch!" );
+
+ OSL_ENSURE( xContainer.is(),
+ "PersistentPropertySet::removeProperty - No container!" );
+
+ if ( xBatch.is() && xContainer.is() )
+ {
+ try
+ {
+ sal_Int32 nHandle = -1;
+
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ // Obtain property handle ( needed for propertysetinfo
+ // change event )...
+
+ try
+ {
+ OUString aFullHandleName = aFullPropName + "/Handle";
+
+ if ( ! ( xRootHierNameAccess->getByHierarchicalName(
+ aFullHandleName ) >>= nHandle ) )
+ nHandle = -1;
+
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ nHandle = -1;
+ }
+ }
+
+ xContainer->removeByName( Name );
+ xBatch->commitChanges();
+
+ // Property set info is invalid.
+ if ( m_pInfo.is() )
+ m_pInfo->reset();
+
+ // Notify propertyset info change listeners.
+ if ( m_pPropSetChangeListeners &&
+ m_pPropSetChangeListeners->getLength() )
+ {
+ PropertySetInfoChangeEvent evt(
+ static_cast< OWeakObject * >( this ),
+ Name,
+ nHandle,
+ PropertySetInfoChange::PROPERTY_REMOVED );
+ notifyPropertySetInfoChange( evt );
+ }
+
+ // Success.
+ return;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // removeByName
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught NoSuchElementException!" );
+ return;
+ }
+ catch (const WrappedTargetException&)
+ {
+ // commitChanges
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - "
+ "caught WrappedTargetException!" );
+ return;
+ }
+ }
+ }
+
+ OSL_FAIL( "PersistentPropertySet::removeProperty - Error!" );
+}
+
+
+// XPropertySetInfoChangeNotifier methods.
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::addPropertySetInfoChangeListener(
+ const Reference< XPropertySetInfoChangeListener >& Listener )
+{
+ if ( !m_pPropSetChangeListeners )
+ m_pPropSetChangeListeners.reset(
+ new OInterfaceContainerHelper3<XPropertySetInfoChangeListener>( m_aMutex ) );
+
+ m_pPropSetChangeListeners->addInterface( Listener );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::removePropertySetInfoChangeListener(
+ const Reference< XPropertySetInfoChangeListener >& Listener )
+{
+ if ( m_pPropSetChangeListeners )
+ m_pPropSetChangeListeners->removeInterface( Listener );
+}
+
+
+// XPropertyAccess methods.
+
+
+// virtual
+Sequence< PropertyValue > SAL_CALL PersistentPropertySet::getPropertyValues()
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ try
+ {
+ Reference< XNameAccess > xNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(getFullKey())
+ >>= xNameAccess;
+ if ( xNameAccess.is() )
+ {
+ // Obtain property names.
+
+ Sequence< OUString > aElems = xNameAccess->getElementNames();
+
+ sal_Int32 nCount = aElems.getLength();
+ if ( nCount )
+ {
+ Reference< XHierarchicalNameAccess > xHierNameAccess(
+ xNameAccess, UNO_QUERY );
+
+ OSL_ENSURE( xHierNameAccess.is(),
+ "PersistentPropertySet::getPropertyValues - "
+ "No hierarchical name access!" );
+
+ if ( xHierNameAccess.is() )
+ {
+ Sequence< PropertyValue > aValues( nCount );
+ auto pValues = aValues.getArray();
+
+ static const OUStringLiteral aHandleName(u"/Handle");
+ static const OUStringLiteral aValueName(u"/Value");
+ static const OUStringLiteral aStateName(u"/State");
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ PropertyValue& rValue = pValues[ n ];
+ OUString rName = aElems[ n ];
+ OUString aXMLName
+ = makeHierarchalNameSegment( rName );
+
+ // Set property name.
+
+ rValue.Name = rName;
+
+ try
+ {
+ // Obtain and set property handle
+ OUString aHierName = aXMLName + aHandleName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ if ( !( aKeyValue >>= rValue.Handle ) )
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "Error getting property handle!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property value
+ OUString aHierName = aXMLName + aValueName;
+ rValue.Value
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ // Note: The value may be void if addProperty
+ // was called with a default value
+ // of type void.
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property state
+ OUString aHierName = aXMLName +aStateName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ sal_Int32 nState = 0;
+ if ( !( aKeyValue >>= nState ) )
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "Error getting property state!" );
+ else
+ rValue.State = PropertyState( nState );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PersistentPropertySet::getPropertyValues - "
+ "NoSuchElementException!" );
+ }
+ }
+
+ return aValues;
+ }
+ }
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+ }
+ }
+
+ return Sequence< PropertyValue >( 0 );
+}
+
+
+// virtual
+void SAL_CALL PersistentPropertySet::setPropertyValues(
+ const Sequence< PropertyValue >& aProps )
+{
+ if ( !aProps.hasElements() )
+ return;
+
+ osl::ClearableGuard< osl::Mutex > aCGuard( m_aMutex );
+
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pCreator->getRootConfigReadAccess(), UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ std::vector< PropertyChangeEvent > aEvents;
+
+ OUString aFullPropNamePrefix( getFullKey() + "/" );
+
+ // Iterate over given property value sequence.
+ for ( const PropertyValue& rNewValue : aProps )
+ {
+ const OUString& rName = rNewValue.Name;
+
+ OUString aFullPropName = aFullPropNamePrefix;
+ aFullPropName += makeHierarchalNameSegment( rName );
+
+ // Does property exist?
+ if ( xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ {
+ Reference< XNameReplace > xNameReplace(
+ m_pCreator->getConfigWriteAccess(
+ aFullPropName ), UNO_QUERY );
+ Reference< XChangesBatch > xBatch(
+ m_pCreator->getConfigWriteAccess(
+ OUString() ), UNO_QUERY );
+
+ if ( xNameReplace.is() && xBatch.is() )
+ {
+ try
+ {
+ // Write handle
+ xNameReplace->replaceByName(
+ "Handle",
+ Any( rNewValue.Handle ) );
+
+ // Save old value
+ OUString aValueName = aFullPropName +"/Value";
+ Any aOldValue
+ = xRootHierNameAccess->getByHierarchicalName(
+ aValueName );
+ // Write value
+ xNameReplace->replaceByName(
+ "Value",
+ rNewValue.Value );
+
+ // Write state ( Now it is a directly set value )
+ xNameReplace->replaceByName(
+ "State",
+ Any(
+ sal_Int32(
+ PropertyState_DIRECT_VALUE ) ) );
+
+ // Commit changes.
+ xBatch->commitChanges();
+
+ if ( m_pPropertyChangeListeners )
+ {
+ PropertyChangeEvent aEvt;
+ aEvt.Source = static_cast<OWeakObject*>(this);
+ aEvt.PropertyName = rNewValue.Name;
+ aEvt.PropertyHandle = rNewValue.Handle;
+ aEvt.Further = false;
+ aEvt.OldValue = aOldValue;
+ aEvt.NewValue = rNewValue.Value;
+
+ aEvents.push_back( aEvt );
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ // replaceByName
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName, replaceByName
+ }
+ catch (const WrappedTargetException&)
+ {
+ // replaceByName, commitChanges
+ }
+ }
+ }
+ }
+
+ // Callback follows!
+ aCGuard.clear();
+
+ if ( m_pPropertyChangeListeners )
+ {
+ // Notify property changes.
+ for (auto const& event : aEvents)
+ {
+ notifyPropertyChangeEvent( event );
+ }
+ }
+
+ return;
+ }
+
+ OSL_FAIL( "PersistentPropertySet::setPropertyValues - Nothing set!" );
+}
+
+
+// Non-interface methods
+
+
+void PersistentPropertySet::notifyPropertyChangeEvent(
+ const PropertyChangeEvent& rEvent ) const
+{
+ // Get "normal" listeners for the property.
+ OInterfaceContainerHelper3<XPropertyChangeListener>* pContainer =
+ m_pPropertyChangeListeners->getContainer( rEvent.PropertyName );
+ if ( pContainer && pContainer->getLength() )
+ {
+ pContainer->notifyEach( &XPropertyChangeListener::propertyChange, rEvent );
+ }
+
+ // Get "normal" listeners for all properties.
+ OInterfaceContainerHelper3<XPropertyChangeListener>* pNoNameContainer =
+ m_pPropertyChangeListeners->getContainer( OUString() );
+ if ( pNoNameContainer && pNoNameContainer->getLength() )
+ {
+ pNoNameContainer->notifyEach( &XPropertyChangeListener::propertyChange, rEvent );
+ }
+}
+
+
+void PersistentPropertySet::notifyPropertySetInfoChange(
+ const PropertySetInfoChangeEvent& evt ) const
+{
+ if ( !m_pPropSetChangeListeners )
+ return;
+
+ // Notify event listeners.
+ m_pPropSetChangeListeners->notifyEach( &XPropertySetInfoChangeListener::propertySetInfoChange, evt );
+}
+
+
+const OUString& PersistentPropertySet::getFullKey()
+{
+ if ( m_aFullKey.isEmpty() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+ if ( m_aFullKey.isEmpty() )
+ {
+ m_aFullKey = makeHierarchalNameSegment( m_aKey );
+ m_aFullKey += "/Values";
+ }
+ }
+
+ return m_aFullKey;
+}
+
+
+PropertySetRegistry& PersistentPropertySet::getPropertySetRegistry()
+{
+ return *m_pCreator;
+}
+
+
+// PropertySetInfo_Impl Implementation.
+
+
+PropertySetInfo_Impl::PropertySetInfo_Impl(
+ PersistentPropertySet* pOwner )
+: m_pOwner( pOwner )
+{
+}
+
+
+// XPropertySetInfo methods.
+
+
+// virtual
+Sequence< Property > SAL_CALL PropertySetInfo_Impl::getProperties()
+{
+ if ( !m_xProps )
+ {
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ try
+ {
+ Reference< XNameAccess > xNameAccess;
+ xRootHierNameAccess->getByHierarchicalName(
+ m_pOwner->getFullKey() )
+ >>= xNameAccess;
+ if ( xNameAccess.is() )
+ {
+ // Obtain property names.
+
+ Sequence< OUString > aElems
+ = xNameAccess->getElementNames();
+
+ sal_uInt32 nCount = aElems.getLength();
+ Sequence< Property > aPropSeq( nCount );
+
+ if ( nCount )
+ {
+ Reference< XHierarchicalNameAccess > xHierNameAccess(
+ xNameAccess, UNO_QUERY );
+
+ OSL_ENSURE( xHierNameAccess.is(),
+ "PropertySetInfo_Impl::getProperties - "
+ "No hierarchical name access!" );
+
+ if ( xHierNameAccess.is() )
+ {
+ static const OUStringLiteral aHandleName(u"/Handle");
+ static const OUStringLiteral aValueName(u"/Value");
+ static const OUStringLiteral aAttrName(u"/Attributes");
+
+ Property* pProps = aPropSeq.getArray();
+
+ for ( sal_uInt32 n = 0; n < nCount; ++n )
+ {
+ Property& rProp = pProps[ n ];
+ OUString rName = aElems[ n ];
+ OUString aXMLName
+ = makeHierarchalNameSegment( rName );
+
+ // Set property name.
+
+ rProp.Name = rName;
+
+ try
+ {
+ // Obtain and set property handle
+ OUString aHierName = aXMLName + aHandleName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ if ( !( aKeyValue >>= rProp.Handle ) )
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "Error getting property handle!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property type
+ OUString aHierName = aXMLName + aValueName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ // Note: The type may be void if addProperty
+ // was called with a default value
+ // of type void.
+
+ rProp.Type = aKeyValue.getValueType();
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+
+ try
+ {
+ // Obtain and set property attributes
+ OUString aHierName = aXMLName + aAttrName;
+ Any aKeyValue
+ = xHierNameAccess->getByHierarchicalName(
+ aHierName );
+
+ sal_Int32 nAttribs = 0;
+ if ( aKeyValue >>= nAttribs )
+ rProp.Attributes
+ = sal_Int16( nAttribs );
+ else
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "Error getting property attributes!" );
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - "
+ "NoSuchElementException!" );
+ }
+ }
+ }
+ }
+
+ // Success.
+ m_xProps = std::move(aPropSeq);
+ return *m_xProps;
+ }
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+ }
+ }
+
+ OSL_FAIL( "PropertySetInfo_Impl::getProperties - Error!" );
+ m_xProps.emplace();
+ }
+
+ return *m_xProps;
+}
+
+
+// virtual
+Property SAL_CALL PropertySetInfo_Impl::getPropertyByName(
+ const OUString& aName )
+{
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( m_pOwner->getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( aName );
+
+ // Does property exist?
+ if ( !xRootHierNameAccess->hasByHierarchicalName( aFullPropName ) )
+ throw UnknownPropertyException(aFullPropName);
+
+ try
+ {
+ Property aProp;
+
+ // Obtain handle.
+ OUString aKey = aFullPropName + "/Handle";
+
+ if ( !( xRootHierNameAccess->getByHierarchicalName( aKey )
+ >>= aProp.Handle ) )
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No handle!" );
+ return Property();
+ }
+
+ // Obtain Value and extract type.
+ aKey = aFullPropName + "/Value";
+
+ Any aValue = xRootHierNameAccess->getByHierarchicalName( aKey );
+ if ( !aValue.hasValue() )
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No Value!" );
+ return Property();
+ }
+
+ aProp.Type = aValue.getValueType();
+
+ // Obtain Attributes.
+ aKey = aFullPropName + "/Attributes";
+
+ sal_Int32 nAttribs = 0;
+ if ( xRootHierNameAccess->getByHierarchicalName( aKey )
+ >>= nAttribs )
+ aProp.Attributes = sal_Int16( nAttribs );
+ else
+ {
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "No attributes!" );
+ return Property();
+ }
+
+ // set name.
+ aProp.Name = aName;
+
+ // Success.
+ return aProp;
+ }
+ catch (const NoSuchElementException&)
+ {
+ // getByHierarchicalName
+
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - "
+ "caught NoSuchElementException!" );
+ }
+
+ }
+
+ OSL_FAIL( "PropertySetInfo_Impl::getPropertyByName - Error!" );
+ return Property();
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetInfo_Impl::hasPropertyByName(
+ const OUString& Name )
+{
+ Reference< XHierarchicalNameAccess > xRootHierNameAccess(
+ m_pOwner->getPropertySetRegistry().getRootConfigReadAccess(),
+ UNO_QUERY );
+ if ( xRootHierNameAccess.is() )
+ {
+ OUString aFullPropName( m_pOwner->getFullKey() + "/" );
+ aFullPropName += makeHierarchalNameSegment( Name );
+
+ return xRootHierNameAccess->hasByHierarchicalName( aFullPropName );
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/core/ucbstore.hxx b/ucb/source/core/ucbstore.hxx
new file mode 100644
index 000000000..8b8597f75
--- /dev/null
+++ b/ucb/source/core/ucbstore.hxx
@@ -0,0 +1,248 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
+#include <com/sun/star/ucb/XPropertySetRegistry.hpp>
+#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/beans/XPropertySetInfoChangeNotifier.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/multiinterfacecontainer3.hxx>
+#include <comphelper/compbase.hxx>
+#include <rtl/ref.hxx>
+#include <unordered_map>
+
+
+using UcbStore_Base = comphelper::WeakComponentImplHelper <
+ css::lang::XServiceInfo,
+ css::ucb::XPropertySetRegistryFactory,
+ css::lang::XInitialization >;
+
+class UcbStore : public UcbStore_Base
+{
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Sequence< css::uno::Any > m_aInitArgs;
+ css::uno::Reference< css::ucb::XPropertySetRegistry > m_xTheRegistry;
+
+public:
+ explicit UcbStore( const css::uno::Reference< css::uno::XComponentContext >& xContext );
+ virtual ~UcbStore() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySetRegistryFactory
+ virtual css::uno::Reference< css::ucb::XPropertySetRegistry > SAL_CALL
+ createPropertySetRegistry( const OUString& URL ) override;
+
+ // XInitialization
+ virtual void SAL_CALL
+ initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+};
+
+
+class PersistentPropertySet;
+
+// PropertySetMap_Impl.
+typedef std::unordered_map< OUString, PersistentPropertySet*> PropertySetMap_Impl;
+
+class PropertySetRegistry : public cppu::WeakImplHelper <
+ css::lang::XServiceInfo,
+ css::ucb::XPropertySetRegistry,
+ css::container::XNameAccess >
+{
+ friend class PersistentPropertySet;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ const css::uno::Sequence< css::uno::Any > m_aInitArgs;
+ PropertySetMap_Impl m_aPropSets;
+ css::uno::Reference< css::lang::XMultiServiceFactory > m_xConfigProvider;
+ css::uno::Reference< css::uno::XInterface > m_xRootReadAccess;
+ css::uno::Reference< css::uno::XInterface > m_xRootWriteAccess;
+ osl::Mutex m_aMutex;
+ bool m_bTriedToGetRootReadAccess;
+ bool m_bTriedToGetRootWriteAccess;
+
+private:
+ css::uno::Reference< css::lang::XMultiServiceFactory >
+ getConfigProvider();
+
+ void add ( PersistentPropertySet* pSet );
+ void remove( PersistentPropertySet* pSet );
+
+ void renamePropertySet( const OUString& rOldKey,
+ const OUString& rNewKey );
+
+public:
+ PropertySetRegistry(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Sequence< css::uno::Any >& rInitArgs);
+ virtual ~PropertySetRegistry() override;
+
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XPropertySetRegistry
+ virtual css::uno::Reference< css::ucb::XPersistentPropertySet > SAL_CALL
+ openPropertySet( const OUString& key, sal_Bool create ) override;
+ virtual void SAL_CALL
+ removePropertySet( const OUString& key ) override;
+
+ // XElementAccess ( XNameAccess is derived from it )
+ virtual css::uno::Type SAL_CALL
+ getElementType() override;
+ virtual sal_Bool SAL_CALL
+ hasElements() 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;
+
+ // Non-interface methods
+ css::uno::Reference< css::uno::XInterface >
+ getRootConfigReadAccess();
+ css::uno::Reference< css::uno::XInterface >
+ getConfigWriteAccess( const OUString& rPath );
+};
+
+
+class PropertySetInfo_Impl;
+typedef comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XPropertyChangeListener, OUString> PropertyListeners_Impl;
+
+class PersistentPropertySet : public cppu::WeakImplHelper <
+ css::lang::XServiceInfo,
+ css::lang::XComponent,
+ css::ucb::XPersistentPropertySet,
+ css::container::XNamed,
+ css::beans::XPropertyContainer,
+ css::beans::XPropertySetInfoChangeNotifier,
+ css::beans::XPropertyAccess >
+{
+ rtl::Reference<PropertySetRegistry> m_pCreator;
+ rtl::Reference<PropertySetInfo_Impl> m_pInfo;
+ OUString m_aKey;
+ OUString m_aFullKey;
+ osl::Mutex m_aMutex;
+ std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::lang::XEventListener>> m_pDisposeEventListeners;
+ std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::beans::XPropertySetInfoChangeListener>> m_pPropSetChangeListeners;
+ std::unique_ptr<PropertyListeners_Impl> m_pPropertyChangeListeners;
+
+private:
+ void notifyPropertyChangeEvent(
+ const css::beans::PropertyChangeEvent& rEvent ) const;
+ void notifyPropertySetInfoChange(
+ const css::beans::PropertySetInfoChangeEvent& evt ) const;
+
+public:
+ PersistentPropertySet(
+ PropertySetRegistry& rCreator,
+ const OUString& rKey );
+ virtual ~PersistentPropertySet() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XComponent
+ virtual void SAL_CALL
+ dispose() override;
+ virtual void SAL_CALL
+ addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) override;
+ virtual void SAL_CALL
+ removeEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) 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;
+
+ // XPersistentPropertySet
+ virtual css::uno::Reference< css::ucb::XPropertySetRegistry > SAL_CALL
+ getRegistry() override;
+ virtual OUString SAL_CALL
+ getKey() override;
+
+ // XNamed
+ virtual OUString SAL_CALL
+ getName() override;
+ virtual void SAL_CALL
+ setName( const OUString& aName ) override;
+
+ // XPropertyContainer
+ virtual void SAL_CALL
+ addProperty( const OUString& Name,
+ sal_Int16 Attributes,
+ const css::uno::Any& DefaultValue ) override;
+ virtual void SAL_CALL
+ removeProperty( const OUString& Name ) override;
+
+ // XPropertySetInfoChangeNotifier
+ virtual void SAL_CALL
+ addPropertySetInfoChangeListener( const css::uno::Reference< css::beans::XPropertySetInfoChangeListener >& Listener ) override;
+ virtual void SAL_CALL
+ removePropertySetInfoChangeListener( const css::uno::Reference< css::beans::XPropertySetInfoChangeListener >& Listener ) override;
+
+ // XPropertyAccess
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL
+ getPropertyValues() override;
+ virtual void SAL_CALL
+ setPropertyValues( const css::uno::Sequence< css::beans::PropertyValue >& aProps ) override;
+
+ // Non-interface methods.
+ PropertySetRegistry& getPropertySetRegistry();
+ const OUString& getFullKey();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */