summaryrefslogtreecommitdiffstats
path: root/ucbhelper/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /ucbhelper/source
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--ucbhelper/source/client/activedatasink.cxx40
-rw-r--r--ucbhelper/source/client/activedatastreamer.cxx41
-rw-r--r--ucbhelper/source/client/activedatastreamer.hxx48
-rw-r--r--ucbhelper/source/client/commandenvironment.cxx77
-rw-r--r--ucbhelper/source/client/content.cxx1353
-rw-r--r--ucbhelper/source/client/interceptedinteraction.cxx138
-rw-r--r--ucbhelper/source/client/proxydecider.cxx916
-rw-r--r--ucbhelper/source/provider/authenticationfallback.cxx31
-rw-r--r--ucbhelper/source/provider/cancelcommandexecution.cxx115
-rw-r--r--ucbhelper/source/provider/contenthelper.cxx863
-rw-r--r--ucbhelper/source/provider/contentidentifier.cxx91
-rw-r--r--ucbhelper/source/provider/contentinfo.cxx318
-rw-r--r--ucbhelper/source/provider/contentinfo.hxx119
-rw-r--r--ucbhelper/source/provider/interactionrequest.cxx626
-rw-r--r--ucbhelper/source/provider/propertyvalueset.cxx680
-rw-r--r--ucbhelper/source/provider/providerhelper.cxx497
-rw-r--r--ucbhelper/source/provider/registerucb.cxx139
-rw-r--r--ucbhelper/source/provider/resultset.cxx1486
-rw-r--r--ucbhelper/source/provider/resultsethelper.cxx252
-rw-r--r--ucbhelper/source/provider/resultsetmetadata.cxx397
-rw-r--r--ucbhelper/source/provider/simpleauthenticationrequest.cxx147
-rw-r--r--ucbhelper/source/provider/simplecertificatevalidationrequest.cxx42
-rw-r--r--ucbhelper/source/provider/simpleinteractionrequest.cxx92
-rw-r--r--ucbhelper/source/provider/simpleioerrorrequest.cxx44
-rw-r--r--ucbhelper/source/provider/simpleioerrorrequest.hxx65
-rw-r--r--ucbhelper/source/provider/simplenameclashresolverequest.cxx157
26 files changed, 8774 insertions, 0 deletions
diff --git a/ucbhelper/source/client/activedatasink.cxx b/ucbhelper/source/client/activedatasink.cxx
new file mode 100644
index 0000000000..96e75f565b
--- /dev/null
+++ b/ucbhelper/source/client/activedatasink.cxx
@@ -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 .
+ */
+
+#include <ucbhelper/activedatasink.hxx>
+
+using namespace com::sun::star;
+
+namespace ucbhelper
+{
+// ActiveDataSink Implementation.
+// XActiveDataSink methods.
+
+// 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; }
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/activedatastreamer.cxx b/ucbhelper/source/client/activedatastreamer.cxx
new file mode 100644
index 0000000000..fe6be13536
--- /dev/null
+++ b/ucbhelper/source/client/activedatastreamer.cxx
@@ -0,0 +1,41 @@
+/* -*- 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 "activedatastreamer.hxx"
+
+using namespace com::sun::star;
+
+namespace ucbhelper
+{
+// ActiveDataStreamer Implementation.
+
+// XActiveDataStreamer methods.
+
+// virtual
+void SAL_CALL ActiveDataStreamer::setStream(const uno::Reference<io::XStream>& xStream)
+{
+ m_xStream = xStream;
+}
+
+// virtual
+uno::Reference<io::XStream> SAL_CALL ActiveDataStreamer::getStream() { return m_xStream; }
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/activedatastreamer.hxx b/ucbhelper/source/client/activedatastreamer.hxx
new file mode 100644
index 0000000000..84ee10ac96
--- /dev/null
+++ b/ucbhelper/source/client/activedatastreamer.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX
+#define UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX
+
+#include <com/sun/star/io/XActiveDataStreamer.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace ucbhelper
+{
+/**
+ * This class implements the interface css::io::XActiveDataStreamer.
+ * Instances of this class can be passed with the parameters of an
+ * "open" command.
+ */
+
+class ActiveDataStreamer final : public cppu::WeakImplHelper<css::io::XActiveDataStreamer>
+{
+ css::uno::Reference<css::io::XStream> m_xStream;
+
+public:
+ // XActiveDataStreamer methods.
+ virtual void SAL_CALL setStream(const css::uno::Reference<css::io::XStream>& xStream) override;
+ virtual css::uno::Reference<css::io::XStream> SAL_CALL getStream() override;
+};
+
+} /* namespace ucbhelper */
+
+#endif /* ! UCBHELPER_SOURCE_CLIENT_ACTIVEDATASTREAMER_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/commandenvironment.cxx b/ucbhelper/source/client/commandenvironment.cxx
new file mode 100644
index 0000000000..37956b2c46
--- /dev/null
+++ b/ucbhelper/source/client/commandenvironment.cxx
@@ -0,0 +1,77 @@
+/* -*- 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 <ucbhelper/commandenvironment.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::task;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+
+namespace com::sun::star::task { class XInteractionHandler; }
+namespace com::sun::star::ucb { class XProgressHandler; }
+
+namespace ucbhelper
+{
+// struct CommandEnvironment_Impl.
+
+struct CommandEnvironment_Impl
+{
+ Reference< XInteractionHandler > m_xInteractionHandler;
+ Reference< XProgressHandler > m_xProgressHandler;
+
+ CommandEnvironment_Impl( const Reference< XInteractionHandler >& rxInteractionHandler,
+ const Reference< XProgressHandler >& rxProgressHandler )
+ : m_xInteractionHandler( rxInteractionHandler )
+ , m_xProgressHandler( rxProgressHandler ) {}
+};
+
+// CommandEnvironment Implementation.
+
+CommandEnvironment::CommandEnvironment(
+ const Reference< XInteractionHandler >& rxInteractionHandler,
+ const Reference< XProgressHandler >& rxProgressHandler )
+ : m_pImpl( new CommandEnvironment_Impl( rxInteractionHandler,
+ rxProgressHandler ) )
+{
+}
+
+// virtual
+CommandEnvironment::~CommandEnvironment()
+{
+}
+
+// XCommandEnvironment methods.
+
+// virtual
+Reference< XInteractionHandler > SAL_CALL CommandEnvironment::getInteractionHandler()
+{
+ return m_pImpl->m_xInteractionHandler;
+}
+
+// virtual
+Reference< XProgressHandler > SAL_CALL CommandEnvironment::getProgressHandler()
+{
+ return m_pImpl->m_xProgressHandler;
+}
+
+} /* namespace ucbhelper */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/content.cxx b/ucbhelper/source/client/content.cxx
new file mode 100644
index 0000000000..8feab846ba
--- /dev/null
+++ b/ucbhelper/source/client/content.cxx
@@ -0,0 +1,1353 @@
+/* -*- 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 <cassert>
+
+#include <o3tl/unreachable.hxx>
+#include <osl/diagnose.h>
+#include <mutex>
+#include <sal/log.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/ucb/CheckinArgument.hpp>
+#include <com/sun/star/ucb/ContentCreationError.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/ucb/Command.hpp>
+#include <com/sun/star/ucb/ContentAction.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/ucb/XContentCreator.hpp>
+#include <com/sun/star/ucb/XContentEventListener.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp>
+#include <com/sun/star/ucb/UniversalContentBroker.hpp>
+#include <com/sun/star/ucb/XUniversalContentBroker.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <ucbhelper/content.hxx>
+#include <ucbhelper/activedatasink.hxx>
+#include "activedatastreamer.hxx"
+#include <ucbhelper/cancelcommandexecution.hxx>
+
+namespace com::sun::star::ucb { class XCommandEnvironment; }
+namespace com::sun::star::ucb { class XContentProvider; }
+namespace com::sun::star::sdbc { class XResultSet; }
+
+using namespace com::sun::star::container;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::task;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+
+namespace ucbhelper
+{
+
+namespace {
+
+class EmptyInputStream : public ::cppu::WeakImplHelper< XInputStream >
+{
+public:
+ virtual sal_Int32 SAL_CALL readBytes(
+ Sequence< sal_Int8 > & data, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes(
+ Sequence< sal_Int8 > & data, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available() override;
+ virtual void SAL_CALL closeInput() override;
+};
+
+}
+
+sal_Int32 EmptyInputStream::readBytes(
+ Sequence< sal_Int8 > & data, sal_Int32 )
+{
+ data.realloc( 0 );
+ return 0;
+}
+
+sal_Int32 EmptyInputStream::readSomeBytes(
+ Sequence< sal_Int8 > & data, sal_Int32 )
+{
+ data.realloc( 0 );
+ return 0;
+}
+
+void EmptyInputStream::skipBytes( sal_Int32 )
+{
+}
+
+sal_Int32 EmptyInputStream::available()
+{
+ return 0;
+}
+
+void EmptyInputStream::closeInput()
+{
+}
+
+
+
+namespace {
+
+class ContentEventListener_Impl : public cppu::OWeakObject,
+ public XContentEventListener
+{
+ Content_Impl& m_rContent;
+
+public:
+ explicit ContentEventListener_Impl( Content_Impl& rContent )
+ : m_rContent( rContent ) {}
+
+ // 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;
+
+ // XContentEventListener
+ virtual void SAL_CALL contentEvent( const ContentEvent& evt ) override;
+
+ // XEventListener ( base of XContentEventListener )
+ virtual void SAL_CALL disposing( const EventObject& Source ) override;
+};
+
+}
+
+
+
+class Content_Impl : public salhelper::SimpleReferenceObject
+{
+friend ContentEventListener_Impl;
+
+ mutable OUString m_aURL;
+ Reference< XComponentContext > m_xCtx;
+ Reference< XContent > m_xContent;
+ Reference< XCommandProcessor > m_xCommandProcessor;
+ Reference< XCommandEnvironment > m_xEnv;
+ Reference< XContentEventListener > m_xContentEventListener;
+ mutable std::mutex m_aMutex;
+
+private:
+ void reinit( const Reference< XContent >& xContent );
+ void disposing(const EventObject& Source);
+ const Reference< XContent > & getContent_NoLock();
+ const OUString& getURL_NoLock() const;
+
+public:
+ Content_Impl() {};
+ Content_Impl( const Reference< XComponentContext >& rCtx,
+ const Reference< XContent >& rContent,
+ const Reference< XCommandEnvironment >& rEnv );
+
+ virtual ~Content_Impl() override;
+
+ const OUString& getURL() const;
+ Reference< XContent > getContent();
+ Reference< XCommandProcessor > getCommandProcessor();
+ Reference< XComponentContext > const & getComponentContext() const
+ { assert(m_xCtx.is()); return m_xCtx; }
+
+ Any executeCommand( const Command& rCommand );
+
+ inline const Reference< XCommandEnvironment >& getEnvironment() const;
+ inline void setEnvironment(
+ const Reference< XCommandEnvironment >& xNewEnv );
+
+ void inserted();
+};
+
+
+// Helpers.
+
+/// @throws ContentCreationException
+/// @throws RuntimeException
+static void ensureContentProviderForURL( const Reference< XUniversalContentBroker >& rBroker,
+ const OUString & rURL )
+{
+ Reference< XContentProvider > xProv
+ = rBroker->queryContentProvider( rURL );
+ if ( !xProv.is() )
+ {
+ throw ContentCreationException(
+ "No Content Provider available for URL: " + rURL,
+ Reference< XInterface >(),
+ ContentCreationError_NO_CONTENT_PROVIDER );
+ }
+}
+
+/// @throws ContentCreationException
+/// @throws RuntimeException
+static Reference< XContentIdentifier > getContentIdentifierThrow(
+ const Reference< XUniversalContentBroker > & rBroker,
+ const OUString & rURL)
+{
+ Reference< XContentIdentifier > xId
+ = rBroker->createContentIdentifier( rURL );
+
+ if (!xId.is())
+ {
+ ensureContentProviderForURL( rBroker, rURL );
+
+ throw ContentCreationException(
+ "Unable to create Content Identifier!",
+ Reference< XInterface >(),
+ ContentCreationError_IDENTIFIER_CREATION_FAILED );
+ }
+
+ return xId;
+}
+
+/// @throws RuntimeException
+static Reference< XContentIdentifier > getContentIdentifierNoThrow(
+ const Reference< XUniversalContentBroker > & rBroker,
+ const OUString & rURL)
+{
+ return rBroker->createContentIdentifier(rURL);
+}
+
+/// @throws ContentCreationException
+/// @throws RuntimeException
+static Reference< XContent > getContentThrow(
+ const Reference< XUniversalContentBroker > & rBroker,
+ const Reference< XContentIdentifier > & xId)
+{
+ Reference< XContent > xContent;
+ OUString msg;
+ try
+ {
+ xContent = rBroker->queryContent( xId );
+ }
+ catch ( IllegalIdentifierException const & e )
+ {
+ msg = e.Message;
+ // handled below.
+ }
+
+ if ( !xContent.is() )
+ {
+ ensureContentProviderForURL( rBroker, xId->getContentIdentifier() );
+
+ throw ContentCreationException(
+ "Unable to create Content for <" + xId->getContentIdentifier() + ">: " + msg,
+ Reference< XInterface >(),
+ ContentCreationError_CONTENT_CREATION_FAILED );
+ }
+
+ return xContent;
+}
+
+/// @throws RuntimeException
+static Reference< XContent > getContentNoThrow(
+ const Reference< XUniversalContentBroker > & rBroker,
+ const Reference< XContentIdentifier > & xId)
+{
+ Reference< XContent > xContent;
+ try
+ {
+ xContent = rBroker->queryContent( xId );
+ }
+ catch ( IllegalIdentifierException const & e )
+ {
+ SAL_WARN("ucbhelper", "getContentNoThrow: " << e);
+ }
+
+ return xContent;
+}
+
+
+// Content Implementation.
+
+
+Content::Content()
+: m_xImpl( new Content_Impl )
+{
+}
+
+
+Content::Content( const OUString& rURL,
+ const Reference< XCommandEnvironment >& rEnv,
+ const Reference< XComponentContext >& rCtx )
+{
+ Reference< XUniversalContentBroker > pBroker(
+ UniversalContentBroker::create( rCtx ) );
+
+ Reference< XContentIdentifier > xId
+ = getContentIdentifierThrow(pBroker, rURL);
+
+ Reference< XContent > xContent = getContentThrow(pBroker, xId);
+
+ m_xImpl = new Content_Impl( rCtx, xContent, rEnv );
+}
+
+
+Content::Content( const Reference< XContent >& rContent,
+ const Reference< XCommandEnvironment >& rEnv,
+ const Reference< XComponentContext >& rCtx )
+{
+ m_xImpl = new Content_Impl( rCtx, rContent, rEnv );
+}
+
+
+Content::Content( const Content& rOther )
+{
+ m_xImpl = rOther.m_xImpl;
+}
+
+Content::Content( Content&& rOther ) noexcept
+{
+ m_xImpl = std::move(rOther.m_xImpl);
+}
+
+// static
+bool Content::create( const OUString& rURL,
+ const Reference< XCommandEnvironment >& rEnv,
+ const Reference< XComponentContext >& rCtx,
+ Content& rContent )
+{
+ Reference< XUniversalContentBroker > pBroker(
+ UniversalContentBroker::create( rCtx ) );
+
+ Reference< XContentIdentifier > xId
+ = getContentIdentifierNoThrow(pBroker, rURL);
+ if ( !xId.is() )
+ return false;
+
+ Reference< XContent > xContent = getContentNoThrow(pBroker, xId);
+ if ( !xContent.is() )
+ return false;
+
+ rContent.m_xImpl
+ = new Content_Impl( rCtx, xContent, rEnv );
+
+ return true;
+}
+
+
+Content::~Content()
+{
+}
+
+
+Content& Content::operator=( const Content& rOther )
+{
+ m_xImpl = rOther.m_xImpl;
+ return *this;
+}
+
+Content& Content::operator=( Content&& rOther ) noexcept
+{
+ m_xImpl = std::move(rOther.m_xImpl);
+ return *this;
+}
+
+Reference< XContent > Content::get() const
+{
+ return m_xImpl->getContent();
+}
+
+
+const OUString& Content::getURL() const
+{
+ return m_xImpl->getURL();
+}
+
+
+const Reference< XCommandEnvironment >& Content::getCommandEnvironment() const
+{
+ return m_xImpl->getEnvironment();
+}
+
+
+void Content::setCommandEnvironment(
+ const Reference< XCommandEnvironment >& xNewEnv )
+{
+ m_xImpl->setEnvironment( xNewEnv );
+}
+
+
+Reference< XCommandInfo > Content::getCommands()
+{
+ Command aCommand;
+ aCommand.Name = "getCommandInfo";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument = Any();
+
+ Any aResult = m_xImpl->executeCommand( aCommand );
+
+ Reference< XCommandInfo > xInfo;
+ aResult >>= xInfo;
+ return xInfo;
+}
+
+
+Reference< XPropertySetInfo > Content::getProperties()
+{
+ static constexpr OUStringLiteral sgetPropertySetInfo = u"getPropertySetInfo";
+ Command aCommand;
+ aCommand.Name = sgetPropertySetInfo;
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument = Any();
+
+ Any aResult = m_xImpl->executeCommand( aCommand );
+
+ Reference< XPropertySetInfo > xInfo;
+ aResult >>= xInfo;
+ return xInfo;
+}
+
+
+Any Content::getPropertyValue( const OUString& rPropertyName )
+{
+ Sequence<OUString> aNames { rPropertyName };
+
+ Sequence< Any > aRet = getPropertyValues( aNames );
+ return aRet.getConstArray()[ 0 ];
+}
+
+
+Any Content::setPropertyValue( const OUString& rName,
+ const Any& rValue )
+{
+ Sequence<OUString> aNames { rName };
+
+ Sequence< Any > aValues( 1 );
+ aValues.getArray()[ 0 ] = rValue;
+
+ Sequence< Any > aErrors = setPropertyValues( aNames, aValues );
+ return aErrors.getConstArray()[ 0 ];
+}
+
+
+Sequence< Any > Content::getPropertyValues(
+ const Sequence< OUString >& rPropertyNames )
+{
+ Reference< XRow > xRow = getPropertyValuesInterface( rPropertyNames );
+
+ sal_Int32 nCount = rPropertyNames.getLength();
+ Sequence< Any > aValues( nCount );
+
+ if ( xRow.is() )
+ {
+ Any* pValues = aValues.getArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ pValues[ n ] = xRow->getObject( n + 1, Reference< XNameAccess >() );
+ }
+
+ return aValues;
+}
+
+
+Reference< XRow > Content::getPropertyValuesInterface(
+ const Sequence< OUString >& rPropertyNames )
+{
+ sal_Int32 nCount = rPropertyNames.getLength();
+ Sequence< Property > aProps( nCount );
+ Property* pProps = aProps.getArray();
+
+ const OUString* pNames = rPropertyNames.getConstArray();
+
+ for ( sal_Int32 n = 0; n< nCount; ++n )
+ {
+ Property& rProp = pProps[ n ];
+
+ rProp.Name = pNames[ n ];
+ rProp.Handle = -1; // n/a
+// rProp.Type =
+// rProp.Attributes = ;
+ }
+
+ static constexpr OUStringLiteral sgetPropertyValues = u"getPropertyValues";
+ Command aCommand;
+ aCommand.Name = sgetPropertyValues;
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aProps;
+
+ Any aResult = m_xImpl->executeCommand( aCommand );
+
+ Reference< XRow > xRow;
+ aResult >>= xRow;
+ return xRow;
+}
+
+
+Sequence< Any > Content::setPropertyValues(
+ const Sequence< OUString >& rPropertyNames,
+ const Sequence< Any >& rValues )
+{
+ if ( rPropertyNames.getLength() != rValues.getLength() )
+ {
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ "Length of property names sequence and value "
+ "sequence are unequal!",
+ get(),
+ -1 ) ),
+ m_xImpl->getEnvironment() );
+ // Unreachable
+ }
+
+ sal_Int32 nCount = rValues.getLength();
+ Sequence< PropertyValue > aProps( nCount );
+ PropertyValue* pProps = aProps.getArray();
+
+ const OUString* pNames = rPropertyNames.getConstArray();
+ const Any* pValues = rValues.getConstArray();
+
+ for ( sal_Int32 n = 0; n< nCount; ++n )
+ {
+ PropertyValue& rProp = pProps[ n ];
+
+ rProp.Name = pNames[ n ];
+ rProp.Handle = -1; // n/a
+ rProp.Value = pValues[ n ];
+// rProp.State = ;
+ }
+
+ Command aCommand;
+ aCommand.Name = "setPropertyValues";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aProps;
+
+ Any aResult = m_xImpl->executeCommand( aCommand );
+
+ Sequence< Any > aErrors;
+ aResult >>= aErrors;
+ return aErrors;
+}
+
+
+Any Content::executeCommand( const OUString& rCommandName,
+ const Any& rCommandArgument )
+{
+ Command aCommand;
+ aCommand.Name = rCommandName;
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument = rCommandArgument;
+
+ return m_xImpl->executeCommand( aCommand );
+}
+
+
+Any Content::createCursorAny( const Sequence< OUString >& rPropertyNames,
+ ResultSetInclude eMode )
+{
+ sal_Int32 nCount = rPropertyNames.getLength();
+ Sequence< Property > aProps( nCount );
+ Property* pProps = aProps.getArray();
+ const OUString* pNames = rPropertyNames.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ Property& rProp = pProps[ n ];
+ rProp.Name = pNames[ n ];
+ rProp.Handle = -1; // n/a
+ }
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = ( eMode == INCLUDE_FOLDERS_ONLY )
+ ? OpenMode::FOLDERS
+ : ( eMode == INCLUDE_DOCUMENTS_ONLY )
+ ? OpenMode::DOCUMENTS : OpenMode::ALL;
+ aArg.Priority = 0; // unused
+ aArg.Sink.clear(); // unused
+ aArg.Properties = aProps;
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ return m_xImpl->executeCommand( aCommand );
+}
+
+
+Reference< XResultSet > Content::createCursor(
+ const Sequence< OUString >& rPropertyNames,
+ ResultSetInclude eMode )
+{
+ Any aCursorAny = createCursorAny( rPropertyNames, eMode );
+
+ Reference< XDynamicResultSet > xDynSet;
+ Reference< XResultSet > aResult;
+
+ aCursorAny >>= xDynSet;
+ if ( xDynSet.is() )
+ aResult = xDynSet->getStaticResultSet();
+
+ OSL_ENSURE( aResult.is(), "Content::createCursor - no cursor!" );
+
+ if ( !aResult.is() )
+ {
+ // Former, the open command directly returned a XResultSet.
+ aCursorAny >>= aResult;
+
+ OSL_ENSURE( !aResult.is(),
+ "Content::createCursor - open-Command must "
+ "return a Reference< XDynnamicResultSet >!" );
+ }
+
+ return aResult;
+}
+
+
+Reference< XDynamicResultSet > Content::createDynamicCursor(
+ const Sequence< OUString >& rPropertyNames,
+ ResultSetInclude eMode )
+{
+ Reference< XDynamicResultSet > aResult;
+ createCursorAny( rPropertyNames, eMode ) >>= aResult;
+
+ OSL_ENSURE( aResult.is(), "Content::createDynamicCursor - no cursor!" );
+
+ return aResult;
+}
+
+
+Reference< XResultSet > Content::createSortedCursor(
+ const Sequence< OUString >& rPropertyNames,
+ const Sequence< NumberedSortingInfo >& rSortInfo,
+ const Reference< XAnyCompareFactory >& rAnyCompareFactory,
+ ResultSetInclude eMode )
+{
+ Reference< XResultSet > aResult;
+ Reference< XDynamicResultSet > aDynSet;
+
+ Any aCursorAny = createCursorAny( rPropertyNames, eMode );
+
+ aCursorAny >>= aDynSet;
+
+ if( aDynSet.is() )
+ {
+ Reference< XDynamicResultSet > aDynResult;
+
+ if( m_xImpl->getComponentContext().is() )
+ {
+ Reference< XSortedDynamicResultSetFactory > aSortFactory =
+ SortedDynamicResultSetFactory::create( m_xImpl->getComponentContext());
+
+ aDynResult = aSortFactory->createSortedDynamicResultSet( aDynSet,
+ rSortInfo,
+ rAnyCompareFactory );
+ }
+
+ OSL_ENSURE( aDynResult.is(), "Content::createSortedCursor - no sorted cursor!" );
+
+ if( aDynResult.is() )
+ aResult = aDynResult->getStaticResultSet();
+ else
+ aResult = aDynSet->getStaticResultSet();
+ }
+
+ OSL_ENSURE( aResult.is(), "Content::createSortedCursor - no cursor!" );
+
+ if ( !aResult.is() )
+ {
+ // Former, the open command directly returned a XResultSet.
+ aCursorAny >>= aResult;
+
+ OSL_ENSURE( !aResult.is(),
+ "Content::createCursor - open-Command must "
+ "return a Reference< XDynnamicResultSet >!" );
+ }
+
+ return aResult;
+}
+
+
+Reference< XInputStream > Content::openStream()
+{
+ if ( !isDocument() )
+ return Reference< XInputStream >();
+
+ Reference< XActiveDataSink > xSink = new ActiveDataSink;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xSink;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return xSink->getInputStream();
+}
+
+
+Reference< XInputStream > Content::openStreamNoLock()
+{
+ if ( !isDocument() )
+ return Reference< XInputStream >();
+
+ Reference< XActiveDataSink > xSink = new ActiveDataSink;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xSink;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return xSink->getInputStream();
+}
+
+
+Reference< XStream > Content::openWriteableStream()
+{
+ if ( !isDocument() )
+ return Reference< XStream >();
+
+ Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xStreamer;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return xStreamer->getStream();
+}
+
+
+Reference< XStream > Content::openWriteableStreamNoLock()
+{
+ if ( !isDocument() )
+ return Reference< XStream >();
+
+ Reference< XActiveDataStreamer > xStreamer = new ActiveDataStreamer;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT_SHARE_DENY_NONE;
+ aArg.Priority = 0; // unused
+ aArg.Sink = xStreamer;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return xStreamer->getStream();
+}
+
+
+bool Content::openStream( const Reference< XActiveDataSink >& rSink )
+{
+ if ( !isDocument() )
+ return false;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = rSink;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return true;
+}
+
+
+bool Content::openStream( const Reference< XOutputStream >& rStream )
+{
+ if ( !isDocument() )
+ return false;
+
+ OpenCommandArgument2 aArg;
+ aArg.Mode = OpenMode::DOCUMENT;
+ aArg.Priority = 0; // unused
+ aArg.Sink = rStream;
+ aArg.Properties = Sequence< Property >( 0 ); // unused
+
+ Command aCommand;
+ aCommand.Name = "open";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ return true;
+}
+
+
+void Content::writeStream( const Reference< XInputStream >& rStream,
+ bool bReplaceExisting )
+{
+ InsertCommandArgument aArg;
+ aArg.Data = rStream.is() ? rStream : new EmptyInputStream;
+ aArg.ReplaceExisting = bReplaceExisting;
+
+ Command aCommand;
+ aCommand.Name = "insert";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aArg;
+
+ m_xImpl->executeCommand( aCommand );
+
+ m_xImpl->inserted();
+}
+
+
+Sequence< ContentInfo > Content::queryCreatableContentsInfo()
+{
+ // First, try it using "CreatableContentsInfo" property -> the "new" way.
+ Sequence< ContentInfo > aInfo;
+ if ( getPropertyValue(
+ "CreatableContentsInfo" )
+ >>= aInfo )
+ return aInfo;
+
+ // Second, try it using XContentCreator interface -> the "old" way (not
+ // providing the chance to supply an XCommandEnvironment.
+ Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY );
+ if ( xCreator.is() )
+ aInfo = xCreator->queryCreatableContentsInfo();
+
+ return aInfo;
+}
+
+
+bool Content::insertNewContent( const OUString& rContentType,
+ const Sequence< OUString >&
+ rPropertyNames,
+ const Sequence< Any >& rPropertyValues,
+ Content& rNewContent )
+{
+ return insertNewContent( rContentType,
+ rPropertyNames,
+ rPropertyValues,
+ new EmptyInputStream,
+ rNewContent );
+}
+
+
+bool Content::insertNewContent( const OUString& rContentType,
+ const Sequence< OUString >&
+ rPropertyNames,
+ const Sequence< Any >& rPropertyValues,
+ const Reference< XInputStream >& rData,
+ Content& rNewContent )
+{
+ if ( rContentType.isEmpty() )
+ return false;
+
+ // First, try it using "createNewContent" command -> the "new" way.
+ ContentInfo aInfo;
+ aInfo.Type = rContentType;
+ aInfo.Attributes = 0;
+
+ Command aCommand;
+ aCommand.Name = "createNewContent";
+ aCommand.Handle = -1; // n/a
+ aCommand.Argument <<= aInfo;
+
+ Reference< XContent > xNew;
+ try
+ {
+ m_xImpl->executeCommand( aCommand ) >>= xNew;
+ }
+ catch ( RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( Exception const & )
+ {
+ }
+
+ if ( !xNew.is() )
+ {
+ // Second, try it using XContentCreator interface -> the "old"
+ // way (not providing the chance to supply an XCommandEnvironment.
+ Reference< XContentCreator > xCreator( m_xImpl->getContent(), UNO_QUERY );
+
+ if ( !xCreator.is() )
+ return false;
+
+ xNew = xCreator->createNewContent( aInfo );
+
+ if ( !xNew.is() )
+ return false;
+ }
+
+ Content aNewContent(
+ xNew, m_xImpl->getEnvironment(), m_xImpl->getComponentContext() );
+ aNewContent.setPropertyValues( rPropertyNames, rPropertyValues );
+ aNewContent.executeCommand( "insert",
+ Any(
+ InsertCommandArgument(
+ rData.is() ? rData : new EmptyInputStream,
+ false /* ReplaceExisting */ ) ) );
+ aNewContent.m_xImpl->inserted();
+
+ rNewContent = aNewContent;
+ return true;
+}
+
+
+void Content::transferContent( const Content& rSourceContent,
+ InsertOperation eOperation,
+ const OUString & rTitle,
+ const sal_Int32 nNameClashAction,
+ const OUString & rMimeType,
+ bool bMajorVersion,
+ const OUString & rVersionComment,
+ OUString* pResultURL,
+ const OUString & rDocumentId ) const
+{
+ Reference< XUniversalContentBroker > pBroker(
+ UniversalContentBroker::create( m_xImpl->getComponentContext() ) );
+
+ // Execute command "globalTransfer" at UCB.
+
+ TransferCommandOperation eTransOp = TransferCommandOperation();
+ OUString sCommand( "globalTransfer" );
+ bool bCheckIn = false;
+ switch ( eOperation )
+ {
+ case InsertOperation::Copy:
+ eTransOp = TransferCommandOperation_COPY;
+ break;
+
+ case InsertOperation::Move:
+ eTransOp = TransferCommandOperation_MOVE;
+ break;
+
+ case InsertOperation::Checkin:
+ eTransOp = TransferCommandOperation_COPY;
+ sCommand = "checkin";
+ bCheckIn = true;
+ break;
+ }
+ Command aCommand;
+ aCommand.Name = sCommand;
+ aCommand.Handle = -1; // n/a
+
+ if ( !bCheckIn )
+ {
+ GlobalTransferCommandArgument2 aTransferArg(
+ eTransOp,
+ rSourceContent.getURL(), // SourceURL
+ getURL(), // TargetFolderURL,
+ rTitle,
+ nNameClashAction,
+ rMimeType,
+ rDocumentId );
+ aCommand.Argument <<= aTransferArg;
+ }
+ else
+ {
+ CheckinArgument aCheckinArg( bMajorVersion, rVersionComment,
+ rSourceContent.getURL(), getURL(), rTitle, rMimeType );
+ aCommand.Argument <<= aCheckinArg;
+ }
+
+ Any aRet = pBroker->execute( aCommand, 0, m_xImpl->getEnvironment() );
+ if ( pResultURL != nullptr )
+ aRet >>= *pResultURL;
+}
+
+
+bool Content::isFolder()
+{
+ bool bFolder = false;
+ if ( getPropertyValue("IsFolder")
+ >>= bFolder )
+ return bFolder;
+
+ ucbhelper::cancelCommandExecution(
+ Any( UnknownPropertyException(
+ "Unable to retrieve value of property 'IsFolder'!",
+ get() ) ),
+ m_xImpl->getEnvironment() );
+
+ O3TL_UNREACHABLE;
+}
+
+
+bool Content::isDocument()
+{
+ bool bDoc = false;
+ if ( getPropertyValue("IsDocument")
+ >>= bDoc )
+ return bDoc;
+
+ ucbhelper::cancelCommandExecution(
+ Any( UnknownPropertyException(
+ "Unable to retrieve value of property 'IsDocument'!",
+ get() ) ),
+ m_xImpl->getEnvironment() );
+
+ O3TL_UNREACHABLE;
+}
+
+void Content::lock()
+{
+ Command aCommand;
+ aCommand.Name = "lock";
+ aCommand.Handle = -1; // n/a
+
+ m_xImpl->executeCommand( aCommand );
+
+}
+
+void Content::unlock()
+{
+
+ Command aCommand;
+ aCommand.Name = "unlock";
+ aCommand.Handle = -1; // n/a
+
+ m_xImpl->executeCommand( aCommand );
+
+}
+
+
+// Content_Impl Implementation.
+
+
+Content_Impl::Content_Impl( const Reference< XComponentContext >& rCtx,
+ const Reference< XContent >& rContent,
+ const Reference< XCommandEnvironment >& rEnv )
+: m_xCtx( rCtx ),
+ m_xContent( rContent ),
+ m_xEnv( rEnv )
+{
+ assert(rCtx.is());
+ if ( m_xContent.is() )
+ {
+ m_xContentEventListener = new ContentEventListener_Impl( *this );
+ m_xContent->addContentEventListener( m_xContentEventListener );
+
+#if OSL_DEBUG_LEVEL > 0
+ // Only done on demand in product version for performance reasons,
+ // but a nice debug helper.
+ getURL();
+#endif
+ }
+}
+
+
+void Content_Impl::reinit( const Reference< XContent >& xContent )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ m_xCommandProcessor = nullptr;
+
+ // #92581# - Don't reset m_aURL!!!
+
+ if ( m_xContent.is() )
+ {
+ try
+ {
+ m_xContent->removeContentEventListener( m_xContentEventListener );
+ }
+ catch ( RuntimeException const & )
+ {
+ }
+ }
+
+ if ( xContent.is() )
+ {
+ m_xContent = xContent;
+ m_xContent->addContentEventListener( m_xContentEventListener );
+
+#if OSL_DEBUG_LEVEL > 0
+ // Only done on demand in product version for performance reasons,
+ // but a nice debug helper.
+ getURL_NoLock();
+#endif
+ }
+ else
+ {
+ // We need m_xContent's URL in order to be able to create the
+ // content object again if demanded ( --> Content_Impl::getContent() )
+ getURL_NoLock();
+
+ m_xContent = nullptr;
+ }
+}
+
+
+// virtual
+Content_Impl::~Content_Impl()
+{
+ if ( m_xContent.is() )
+ {
+ try
+ {
+ m_xContent->removeContentEventListener( m_xContentEventListener );
+ }
+ catch ( RuntimeException const & )
+ {
+ }
+ }
+}
+
+
+void Content_Impl::disposing( const EventObject& Source )
+{
+ Reference<XContent> xContent;
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if(Source.Source != m_xContent)
+ return;
+
+ xContent = m_xContent;
+
+ m_aURL.clear();
+ m_xCommandProcessor = nullptr;
+ m_xContent = nullptr;
+ }
+
+ if ( xContent.is() )
+ {
+ try
+ {
+ xContent->removeContentEventListener( m_xContentEventListener );
+ }
+ catch ( RuntimeException const & )
+ {
+ }
+ }
+}
+
+
+const OUString& Content_Impl::getURL() const
+{
+ if ( m_aURL.isEmpty() && m_xContent.is() )
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ return getURL_NoLock();
+ }
+
+ return m_aURL;
+}
+
+const OUString& Content_Impl::getURL_NoLock() const
+{
+ if ( m_aURL.isEmpty() && m_xContent.is() )
+ {
+ Reference< XContentIdentifier > xId = m_xContent->getIdentifier();
+ if ( xId.is() )
+ m_aURL = xId->getContentIdentifier();
+ }
+
+ return m_aURL;
+}
+
+Reference< XContent > Content_Impl::getContent()
+{
+ if ( !m_xContent.is() && !m_aURL.isEmpty() )
+ {
+ std::unique_lock aGuard( m_aMutex );
+ return getContent_NoLock();
+ }
+ return m_xContent;
+}
+
+const Reference< XContent > & Content_Impl::getContent_NoLock()
+{
+ if ( !m_xContent.is() && !m_aURL.isEmpty() )
+ {
+ Reference< XUniversalContentBroker > pBroker(
+ UniversalContentBroker::create( getComponentContext() ) );
+
+ OSL_ENSURE( pBroker->queryContentProviders().hasElements(),
+ "Content Broker not configured (no providers)!" );
+
+ Reference< XContentIdentifier > xId
+ = pBroker->createContentIdentifier( m_aURL );
+
+ OSL_ENSURE( xId.is(), "No Content Identifier!" );
+
+ if ( xId.is() )
+ {
+ try
+ {
+ m_xContent = pBroker->queryContent( xId );
+ }
+ catch ( IllegalIdentifierException const & )
+ {
+ }
+
+ if ( m_xContent.is() )
+ m_xContent->addContentEventListener(
+ m_xContentEventListener );
+ }
+ }
+
+ return m_xContent;
+}
+
+
+Reference< XCommandProcessor > Content_Impl::getCommandProcessor()
+{
+ if ( !m_xCommandProcessor.is() )
+ {
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( !m_xCommandProcessor.is() )
+ m_xCommandProcessor.set( getContent_NoLock(), UNO_QUERY );
+ }
+
+ return m_xCommandProcessor;
+}
+
+
+Any Content_Impl::executeCommand( const Command& rCommand )
+{
+ Reference< XCommandProcessor > xProc = getCommandProcessor();
+ if ( !xProc.is() )
+ return Any();
+
+ // Execute command
+ return xProc->execute( rCommand, 0, m_xEnv );
+}
+
+
+inline const Reference< XCommandEnvironment >&
+ Content_Impl::getEnvironment() const
+{
+ return m_xEnv;
+}
+
+
+inline void Content_Impl::setEnvironment(
+ const Reference< XCommandEnvironment >& xNewEnv )
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_xEnv = xNewEnv;
+}
+
+
+void Content_Impl::inserted()
+{
+ // URL might have changed during 'insert' => recalculate in next getURL()
+ std::unique_lock aGuard( m_aMutex );
+ m_aURL.clear();
+}
+
+
+// ContentEventListener_Impl Implementation.
+
+
+// XInterface methods.
+
+void SAL_CALL ContentEventListener_Impl::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ContentEventListener_Impl::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+css::uno::Any SAL_CALL ContentEventListener_Impl::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< XContentEventListener* >(this),
+ static_cast< XEventListener* >(this)
+ );
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+}
+
+// XContentEventListener methods.
+
+
+// virtual
+void SAL_CALL ContentEventListener_Impl::contentEvent( const ContentEvent& evt )
+{
+ if ( evt.Source != m_rContent.m_xContent )
+ return;
+
+ switch ( evt.Action )
+ {
+ case ContentAction::DELETED:
+ m_rContent.reinit( Reference< XContent >() );
+ break;
+
+ case ContentAction::EXCHANGED:
+ m_rContent.reinit( evt.Content );
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+// XEventListenr methods.
+
+
+// virtual
+void SAL_CALL ContentEventListener_Impl::disposing( const EventObject& Source )
+{
+ m_rContent.disposing(Source);
+}
+
+} /* namespace ucbhelper */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/interceptedinteraction.cxx b/ucbhelper/source/client/interceptedinteraction.cxx
new file mode 100644
index 0000000000..96b3fd32cb
--- /dev/null
+++ b/ucbhelper/source/client/interceptedinteraction.cxx
@@ -0,0 +1,138 @@
+/* -*- 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 <ucbhelper/interceptedinteraction.hxx>
+
+#include <osl/diagnose.h>
+
+namespace ucbhelper{
+
+InterceptedInteraction::InterceptedInteraction()
+{
+}
+
+void InterceptedInteraction::setInterceptedHandler(const css::uno::Reference< css::task::XInteractionHandler >& xInterceptedHandler)
+{
+ m_xInterceptedHandler = xInterceptedHandler;
+}
+
+void InterceptedInteraction::setInterceptions(::std::vector< InterceptedRequest >&& lInterceptions)
+{
+ m_lInterceptions = std::move(lInterceptions);
+}
+
+InterceptedInteraction::EInterceptionState InterceptedInteraction::intercepted(
+ const InterceptedRequest&,
+ const css::uno::Reference< css::task::XInteractionRequest >&)
+{
+ // default behaviour! see impl_interceptRequest() for further information ...
+ return E_NOT_INTERCEPTED;
+}
+
+css::uno::Reference< css::task::XInteractionContinuation > InterceptedInteraction::extractContinuation(const css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >& lContinuations,
+ const css::uno::Type& aType )
+{
+ const css::uno::Reference< css::task::XInteractionContinuation >* pContinuations = std::find_if(lContinuations.begin(), lContinuations.end(),
+ [&aType](const css::uno::Reference< css::task::XInteractionContinuation >& rContinuation) {
+ css::uno::Reference< css::uno::XInterface > xCheck(rContinuation, css::uno::UNO_QUERY);
+ return xCheck->queryInterface(aType).hasValue();
+ });
+ if (pContinuations != lContinuations.end())
+ return *pContinuations;
+
+ return css::uno::Reference< css::task::XInteractionContinuation >();
+}
+
+void SAL_CALL InterceptedInteraction::handle(const css::uno::Reference< css::task::XInteractionRequest >& xRequest)
+{
+ impl_handleDefault(xRequest);
+}
+
+void InterceptedInteraction::impl_handleDefault(const css::uno::Reference< css::task::XInteractionRequest >& xRequest)
+{
+ EInterceptionState eState = impl_interceptRequest(xRequest);
+
+ switch(eState)
+ {
+ case E_NOT_INTERCEPTED:
+ {
+ // Non of the intercepted requests match to the given one.
+ // => forward request to the internal wrapped handler - if there is one.
+ if (m_xInterceptedHandler.is())
+ m_xInterceptedHandler->handle(xRequest);
+ }
+ break;
+
+ case E_NO_CONTINUATION_FOUND:
+ {
+ // Runtime error! The defined continuation could not be located
+ // inside the set of available continuations of the incoming request.
+ // What's wrong - the interception list or the request?
+ OSL_FAIL("InterceptedInteraction::handle()\nCould intercept this interaction request - but can't locate the right continuation!");
+ }
+ break;
+
+ case E_INTERCEPTED:
+ break;
+ }
+}
+
+InterceptedInteraction::EInterceptionState InterceptedInteraction::impl_interceptRequest(const css::uno::Reference< css::task::XInteractionRequest >& xRequest)
+{
+ css::uno::Any aRequest = xRequest->getRequest();
+ const css::uno::Type& aRequestType = aRequest.getValueType();
+ css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > lContinuations = xRequest->getContinuations();
+
+ // check against the list of static requests
+ auto pIt = std::find_if(m_lInterceptions.begin(), m_lInterceptions.end(),
+ [&aRequestType](const InterceptedRequest& rInterception) {
+ // check the request
+ // don't change intercepted and request type here -> it will check the wrong direction!
+ return rInterception.Request.getValueType().isAssignableFrom(aRequestType);
+ });
+
+ if (pIt != m_lInterceptions.end()) // intercepted ...
+ {
+ const InterceptedRequest& rInterception = *pIt;
+
+ // Call they might existing derived class, so they can handle that by its own.
+ // If it's not interested on that (maybe it's not overwritten and the default implementation
+ // returns E_NOT_INTERCEPTED as default) -> search required continuation
+ EInterceptionState eState = intercepted(rInterception, xRequest);
+ if (eState != E_NOT_INTERCEPTED)
+ return eState;
+
+ css::uno::Reference< css::task::XInteractionContinuation > xContinuation = InterceptedInteraction::extractContinuation(lContinuations, rInterception.Continuation);
+ if (xContinuation.is())
+ {
+ xContinuation->select();
+ return E_INTERCEPTED;
+ }
+
+ // Can be reached only, if the request does not support the given continuation!
+ // => RuntimeError!?
+ return E_NO_CONTINUATION_FOUND;
+ }
+
+ return E_NOT_INTERCEPTED;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/client/proxydecider.cxx b/ucbhelper/source/client/proxydecider.cxx
new file mode 100644
index 0000000000..8acc15716a
--- /dev/null
+++ b/ucbhelper/source/client/proxydecider.cxx
@@ -0,0 +1,916 @@
+/* -*- 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 <string_view>
+#include <utility>
+#include <vector>
+#include <deque>
+
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+#include <osl/socket.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <ucbhelper/proxydecider.hxx>
+#include <o3tl/string_view.hxx>
+
+#ifdef _WIN32
+#include <o3tl/char16_t2wchar_t.hxx>
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <Winhttp.h>
+#include <process.h>
+#endif
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+constexpr OUString CONFIG_ROOT_KEY = u"org.openoffice.Inet/Settings"_ustr;
+constexpr OUString PROXY_TYPE_KEY = u"ooInetProxyType"_ustr;
+constexpr OUString NO_PROXY_LIST_KEY = u"ooInetNoProxy"_ustr;
+constexpr OUString HTTP_PROXY_NAME_KEY = u"ooInetHTTPProxyName"_ustr;
+constexpr OUString HTTP_PROXY_PORT_KEY = u"ooInetHTTPProxyPort"_ustr;
+constexpr OUString HTTPS_PROXY_NAME_KEY = u"ooInetHTTPSProxyName"_ustr;
+constexpr OUString HTTPS_PROXY_PORT_KEY = u"ooInetHTTPSProxyPort"_ustr;
+
+
+namespace ucbhelper
+{
+
+
+namespace proxydecider_impl
+{
+
+namespace {
+
+// A simple case ignoring wildcard matcher.
+class WildCard
+{
+private:
+ OString m_aWildString;
+
+public:
+ explicit WildCard( std::u16string_view rWildCard )
+ : m_aWildString(
+ OUStringToOString(
+ rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
+
+ bool Matches( std::u16string_view rStr ) const;
+};
+
+}
+
+namespace {
+
+class HostnameCache
+{
+ typedef std::pair< OUString, OUString > HostListEntry;
+
+ std::deque< HostListEntry > m_aHostList;
+
+public:
+ bool get( std::u16string_view rKey, OUString & rValue ) const
+ {
+ for (auto const& host : m_aHostList)
+ {
+ if ( host.first == rKey )
+ {
+ rValue = host.second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void put( const OUString & rKey, const OUString & rValue )
+ {
+ static constexpr sal_uInt32 nCapacity = 256;
+
+ if ( m_aHostList.size() == nCapacity )
+ m_aHostList.resize( nCapacity / 2 );
+
+ m_aHostList.push_front( HostListEntry( rKey, rValue ) );
+ }
+};
+
+}
+
+class InternetProxyDecider_Impl :
+ public cppu::WeakImplHelper< util::XChangesListener >
+{
+ // see officecfg/registry/schema/org/openoffice/Inet.xcs for the definition of these values
+ enum class ProxyType { NoProxy, Automatic, Manual };
+ mutable osl::Mutex m_aMutex;
+ InternetProxyServer m_aHttpProxy;
+ InternetProxyServer m_aHttpsProxy;
+ const InternetProxyServer m_aEmptyProxy;
+ ProxyType m_nProxyType;
+ uno::Reference< util::XChangesNotifier > m_xNotifier;
+ typedef std::pair< WildCard, WildCard > NoProxyListEntry;
+ std::vector< NoProxyListEntry > m_aNoProxyList;
+ mutable HostnameCache m_aHostnames;
+
+private:
+ bool shouldUseProxy( std::u16string_view rHost,
+ sal_Int32 nPort,
+ bool bUseFullyQualified ) const;
+public:
+ explicit InternetProxyDecider_Impl(
+ const uno::Reference< uno::XComponentContext >& rxContext );
+
+ void dispose();
+
+ InternetProxyServer getProxy(const OUString& rProtocol,
+ const OUString & rHost,
+ sal_Int32 nPort ) const;
+
+ // XChangesListener
+ virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event ) override;
+
+ // XEventListener ( base of XChangesLisetenr )
+ virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
+
+private:
+ void setNoProxyList( const OUString & rNoProxyList );
+};
+
+
+// WildCard Implementation.
+
+
+bool WildCard::Matches( std::u16string_view rString ) const
+{
+ OString aString
+ = OUStringToOString( rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
+ const char * pStr = aString.getStr();
+ const char * pWild = m_aWildString.getStr();
+
+ int pos = 0;
+ int flag = 0;
+
+ while ( *pWild || flag )
+ {
+ switch ( *pWild )
+ {
+ case '?':
+ if ( *pStr == '\0' )
+ return false;
+ break;
+
+ default:
+ if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
+ || ( *( pWild + 1 ) == '*') ) )
+ pWild++;
+ if ( *pWild != *pStr )
+ if ( !pos )
+ return false;
+ else
+ pWild += pos;
+ else
+ break;
+
+ [[fallthrough]];
+
+ case '*':
+ while ( *pWild == '*' )
+ pWild++;
+ if ( *pWild == '\0' )
+ return true;
+ flag = 1;
+ pos = 0;
+ if ( *pStr == '\0' )
+ return ( *pWild == '\0' );
+ while ( *pStr && *pStr != *pWild )
+ {
+ if ( *pWild == '?' ) {
+ pWild++;
+ while ( *pWild == '*' )
+ pWild++;
+ }
+ pStr++;
+ if ( *pStr == '\0' )
+ return ( *pWild == '\0' );
+ }
+ break;
+ }
+ if ( *pWild != '\0' )
+ pWild++;
+ if ( *pStr != '\0' )
+ pStr++;
+ else
+ flag = 0;
+ if ( flag )
+ pos--;
+ }
+ return ( *pStr == '\0' ) && ( *pWild == '\0' );
+}
+
+
+static bool getConfigStringValue(
+ const uno::Reference< container::XNameAccess > & xNameAccess,
+ const OUString& key,
+ OUString & value )
+{
+ try
+ {
+ if ( !( xNameAccess->getByName( key ) >>= value ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - "
+ "Error getting config item value!" );
+ return false;
+ }
+ }
+ catch ( lang::WrappedTargetException const & )
+ {
+ return false;
+ }
+ catch ( container::NoSuchElementException const & )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+static bool getConfigInt32Value(
+ const uno::Reference< container::XNameAccess > & xNameAccess,
+ const OUString& key,
+ sal_Int32 & value )
+{
+ try
+ {
+ uno::Any aValue = xNameAccess->getByName( key );
+ if ( aValue.hasValue() && !( aValue >>= value ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - "
+ "Error getting config item value!" );
+ return false;
+ }
+ }
+ catch ( lang::WrappedTargetException const & )
+ {
+ return false;
+ }
+ catch ( container::NoSuchElementException const & )
+ {
+ return false;
+ }
+ return true;
+}
+
+
+// InternetProxyDecider_Impl Implementation.
+
+
+InternetProxyDecider_Impl::InternetProxyDecider_Impl(
+ const uno::Reference< uno::XComponentContext >& rxContext )
+ : m_nProxyType( ProxyType::NoProxy ),
+ m_aHostnames()
+{
+ try
+ {
+
+ // Read proxy configuration from config db.
+
+
+ uno::Reference< lang::XMultiServiceFactory > xConfigProv =
+ configuration::theDefaultProvider::get( rxContext );
+
+ uno::Sequence< uno::Any > aArguments{ uno::Any(CONFIG_ROOT_KEY) };
+ uno::Reference< uno::XInterface > xInterface(
+ xConfigProv->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments ) );
+
+ OSL_ENSURE( xInterface.is(),
+ "InternetProxyDecider - No config access!" );
+
+ if ( xInterface.is() )
+ {
+ uno::Reference< container::XNameAccess > xNameAccess(
+ xInterface, uno::UNO_QUERY );
+ OSL_ENSURE( xNameAccess.is(),
+ "InternetProxyDecider - No name access!" );
+
+ if ( xNameAccess.is() )
+ {
+ // *** Proxy type ***
+ sal_Int32 tmp = 0;
+ getConfigInt32Value(
+ xNameAccess, PROXY_TYPE_KEY, tmp );
+ m_nProxyType = static_cast<ProxyType>(tmp);
+
+ // *** No proxy list ***
+ OUString aNoProxyList;
+ getConfigStringValue(
+ xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
+ setNoProxyList( aNoProxyList );
+
+ // *** HTTP ***
+ getConfigStringValue(
+ xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
+
+ m_aHttpProxy.nPort = -1;
+ getConfigInt32Value(
+ xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
+ if ( m_aHttpProxy.nPort == -1 )
+ m_aHttpProxy.nPort = 80; // standard HTTP port.
+
+ // *** HTTPS ***
+ getConfigStringValue(
+ xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
+
+ m_aHttpsProxy.nPort = -1;
+ getConfigInt32Value(
+ xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
+ if ( m_aHttpsProxy.nPort == -1 )
+ m_aHttpsProxy.nPort = 443; // standard HTTPS port.
+ }
+
+ // Register as listener for config changes.
+
+ m_xNotifier.set( xInterface, uno::UNO_QUERY );
+
+ OSL_ENSURE( m_xNotifier.is(),
+ "InternetProxyDecider - No notifier!" );
+
+ if ( m_xNotifier.is() )
+ m_xNotifier->addChangesListener( this );
+ }
+ }
+ catch ( uno::Exception const & )
+ {
+ // createInstance, createInstanceWithArguments
+ OSL_FAIL( "InternetProxyDecider - Exception!" );
+ }
+}
+
+void InternetProxyDecider_Impl::dispose()
+{
+ uno::Reference< util::XChangesNotifier > xNotifier;
+
+ if ( m_xNotifier.is() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( m_xNotifier.is() )
+ {
+ xNotifier = m_xNotifier;
+ m_xNotifier.clear();
+ }
+ }
+
+ // Do this unguarded!
+ if ( xNotifier.is() )
+ xNotifier->removeChangesListener( this );
+}
+
+
+bool InternetProxyDecider_Impl::shouldUseProxy( std::u16string_view rHost,
+ sal_Int32 nPort,
+ bool bUseFullyQualified ) const
+{
+ OUStringBuffer aBuffer;
+
+ if ( ( rHost.find( ':' ) != std::u16string_view::npos ) &&
+ ( rHost[ 0 ] != '[' ) )
+ {
+ // host is given as numeric IPv6 address
+ aBuffer.append( OUString::Concat("[") + rHost + "]" );
+ }
+ else
+ {
+ // host is given either as numeric IPv4 address or non-numeric hostname
+ aBuffer.append( rHost );
+ }
+
+ aBuffer.append( ":" + OUString::number( nPort ) );
+
+ for (auto const& noProxy : m_aNoProxyList)
+ {
+ if ( bUseFullyQualified )
+ {
+ if ( noProxy.second.Matches( aBuffer ) )
+ return false;
+ }
+ else
+ {
+ if ( noProxy.first.Matches( aBuffer ) )
+ return false;
+ }
+ }
+
+ return true;
+}
+
+namespace
+{
+#ifdef _WIN32
+struct GetPACProxyData
+{
+ const OUString& m_rProtocol;
+ const OUString& m_rHost;
+ sal_Int32 m_nPort;
+ bool m_bAutoDetect = false;
+ OUString m_sAutoConfigUrl;
+ InternetProxyServer m_ProxyServer;
+
+ GetPACProxyData(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
+ : m_rProtocol(rProtocol)
+ , m_rHost(rHost)
+ , m_nPort(nPort)
+ {
+ }
+};
+
+// Tries to get proxy configuration using WinHttpGetProxyForUrl, which supports Web Proxy Auto-Discovery
+// (WPAD) protocol and manually configured address to get Proxy Auto-Configuration (PAC) file.
+// The WinINet/WinHTTP functions cannot correctly run in a STA COM thread, so use a dedicated thread
+unsigned __stdcall GetPACProxyThread(void* lpParameter)
+{
+ assert(lpParameter);
+ GetPACProxyData* pData = static_cast<GetPACProxyData*>(lpParameter);
+
+ OUString url(pData->m_rProtocol + "://" + pData->m_rHost + ":"
+ + OUString::number(pData->m_nPort));
+
+ HINTERNET hInternet = WinHttpOpen(L"Mozilla 5.0", WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
+ DWORD nError = GetLastError();
+ if (!hInternet)
+ return nError;
+
+ WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions{};
+ if (pData->m_bAutoDetect)
+ {
+ AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+ AutoProxyOptions.dwAutoDetectFlags
+ = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+ }
+ if (!pData->m_sAutoConfigUrl.isEmpty())
+ {
+ AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
+ AutoProxyOptions.lpszAutoConfigUrl = o3tl::toW(pData->m_sAutoConfigUrl.getStr());
+ }
+ // First, try without autologon. According to
+ // https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/web/winhttp/WinhttpProxySample/GetProxy.cpp
+ // autologon prevents caching, and so causes repetitive network traffic.
+ AutoProxyOptions.fAutoLogonIfChallenged = FALSE;
+ WINHTTP_PROXY_INFO ProxyInfo{};
+ bool bResult
+ = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()), &AutoProxyOptions, &ProxyInfo);
+ nError = GetLastError();
+ if (!bResult && nError == ERROR_WINHTTP_LOGIN_FAILURE)
+ {
+ AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
+ bResult = WinHttpGetProxyForUrl(hInternet, o3tl::toW(url.getStr()),
+ &AutoProxyOptions, &ProxyInfo);
+ nError = GetLastError();
+ }
+ WinHttpCloseHandle(hInternet);
+ if (bResult)
+ {
+ if (ProxyInfo.lpszProxyBypass)
+ GlobalFree(ProxyInfo.lpszProxyBypass);
+ if (ProxyInfo.lpszProxy)
+ {
+ OUString sProxyResult(o3tl::toU(ProxyInfo.lpszProxy));
+ GlobalFree(ProxyInfo.lpszProxy);
+ // Get the first of possibly multiple results
+ sProxyResult = sProxyResult.getToken(0, ';');
+ sal_Int32 nPortSepPos = sProxyResult.indexOf(':');
+ if (nPortSepPos != -1)
+ {
+ pData->m_ProxyServer.nPort = o3tl::toInt32(sProxyResult.subView(nPortSepPos + 1));
+ sProxyResult = sProxyResult.copy(0, nPortSepPos);
+ }
+ else
+ {
+ pData->m_ProxyServer.nPort = 0;
+ }
+ pData->m_ProxyServer.aName = sProxyResult;
+ }
+ }
+
+ return nError;
+}
+
+InternetProxyServer GetPACProxy(const OUString& rProtocol, const OUString& rHost, sal_Int32 nPort)
+{
+ GetPACProxyData aData(rProtocol, rHost, nPort);
+
+ // WinHTTP only supports http(s), so don't try for other protocols
+ if (!(rProtocol.equalsIgnoreAsciiCase("http") || rProtocol.equalsIgnoreAsciiCase("https")))
+ return aData.m_ProxyServer;
+
+ // Only try to get configuration from PAC (with all the overhead, including new thread)
+ // if configured to do so
+ {
+ WINHTTP_CURRENT_USER_IE_PROXY_CONFIG aProxyConfig{};
+ bool bResult = WinHttpGetIEProxyConfigForCurrentUser(&aProxyConfig);
+ if (aProxyConfig.lpszProxy)
+ GlobalFree(aProxyConfig.lpszProxy);
+ if (aProxyConfig.lpszProxyBypass)
+ GlobalFree(aProxyConfig.lpszProxyBypass);
+ // Don't try WPAD if AutoDetection or AutoConfig script URL are not configured
+ if (!bResult || !(aProxyConfig.fAutoDetect || aProxyConfig.lpszAutoConfigUrl))
+ return aData.m_ProxyServer;
+ aData.m_bAutoDetect = aProxyConfig.fAutoDetect;
+ if (aProxyConfig.lpszAutoConfigUrl)
+ {
+ aData.m_sAutoConfigUrl = o3tl::toU(aProxyConfig.lpszAutoConfigUrl);
+ GlobalFree(aProxyConfig.lpszAutoConfigUrl);
+ }
+ }
+
+ HANDLE hThread = reinterpret_cast<HANDLE>(
+ _beginthreadex(nullptr, 0, GetPACProxyThread, &aData, 0, nullptr));
+ if (hThread)
+ {
+ WaitForSingleObject(hThread, INFINITE);
+ CloseHandle(hThread);
+ }
+ return aData.m_ProxyServer;
+}
+
+#else // .. _WIN32
+
+// Read the settings from the OS which are stored in env vars
+//
+InternetProxyServer GetUnixSystemProxy(const OUString & rProtocol)
+{
+ // TODO this could be improved to read the "no_proxy" env variable
+ InternetProxyServer aProxy;
+ OUString protocolLower = rProtocol.toAsciiLowerCase() + "_proxy";
+ OString protocolLowerStr = OUStringToOString( protocolLower, RTL_TEXTENCODING_ASCII_US );
+ const char* pEnvProxy = getenv(protocolLowerStr.getStr());
+ if (!pEnvProxy)
+ return aProxy;
+ // expecting something like "https://example.ct:80"
+ OUString tmp = OUString::createFromAscii(pEnvProxy);
+ if (tmp.getLength() < (rProtocol.getLength() + 3))
+ return aProxy;
+ sal_Int32 x = tmp.indexOf("://");
+ sal_Int32 at = tmp.indexOf('@', x == -1 ? 0 : x + 3);
+ x = tmp.indexOf(':', at == -1 ? x == -1 ? 0 : x + 3 : at + 1);
+ if (x == -1)
+ return aProxy;
+ int nPort = o3tl::toInt32(tmp.subView(x + 1));
+ if (nPort == 0)
+ return aProxy;
+ aProxy.aName = tmp.copy(0, x);
+ aProxy.nPort = nPort;
+ return aProxy;
+}
+
+#endif // else .. _WIN32
+}
+
+InternetProxyServer InternetProxyDecider_Impl::getProxy(
+ const OUString & rProtocol,
+ const OUString & rHost,
+ sal_Int32 nPort ) const
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( m_nProxyType == ProxyType::NoProxy )
+ {
+ // Never use proxy.
+ return m_aEmptyProxy;
+ }
+
+ // If get from system
+ if (m_nProxyType == ProxyType::Automatic && !rHost.isEmpty())
+ {
+#ifdef _WIN32
+ InternetProxyServer aProxy(GetPACProxy(rProtocol, rHost, nPort));
+#else
+ InternetProxyServer aProxy(GetUnixSystemProxy(rProtocol));
+#endif // _WIN32
+ if (!aProxy.aName.isEmpty())
+ return aProxy;
+ }
+
+ if ( !rHost.isEmpty() && !m_aNoProxyList.empty() )
+ {
+
+ // First, try direct hostname match - #110515#
+
+
+ if ( !shouldUseProxy( rHost, nPort, false ) )
+ return m_aEmptyProxy;
+
+
+ // Second, try match against full qualified hostname - #104401#
+
+
+ OUString aHost;
+
+ if ( ( rHost.getLength() > 1 ) &&
+ ( rHost[ 0 ] == '[' ))
+ {
+ // host is given as numeric IPv6 address. name resolution
+ // functions need hostname without square brackets.
+ aHost = rHost.copy( 1, rHost.getLength() - 2 );
+ }
+ else
+ {
+ aHost = rHost;
+ }
+
+ OUString aFullyQualifiedHost;
+ if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
+ {
+ // This might be quite expensive (DNS lookup).
+ const osl::SocketAddr aAddr( aHost, nPort );
+ aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
+ m_aHostnames.put( aHost, aFullyQualifiedHost );
+ }
+
+ // Error resolving name? -> fallback.
+ if ( aFullyQualifiedHost.isEmpty() )
+ aFullyQualifiedHost = aHost;
+
+ if ( aFullyQualifiedHost != aHost )
+ {
+ if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
+ return m_aEmptyProxy;
+ }
+
+
+ // Third, try match of fully qualified entries in no-proxy list
+ // against full qualified hostname
+
+ // Example:
+ // list: staroffice-doc -> full: xyz.germany.sun.com
+ // in: staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
+
+
+ if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
+ return m_aEmptyProxy;
+ }
+
+ if (rProtocol.toAsciiLowerCase() == "https")
+ {
+ if ( !m_aHttpsProxy.aName.isEmpty() )
+ return m_aHttpsProxy;
+ }
+ else if ( !m_aHttpProxy.aName.isEmpty() )
+ {
+ // All other protocols use the HTTP proxy.
+ return m_aHttpProxy;
+ }
+ return m_aEmptyProxy;
+}
+
+// virtual
+void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
+ const util::ChangesEvent& Event )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ for ( const util::ElementChange& rElem : Event.Changes )
+ {
+ OUString aKey;
+ if ( ( rElem.Accessor >>= aKey ) && !aKey.isEmpty() )
+ {
+ if ( aKey == PROXY_TYPE_KEY )
+ {
+ sal_Int32 tmp;
+ if ( !( rElem.Element >>= tmp ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+ else
+ m_nProxyType = static_cast<ProxyType>(tmp);
+ }
+ else if ( aKey == NO_PROXY_LIST_KEY )
+ {
+ OUString aNoProxyList;
+ if ( !( rElem.Element >>= aNoProxyList ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+
+ setNoProxyList( aNoProxyList );
+ }
+ else if ( aKey == HTTP_PROXY_NAME_KEY )
+ {
+ if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+ }
+ else if ( aKey == HTTP_PROXY_PORT_KEY )
+ {
+ if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+
+ if ( m_aHttpProxy.nPort == -1 )
+ m_aHttpProxy.nPort = 80; // standard HTTP port.
+ }
+ else if ( aKey == HTTPS_PROXY_NAME_KEY )
+ {
+ if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+ }
+ else if ( aKey == HTTPS_PROXY_PORT_KEY )
+ {
+ if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
+ {
+ OSL_FAIL( "InternetProxyDecider - changesOccurred - "
+ "Error getting config item value!" );
+ }
+
+ if ( m_aHttpsProxy.nPort == -1 )
+ m_aHttpsProxy.nPort = 443; // standard HTTPS port.
+ }
+ }
+ }
+}
+
+
+// virtual
+void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
+{
+ if ( m_xNotifier.is() )
+ {
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ if ( m_xNotifier.is() )
+ m_xNotifier.clear();
+ }
+}
+
+
+void InternetProxyDecider_Impl::setNoProxyList(
+ const OUString & rNoProxyList )
+{
+ osl::Guard< osl::Mutex > aGuard( m_aMutex );
+
+ m_aNoProxyList.clear();
+
+ if ( rNoProxyList.isEmpty() )
+ return;
+
+ // List of connection endpoints hostname[:port],
+ // separated by semicolon. Wildcards allowed.
+
+ sal_Int32 nPos = 0;
+ sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
+ sal_Int32 nLen = rNoProxyList.getLength();
+
+ do
+ {
+ if ( nEnd == -1 )
+ nEnd = nLen;
+
+ OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
+
+ if ( !aToken.isEmpty() )
+ {
+ OUString aServer;
+ OUString aPort;
+
+ // numerical IPv6 address?
+ bool bIPv6Address = false;
+ sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
+ if ( nClosedBracketPos == -1 )
+ nClosedBracketPos = 0;
+ else
+ bIPv6Address = true;
+
+ sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
+ if ( nColonPos == -1 )
+ {
+ // No port given, server pattern equals current token
+ aPort = "*";
+ if ( aToken.indexOf( '*' ) == -1 )
+ {
+ // pattern describes exactly one server
+ aServer = aToken;
+ }
+
+ aToken += ":*";
+ }
+ else
+ {
+ // Port given, extract server pattern
+ sal_Int32 nAsteriskPos = aToken.indexOf( '*' );
+ aPort = aToken.copy( nColonPos + 1 );
+ if ( nAsteriskPos < nColonPos )
+ {
+ // pattern describes exactly one server
+ aServer = aToken.copy( 0, nColonPos );
+ }
+ }
+
+ OUStringBuffer aFullyQualifiedHost;
+ if ( !aServer.isEmpty() )
+ {
+ // Remember fully qualified server name if current list
+ // entry specifies exactly one non-fully qualified server
+ // name.
+
+ // remove square brackets from host name in case it's
+ // a numerical IPv6 address.
+ if ( bIPv6Address )
+ aServer = aServer.copy( 1, aServer.getLength() - 2 );
+
+ // This might be quite expensive (DNS lookup).
+ const osl::SocketAddr aAddr( aServer, 0 );
+ OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
+ if ( aTmp != aServer.toAsciiLowerCase() )
+ {
+ if ( bIPv6Address )
+ aFullyQualifiedHost.append( "[" + aTmp + "]" );
+ else
+ aFullyQualifiedHost.append( aTmp );
+ aFullyQualifiedHost.append( ":" + aPort );
+ }
+ }
+
+ m_aNoProxyList.emplace_back( WildCard( aToken ),
+ WildCard( aFullyQualifiedHost ) );
+ }
+
+ if ( nEnd != nLen )
+ {
+ nPos = nEnd + 1;
+ nEnd = rNoProxyList.indexOf( ';', nPos );
+ }
+ }
+ while ( nEnd != nLen );
+}
+
+} // namespace proxydecider_impl
+
+
+// InternetProxyDecider Implementation.
+
+
+InternetProxyDecider::InternetProxyDecider(
+ const uno::Reference< uno::XComponentContext>& rxContext )
+: m_xImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxContext ) )
+{
+}
+
+
+InternetProxyDecider::~InternetProxyDecider()
+{
+ // Break circular reference between config listener and notifier.
+ m_xImpl->dispose();
+}
+
+
+OUString InternetProxyDecider::getProxy(
+ const OUString & rProtocol,
+ const OUString & rHost,
+ sal_Int32 nPort ) const
+{
+ InternetProxyServer ret(m_xImpl->getProxy(rProtocol, rHost, nPort));
+
+ if (ret.aName.isEmpty() || ret.nPort == -1)
+ {
+ return ret.aName;
+ }
+
+ return ret.aName + ":" + OUString::number(ret.nPort);
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/authenticationfallback.cxx b/ucbhelper/source/provider/authenticationfallback.cxx
new file mode 100644
index 0000000000..04491520bd
--- /dev/null
+++ b/ucbhelper/source/provider/authenticationfallback.cxx
@@ -0,0 +1,31 @@
+/* -*- 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/.
+ */
+
+#include <ucbhelper/authenticationfallback.hxx>
+#include <com/sun/star/ucb/AuthenticationFallbackRequest.hpp>
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+AuthenticationFallbackRequest::AuthenticationFallbackRequest(
+ const OUString & rInstructions,
+ const OUString & rURL )
+{
+
+ ucb::AuthenticationFallbackRequest aRequest;
+ aRequest.instructions = rInstructions;
+ aRequest.url = rURL;
+
+ setRequest( uno::Any( aRequest ) );
+ m_xAuthFallback = new InteractionAuthFallback( this );
+
+ setContinuations({ new InteractionAbort(this), m_xAuthFallback });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/cancelcommandexecution.cxx b/ucbhelper/source/provider/cancelcommandexecution.cxx
new file mode 100644
index 0000000000..57166e49b0
--- /dev/null
+++ b/ucbhelper/source/provider/cancelcommandexecution.cxx
@@ -0,0 +1,115 @@
+/* -*- 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 <rtl/ref.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/ucb/CommandFailedException.hpp>
+#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <ucbhelper/interactionrequest.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include "simpleioerrorrequest.hxx"
+
+using namespace com::sun::star;
+
+namespace ucbhelper
+{
+
+
+void cancelCommandExecution( const uno::Any & rException,
+ const uno::Reference<
+ ucb::XCommandEnvironment > & xEnv )
+{
+ if ( xEnv.is() )
+ {
+ uno::Reference<
+ task::XInteractionHandler > xIH = xEnv->getInteractionHandler();
+ if ( xIH.is() )
+ {
+ rtl::Reference< ucbhelper::InteractionRequest > xRequest
+ = new ucbhelper::InteractionRequest( rException );
+
+ xRequest->setContinuations({ new ucbhelper::InteractionAbort(xRequest.get()) });
+
+ xIH->handle( xRequest );
+
+ rtl::Reference< ucbhelper::InteractionContinuation > xSelection
+ = xRequest->getSelection();
+
+ if ( xSelection.is() )
+ throw ucb::CommandFailedException(
+ OUString(),
+ uno::Reference< uno::XInterface >(),
+ rException );
+ }
+ }
+
+ cppu::throwException( rException );
+ OSL_FAIL( "Return from cppu::throwException call!!!" );
+ throw uno::RuntimeException();
+}
+
+
+void cancelCommandExecution( const ucb::IOErrorCode eError,
+ const uno::Sequence< uno::Any > & rArgs,
+ const uno::Reference<
+ ucb::XCommandEnvironment > & xEnv,
+ const OUString & rMessage,
+ const uno::Reference<
+ ucb::XCommandProcessor > & xContext )
+{
+ if ( !xEnv )
+ {
+ // Fast path
+
+ ucb::InteractiveAugmentedIOException aRequest(
+ rMessage, xContext, task::InteractionClassification_ERROR, eError, rArgs);
+ cppu::throwException( uno::Any( aRequest ) );
+ }
+ else
+ {
+ rtl::Reference< ucbhelper::SimpleIOErrorRequest > xRequest
+ = new ucbhelper::SimpleIOErrorRequest(
+ eError, rArgs, rMessage, xContext );
+ uno::Reference<
+ task::XInteractionHandler > xIH = xEnv->getInteractionHandler();
+ if ( xIH.is() )
+ {
+ xIH->handle( xRequest );
+
+ rtl::Reference< ucbhelper::InteractionContinuation > xSelection
+ = xRequest->getSelection();
+
+ if ( xSelection.is() )
+ throw ucb::CommandFailedException( OUString(),
+ xContext,
+ xRequest->getRequest() );
+ }
+ cppu::throwException( xRequest->getRequest() );
+ }
+
+ OSL_FAIL( "Return from cppu::throwException call!!!" );
+ throw uno::RuntimeException();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/contenthelper.cxx b/ucbhelper/source/provider/contenthelper.cxx
new file mode 100644
index 0000000000..1e5147f6fb
--- /dev/null
+++ b/ucbhelper/source/provider/contenthelper.cxx
@@ -0,0 +1,863 @@
+/* -*- 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/lang/NoSupportException.hpp>
+#include <com/sun/star/ucb/ContentAction.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
+#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 <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <ucbhelper/contenthelper.hxx>
+#include <ucbhelper/contentidentifier.hxx>
+#include "contentinfo.hxx"
+#include <ucbhelper/providerhelper.hxx>
+#include <ucbhelper/macros.hxx>
+
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <rtl/ref.hxx>
+
+#include <unordered_map>
+#include <utility>
+
+using namespace com::sun::star;
+
+namespace ucbhelper_impl
+{
+
+namespace {
+
+class PropertyEventSequence
+{
+ uno::Sequence< beans::PropertyChangeEvent > m_aSeq;
+ sal_uInt32 m_nPos;
+
+public:
+ explicit PropertyEventSequence( sal_uInt32 nSize )
+ : m_aSeq( nSize ), m_nPos( 0 ) {};
+
+ void append( const beans::PropertyChangeEvent& rEvt )
+ { m_aSeq.getArray()[ m_nPos ] = rEvt; ++m_nPos; }
+
+ const uno::Sequence< beans::PropertyChangeEvent >& getEvents()
+ { m_aSeq.realloc( m_nPos ); return m_aSeq; }
+};
+
+}
+
+typedef void* XPropertiesChangeListenerPtr; // -> Compiler problems!
+
+namespace {
+
+struct equalPtr
+{
+ bool operator()( const XPropertiesChangeListenerPtr& rp1,
+ const XPropertiesChangeListenerPtr& rp2 ) const
+ {
+ return ( rp1 == rp2 );
+ }
+};
+
+struct hashPtr
+{
+ size_t operator()( const XPropertiesChangeListenerPtr& rp ) const
+ {
+ return reinterpret_cast<size_t>(rp);
+ }
+};
+
+}
+
+typedef std::unordered_map
+<
+ XPropertiesChangeListenerPtr,
+ PropertyEventSequence,
+ hashPtr,
+ equalPtr
+>
+PropertiesEventListenerMap;
+
+typedef cppu::OMultiTypeInterfaceContainerHelperVar<OUString>
+ PropertyChangeListeners;
+
+struct ContentImplHelper_Impl
+{
+ rtl::Reference< ::ucbhelper::PropertySetInfo > m_xPropSetInfo;
+ rtl::Reference< ::ucbhelper::CommandProcessorInfo > m_xCommandsInfo;
+ std::unique_ptr<cppu::OInterfaceContainerHelper> m_pDisposeEventListeners;
+ std::unique_ptr<comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener>>
+ m_pContentEventListeners;
+ std::unique_ptr<comphelper::OInterfaceContainerHelper3<beans::XPropertySetInfoChangeListener>>
+ m_pPropSetChangeListeners;
+ std::unique_ptr<cppu::OInterfaceContainerHelper> m_pCommandChangeListeners;
+ std::unique_ptr<PropertyChangeListeners> m_pPropertyChangeListeners;
+};
+
+} // namespace ucbhelper_impl
+
+using namespace ucbhelper_impl;
+
+namespace ucbhelper {
+
+ContentImplHelper::ContentImplHelper(
+ uno::Reference< uno::XComponentContext > xContext,
+ rtl::Reference< ContentProviderImplHelper > xProvider,
+ uno::Reference<
+ css::ucb::XContentIdentifier > Identifier )
+: m_pImpl( new ContentImplHelper_Impl ),
+ m_xContext(std::move( xContext )),
+ m_xIdentifier(std::move( Identifier )),
+ m_xProvider(std::move( xProvider )),
+ m_nCommandId( 0 )
+{
+}
+
+// virtual
+ContentImplHelper::~ContentImplHelper()
+{
+}
+
+void SAL_CALL ContentImplHelper::release()
+ noexcept
+{
+ // #144882# - Call to OWeakObject::release may destroy m_xProvider.
+ // Prevent this.
+ rtl::Reference< ContentProviderImplHelper > xKeepProviderAlive(
+ m_xProvider );
+
+ osl::MutexGuard aGuard( m_xProvider->m_aMutex );
+ OWeakObject::release();
+}
+
+uno::Any SAL_CALL ContentImplHelper::queryInterface( const uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >(this),
+ static_cast< lang::XServiceInfo * >(this),
+ static_cast< lang::XComponent * >(this),
+ static_cast< css::ucb::XContent * >(this),
+ static_cast< css::ucb::XCommandProcessor * >(this),
+ static_cast< beans::XPropertiesChangeNotifier * >(this),
+ static_cast< css::ucb::XCommandInfoChangeNotifier * >(this),
+ static_cast< beans::XPropertyContainer * >(this),
+ static_cast< beans::XPropertySetInfoChangeNotifier * >(this),
+ static_cast< container::XChild * >(this));
+ return aRet.hasValue() ? aRet : cppu::OWeakObject::queryInterface( rType );
+}
+
+XTYPEPROVIDER_IMPL_10( ContentImplHelper,
+ lang::XTypeProvider,
+ lang::XServiceInfo,
+ lang::XComponent,
+ css::ucb::XContent,
+ css::ucb::XCommandProcessor,
+ beans::XPropertiesChangeNotifier,
+ css::ucb::XCommandInfoChangeNotifier,
+ beans::XPropertyContainer,
+ beans::XPropertySetInfoChangeNotifier,
+ container::XChild );
+
+// virtual
+sal_Bool SAL_CALL ContentImplHelper::supportsService(
+ const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::dispose()
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pImpl->m_pDisposeEventListeners &&
+ m_pImpl->m_pDisposeEventListeners->getLength() )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< lang::XComponent * >( this );
+ m_pImpl->m_pDisposeEventListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pImpl->m_pContentEventListeners &&
+ m_pImpl->m_pContentEventListeners->getLength() )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< css::ucb::XContent * >( this );
+ m_pImpl->m_pContentEventListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pImpl->m_pPropSetChangeListeners &&
+ m_pImpl->m_pPropSetChangeListeners->getLength() )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source
+ = static_cast< beans::XPropertySetInfoChangeNotifier * >( this );
+ m_pImpl->m_pPropSetChangeListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pImpl->m_pCommandChangeListeners &&
+ m_pImpl->m_pCommandChangeListeners->getLength() )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< css::ucb::XCommandInfoChangeNotifier * >( this );
+ m_pImpl->m_pCommandChangeListeners->disposeAndClear( aEvt );
+ }
+
+ if ( m_pImpl->m_pPropertyChangeListeners )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source
+ = static_cast< beans::XPropertiesChangeNotifier * >( this );
+ m_pImpl->m_pPropertyChangeListeners->disposeAndClear( aEvt );
+ }
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pDisposeEventListeners )
+ m_pImpl->m_pDisposeEventListeners.reset(
+ new cppu::OInterfaceContainerHelper( m_aMutex ));
+
+ m_pImpl->m_pDisposeEventListeners->addInterface( Listener );
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removeEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pImpl->m_pDisposeEventListeners )
+ m_pImpl->m_pDisposeEventListeners->removeInterface( Listener );
+}
+
+// virtual
+uno::Reference< css::ucb::XContentIdentifier > SAL_CALL
+ContentImplHelper::getIdentifier()
+{
+ return m_xIdentifier;
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addContentEventListener(
+ const uno::Reference< css::ucb::XContentEventListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pContentEventListeners )
+ m_pImpl->m_pContentEventListeners.reset(
+ new comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener>( m_aMutex ));
+
+ m_pImpl->m_pContentEventListeners->addInterface( Listener );
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removeContentEventListener(
+ const uno::Reference< css::ucb::XContentEventListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pImpl->m_pContentEventListeners )
+ m_pImpl->m_pContentEventListeners->removeInterface( Listener );
+}
+
+// virtual
+sal_Int32 SAL_CALL ContentImplHelper::createCommandIdentifier()
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // Just increase counter on every call to generate an identifier.
+ return ++m_nCommandId;
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addPropertiesChangeListener(
+ const uno::Sequence< OUString >& PropertyNames,
+ const uno::Reference< beans::XPropertiesChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ m_pImpl->m_pPropertyChangeListeners.reset(
+ new PropertyChangeListeners( m_aMutex ));
+
+ if ( !PropertyNames.hasElements() )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_pImpl->m_pPropertyChangeListeners->addInterface(
+ OUString(), Listener );
+ }
+ else
+ {
+ for ( const OUString& rName : PropertyNames )
+ {
+ if ( !rName.isEmpty() )
+ m_pImpl->m_pPropertyChangeListeners->addInterface(
+ rName, Listener );
+ }
+ }
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removePropertiesChangeListener(
+ const uno::Sequence< OUString >& PropertyNames,
+ const uno::Reference< beans::XPropertiesChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ return;
+
+ if ( !PropertyNames.hasElements() )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_pImpl->m_pPropertyChangeListeners->removeInterface(
+ OUString(), Listener );
+ }
+ else
+ {
+ for ( const OUString& rName : PropertyNames )
+ {
+ if ( !rName.isEmpty() )
+ m_pImpl->m_pPropertyChangeListeners->removeInterface(
+ rName, Listener );
+ }
+ }
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addCommandInfoChangeListener(
+ const uno::Reference< css::ucb::XCommandInfoChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pCommandChangeListeners )
+ m_pImpl->m_pCommandChangeListeners.reset(
+ new cppu::OInterfaceContainerHelper( m_aMutex ));
+
+ m_pImpl->m_pCommandChangeListeners->addInterface( Listener );
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removeCommandInfoChangeListener(
+ const uno::Reference< css::ucb::XCommandInfoChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pImpl->m_pCommandChangeListeners )
+ m_pImpl->m_pCommandChangeListeners->removeInterface( Listener );
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addProperty(
+ const OUString& Name,
+ sal_Int16 Attributes,
+ const uno::Any& DefaultValue )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // Make sure a property with the requested name does not already
+ // exist in dynamic and static(!) properties.
+
+ // @@@ Need real command environment here, but where to get it from?
+ // XPropertyContainer interface should be replaced by
+ // XCommandProcessor commands!
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv;
+
+ if ( getPropertySetInfo( xEnv )->hasPropertyByName( Name ) )
+ {
+ // Property does already exist.
+ throw beans::PropertyExistException();
+ }
+
+ // Add a new dynamic property.
+ // Open/create persistent property set.
+ uno::Reference< css::ucb::XPersistentPropertySet > xSet(
+ getAdditionalPropertySet( true ) );
+
+ OSL_ENSURE( xSet.is(),
+ "ContentImplHelper::addProperty - No property set!" );
+
+ if ( !xSet.is() )
+ return;
+
+ uno::Reference< beans::XPropertyContainer > xContainer(
+ xSet, uno::UNO_QUERY );
+
+ OSL_ENSURE(
+ xContainer.is(),
+ "ContentImplHelper::addProperty - No property container!" );
+
+ if ( !xContainer.is() )
+ return;
+
+ // Property is always removable.
+ Attributes |= beans::PropertyAttribute::REMOVABLE;
+
+ try
+ {
+ xContainer->addProperty( Name, Attributes, DefaultValue );
+ }
+ catch ( beans::PropertyExistException const & )
+ {
+ OSL_FAIL( "ContentImplHelper::addProperty - Exists!" );
+ throw;
+ }
+ catch ( beans::IllegalTypeException const & )
+ {
+ OSL_FAIL( "ContentImplHelper::addProperty - Wrong Type!" );
+ throw;
+ }
+ catch ( lang::IllegalArgumentException const & )
+ {
+ OSL_FAIL( "ContentImplHelper::addProperty - Illegal Arg!" );
+ throw;
+ }
+
+ // Success!
+
+ if ( m_pImpl->m_xPropSetInfo.is() )
+ {
+ // Info cached in propertyset info is invalid now!
+ m_pImpl->m_xPropSetInfo->reset();
+ }
+
+ // Notify propertyset info change listeners.
+ if ( m_pImpl->m_pPropSetChangeListeners &&
+ m_pImpl->m_pPropSetChangeListeners->getLength() )
+ {
+ beans::PropertySetInfoChangeEvent evt(
+ getXWeak(),
+ Name,
+ -1, // No handle available
+ beans::PropertySetInfoChange::PROPERTY_INSERTED );
+ notifyPropertySetInfoChange( evt );
+ }
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removeProperty( const OUString& Name )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ try
+ {
+ // @@@ Need real command environment here, but where to get it from?
+ // XPropertyContainer interface should be replaced by
+ // XCommandProcessor commands!
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv;
+
+ beans::Property aProp
+ = getPropertySetInfo( xEnv )->getPropertyByName( Name );
+
+ if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVABLE ) )
+ {
+ // Not removable!
+ throw beans::NotRemoveableException();
+ }
+ }
+ catch ( beans::UnknownPropertyException const & )
+ {
+ OSL_FAIL( "ContentImplHelper::removeProperty - Unknown!" );
+ throw;
+ }
+
+ // Try to remove property from dynamic property set.
+ // Open persistent property set, if exists.
+ uno::Reference< css::ucb::XPersistentPropertySet > xSet(
+ getAdditionalPropertySet( false ) );
+ if ( !xSet.is() )
+ return;
+
+ uno::Reference< beans::XPropertyContainer > xContainer(
+ xSet, uno::UNO_QUERY );
+
+ OSL_ENSURE(
+ xContainer.is(),
+ "ContentImplHelper::removeProperty - No property container!" );
+
+ if ( !xContainer.is() )
+ return;
+
+ try
+ {
+ xContainer->removeProperty( Name );
+ }
+ catch ( beans::UnknownPropertyException const & )
+ {
+ OSL_FAIL( "ContentImplHelper::removeProperty - Unknown!" );
+ throw;
+ }
+ catch ( beans::NotRemoveableException const & )
+ {
+ OSL_FAIL(
+ "ContentImplHelper::removeProperty - Unremovable!" );
+ throw;
+ }
+
+ xContainer = nullptr;
+
+ // Success!
+
+ if ( !xSet->getPropertySetInfo()->getProperties().hasElements() )
+ {
+ // Remove empty propertyset from registry.
+ uno::Reference< css::ucb::XPropertySetRegistry >
+ xReg = xSet->getRegistry();
+ if ( xReg.is() )
+ {
+ OUString aKey( xSet->getKey() );
+ xSet = nullptr;
+ xReg->removePropertySet( aKey );
+ }
+ }
+
+ if ( m_pImpl->m_xPropSetInfo.is() )
+ {
+ // Info cached in propertyset info is invalid now!
+ m_pImpl->m_xPropSetInfo->reset();
+ }
+
+ // Notify propertyset info change listeners.
+ if ( m_pImpl->m_pPropSetChangeListeners &&
+ m_pImpl->m_pPropSetChangeListeners->getLength() )
+ {
+ beans::PropertySetInfoChangeEvent evt(
+ getXWeak(),
+ Name,
+ -1, // No handle available
+ beans::PropertySetInfoChange::PROPERTY_REMOVED );
+ notifyPropertySetInfoChange( evt );
+ }
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::addPropertySetInfoChangeListener(
+ const uno::Reference< beans::XPropertySetInfoChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_pPropSetChangeListeners )
+ m_pImpl->m_pPropSetChangeListeners.reset(
+ new comphelper::OInterfaceContainerHelper3<beans::XPropertySetInfoChangeListener>( m_aMutex ));
+
+ m_pImpl->m_pPropSetChangeListeners->addInterface( Listener );
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::removePropertySetInfoChangeListener(
+ const uno::Reference< beans::XPropertySetInfoChangeListener >& Listener )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pImpl->m_pPropSetChangeListeners )
+ m_pImpl->m_pPropSetChangeListeners->removeInterface( Listener );
+}
+
+// virtual
+uno::Reference< uno::XInterface > SAL_CALL ContentImplHelper::getParent()
+{
+ uno::Reference< uno::XInterface > xParent;
+ OUString aURL = getParentURL();
+
+ if ( !aURL.isEmpty() )
+ {
+ uno::Reference< css::ucb::XContentIdentifier > xId(
+ new ContentIdentifier( aURL ) );
+ try
+ {
+ xParent.set( m_xProvider->queryContent( xId ) );
+ }
+ catch ( css::ucb::IllegalIdentifierException const & )
+ {
+ }
+ }
+
+ return xParent;
+}
+
+// virtual
+void SAL_CALL ContentImplHelper::setParent(
+ const uno::Reference< uno::XInterface >& )
+{
+ throw lang::NoSupportException();
+}
+
+uno::Reference< css::ucb::XPersistentPropertySet >
+ContentImplHelper::getAdditionalPropertySet( bool bCreate )
+{
+ // Get propertyset from provider.
+ return m_xProvider->getAdditionalPropertySet(
+ m_xIdentifier->getContentIdentifier(), bCreate );
+}
+
+bool ContentImplHelper::renameAdditionalPropertySet(
+ const OUString& rOldKey,
+ const OUString& rNewKey )
+{
+ return m_xProvider->renameAdditionalPropertySet(
+ rOldKey, rNewKey, true/*bRecursive*/ );
+}
+
+bool ContentImplHelper::copyAdditionalPropertySet(
+ const OUString& rSourceKey,
+ const OUString& rTargetKey )
+{
+ return m_xProvider->copyAdditionalPropertySet(
+ rSourceKey, rTargetKey, true/*bRecursive*/ );
+}
+
+bool ContentImplHelper::removeAdditionalPropertySet()
+{
+ return m_xProvider->removeAdditionalPropertySet(
+ m_xIdentifier->getContentIdentifier(), true/*bRecursive*/ );
+}
+
+void ContentImplHelper::notifyPropertiesChange(
+ const uno::Sequence< beans::PropertyChangeEvent >& evt ) const
+{
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ return;
+
+ sal_Int32 nCount = evt.getLength();
+ if ( !nCount )
+ return;
+
+ // First, notify listeners interested in changes of every property.
+ cppu::OInterfaceContainerHelper* pAllPropsContainer
+ = m_pImpl->m_pPropertyChangeListeners->getContainer(
+ OUString() );
+ if ( pAllPropsContainer )
+ {
+ cppu::OInterfaceIteratorHelper aIter( *pAllPropsContainer );
+ while ( aIter.hasMoreElements() )
+ {
+ // Propagate event.
+ static_cast< beans::XPropertiesChangeListener* >(
+ aIter.next())->propertiesChange( evt );
+ }
+ }
+
+ PropertiesEventListenerMap aListeners;
+
+ for ( const beans::PropertyChangeEvent& rEvent : evt )
+ {
+ const OUString& rName = rEvent.PropertyName;
+
+ cppu::OInterfaceContainerHelper* pPropsContainer
+ = m_pImpl->m_pPropertyChangeListeners->getContainer( rName );
+ if ( pPropsContainer )
+ {
+ cppu::OInterfaceIteratorHelper aIter( *pPropsContainer );
+ while ( aIter.hasMoreElements() )
+ {
+ PropertyEventSequence* p = nullptr;
+
+ beans::XPropertiesChangeListener* pListener =
+ static_cast< beans::XPropertiesChangeListener * >(
+ aIter.next() );
+ PropertiesEventListenerMap::iterator it =
+ aListeners.find( pListener );
+ if ( it == aListeners.end() )
+ {
+ // Not in map - create and insert new entry.
+ p = &aListeners.emplace( pListener, PropertyEventSequence(nCount)).first->second;
+ }
+ else
+ p = &it->second;
+
+ if ( p )
+ p->append( rEvent );
+ }
+ }
+ }
+
+ // Notify listeners.
+ PropertiesEventListenerMap::iterator it = aListeners.begin();
+ while ( !aListeners.empty() )
+ {
+ beans::XPropertiesChangeListener* pListener =
+ static_cast< beans::XPropertiesChangeListener * >( (*it).first );
+ PropertyEventSequence pSeq = std::move(it->second);
+
+ // Remove current element.
+ aListeners.erase( it );
+
+ // Propagate event.
+ pListener->propertiesChange( pSeq.getEvents() );
+
+ it = aListeners.begin();
+ }
+}
+
+void ContentImplHelper::notifyPropertySetInfoChange(
+ const beans::PropertySetInfoChangeEvent& evt ) const
+{
+ if ( !m_pImpl->m_pPropSetChangeListeners )
+ return;
+
+ // Notify event listeners.
+ m_pImpl->m_pPropSetChangeListeners->notifyEach( &beans::XPropertySetInfoChangeListener::propertySetInfoChange, evt );
+}
+
+void ContentImplHelper::notifyContentEvent(
+ const css::ucb::ContentEvent& evt ) const
+{
+ if ( !m_pImpl->m_pContentEventListeners )
+ return;
+
+ // Notify event listeners.
+ m_pImpl->m_pContentEventListeners->notifyEach( &css::ucb::XContentEventListener::contentEvent, evt);
+}
+
+void ContentImplHelper::inserted()
+{
+ // Content is not yet registered at provider.
+ m_xProvider->registerNewContent( this );
+
+ // If the parent content is currently not instantiated, there can be
+ // no listeners interested in changes ;-)
+
+ rtl::Reference< ContentImplHelper > xParent
+ = m_xProvider->queryExistingContent( getParentURL() );
+
+ if ( xParent.is() )
+ {
+ css::ucb::ContentEvent aEvt(
+ xParent->getXWeak(), // Source
+ css::ucb::ContentAction::INSERTED, // Action
+ this, // Content
+ xParent->getIdentifier() ); // Id
+ xParent->notifyContentEvent( aEvt );
+ }
+}
+
+void ContentImplHelper::deleted()
+{
+ uno::Reference< css::ucb::XContent > xThis = this;
+
+ rtl::Reference< ContentImplHelper > xParent
+ = m_xProvider->queryExistingContent( getParentURL() );
+
+ if ( xParent.is() )
+ {
+ // Let parent notify "REMOVED" event.
+ css::ucb::ContentEvent aEvt(
+ xParent->getXWeak(),
+ css::ucb::ContentAction::REMOVED,
+ this,
+ xParent->getIdentifier() );
+ xParent->notifyContentEvent( aEvt );
+ }
+
+ // Notify "DELETED" event.
+ css::ucb::ContentEvent aEvt1(
+ getXWeak(),
+ css::ucb::ContentAction::DELETED,
+ this,
+ getIdentifier() );
+ notifyContentEvent( aEvt1 );
+
+ m_xProvider->removeContent( this );
+}
+
+bool ContentImplHelper::exchange(
+ const uno::Reference< css::ucb::XContentIdentifier >& rNewId )
+{
+ uno::Reference< css::ucb::XContent > xThis = this;
+
+ osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ rtl::Reference< ContentImplHelper > xContent
+ = m_xProvider->queryExistingContent( rNewId );
+ if ( xContent.is() )
+ {
+ // @@@
+ // Big trouble. Another object with the new identity exists.
+ // How shall I mutate to / merge with the other object?
+ return false;
+ }
+
+ uno::Reference< css::ucb::XContentIdentifier > xOldId
+ = getIdentifier();
+
+ // Re-insert at provider.
+ m_xProvider->removeContent( this );
+ m_xIdentifier = rNewId;
+ m_xProvider->registerNewContent( this );
+
+ aGuard.clear();
+
+ // Notify "EXCHANGED" event.
+ css::ucb::ContentEvent aEvt(
+ getXWeak(),
+ css::ucb::ContentAction::EXCHANGED,
+ this,
+ xOldId );
+ notifyContentEvent( aEvt );
+ return true;
+}
+
+uno::Reference< css::ucb::XCommandInfo >
+ContentImplHelper::getCommandInfo(
+ const uno::Reference< css::ucb::XCommandEnvironment > & xEnv,
+ bool bCache )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_xCommandsInfo.is() )
+ m_pImpl->m_xCommandsInfo
+ = new CommandProcessorInfo( xEnv, this );
+ else if ( !bCache )
+ m_pImpl->m_xCommandsInfo->reset();
+
+ return m_pImpl->m_xCommandsInfo;
+}
+
+uno::Reference< beans::XPropertySetInfo >
+ContentImplHelper::getPropertySetInfo(
+ const uno::Reference< css::ucb::XCommandEnvironment > & xEnv,
+ bool bCache )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_xPropSetInfo.is() )
+ m_pImpl->m_xPropSetInfo
+ = new PropertySetInfo( xEnv, this );
+ else if ( !bCache )
+ m_pImpl->m_xPropSetInfo->reset();
+
+ return m_pImpl->m_xPropSetInfo;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/contentidentifier.cxx b/ucbhelper/source/provider/contentidentifier.cxx
new file mode 100644
index 0000000000..2a5da953d9
--- /dev/null
+++ b/ucbhelper/source/provider/contentidentifier.cxx
@@ -0,0 +1,91 @@
+/* -*- 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 <ucbhelper/contentidentifier.hxx>
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+
+
+namespace ucbhelper
+{
+
+struct ContentIdentifier_Impl
+{
+ OUString m_aContentId;
+ OUString m_aProviderScheme;
+
+ explicit ContentIdentifier_Impl( const OUString& rURL );
+};
+
+
+// ContentIdentifier_Impl Implementation.
+
+
+ContentIdentifier_Impl::ContentIdentifier_Impl(const OUString& rURL )
+{
+ // Normalize URL scheme ( it's case insensitive ).
+
+ // The content provider scheme is the part before the first ':'
+ // within the content id.
+ sal_Int32 nPos = rURL.indexOf( ':' );
+ if ( nPos != -1 )
+ {
+ OUString aScheme( rURL.copy( 0, nPos ) );
+ m_aProviderScheme = aScheme.toAsciiLowerCase();
+ m_aContentId = rURL.replaceAt( 0, nPos, aScheme );
+ }
+}
+
+
+// ContentIdentifier Implementation.
+
+
+ContentIdentifier::ContentIdentifier( const OUString& rURL )
+ : m_pImpl( new ContentIdentifier_Impl( rURL ) )
+{
+}
+
+
+// virtual
+ContentIdentifier::~ContentIdentifier()
+{
+}
+
+
+// XContentIdentifier methods.
+
+
+// virtual
+OUString SAL_CALL ContentIdentifier::getContentIdentifier()
+{
+ return m_pImpl->m_aContentId;
+}
+
+
+// virtual
+OUString SAL_CALL ContentIdentifier::getContentProviderScheme()
+{
+ return m_pImpl->m_aProviderScheme;
+}
+
+} /* namespace ucbhelper */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/contentinfo.cxx b/ucbhelper/source/provider/contentinfo.cxx
new file mode 100644
index 0000000000..1e513604eb
--- /dev/null
+++ b/ucbhelper/source/provider/contentinfo.cxx
@@ -0,0 +1,318 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/ucb/XPersistentPropertySet.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+
+#include <ucbhelper/contenthelper.hxx>
+#include <utility>
+#include "contentinfo.hxx"
+
+using namespace com::sun::star;
+
+
+// PropertySetInfo Implementation.
+
+
+namespace ucbhelper {
+
+PropertySetInfo::PropertySetInfo(
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv,
+ ContentImplHelper* pContent )
+: m_xEnv(std::move( xEnv )),
+ m_pContent( pContent )
+{
+}
+
+
+// virtual
+PropertySetInfo::~PropertySetInfo()
+{
+}
+
+
+// XPropertySetInfo methods.
+
+
+// virtual
+uno::Sequence< beans::Property > SAL_CALL PropertySetInfo::getProperties()
+{
+ std::unique_lock aGuard( m_aMutex );
+ return getPropertiesImpl();
+}
+
+const uno::Sequence< beans::Property > & PropertySetInfo::getPropertiesImpl()
+{
+ if ( m_xProps )
+ return *m_xProps;
+
+ // Get info for core ( native) properties.
+
+ try
+ {
+ m_xProps = m_pContent->getProperties( m_xEnv );
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ m_xProps.emplace();
+ }
+
+ // Get info for additional properties.
+
+ uno::Reference< css::ucb::XPersistentPropertySet >
+ xSet ( m_pContent->getAdditionalPropertySet( false ) );
+
+ if ( xSet.is() )
+ {
+ // Get property set info.
+ uno::Reference< beans::XPropertySetInfo > xInfo(
+ xSet->getPropertySetInfo() );
+ if ( xInfo.is() )
+ {
+ const uno::Sequence< beans::Property >& rAddProps
+ = xInfo->getProperties();
+ sal_Int32 nAddProps = rAddProps.getLength();
+ if ( nAddProps > 0 )
+ {
+ sal_Int32 nPos = m_xProps->getLength();
+ m_xProps->realloc( nPos + nAddProps );
+
+ std::copy(rAddProps.begin(), rAddProps.end(),
+ std::next(m_xProps->getArray(), nPos));
+ }
+ }
+ }
+ return *m_xProps;
+}
+
+
+// virtual
+beans::Property SAL_CALL PropertySetInfo::getPropertyByName(
+ const OUString& aName )
+{
+ beans::Property aProp;
+ if ( queryProperty( aName, aProp ) )
+ return aProp;
+
+ throw beans::UnknownPropertyException(aName);
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName(
+ const OUString& Name )
+{
+ beans::Property aProp;
+ return queryProperty( Name, aProp );
+}
+
+
+// Non-Interface methods.
+
+
+void PropertySetInfo::reset()
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_xProps.reset();
+}
+
+
+bool PropertySetInfo::queryProperty(
+ std::u16string_view rName, beans::Property& rProp )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ getPropertiesImpl();
+
+ const beans::Property* pProps = m_xProps->getConstArray();
+ sal_Int32 nCount = m_xProps->getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const beans::Property& rCurrProp = pProps[ n ];
+ if ( rCurrProp.Name == rName )
+ {
+ rProp = rCurrProp;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+// CommandProcessorInfo Implementation.
+
+
+CommandProcessorInfo::CommandProcessorInfo(
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv,
+ ContentImplHelper* pContent )
+: m_xEnv(std::move( xEnv )),
+ m_pContent( pContent )
+{
+}
+
+
+// virtual
+CommandProcessorInfo::~CommandProcessorInfo()
+{
+}
+
+
+// XCommandInfo methods.
+
+
+// virtual
+uno::Sequence< css::ucb::CommandInfo > SAL_CALL CommandProcessorInfo::getCommands()
+{
+ std::unique_lock aGuard( m_aMutex );
+ return getCommandsImpl();
+}
+
+const uno::Sequence< css::ucb::CommandInfo > & CommandProcessorInfo::getCommandsImpl()
+{
+ if ( m_xCommands )
+ return *m_xCommands;
+
+ // Get info for commands.
+
+ try
+ {
+ m_xCommands = m_pContent->getCommands( m_xEnv );
+ }
+ catch ( uno::RuntimeException const & )
+ {
+ throw;
+ }
+ catch ( uno::Exception const & )
+ {
+ m_xCommands.emplace();
+ }
+ return *m_xCommands;
+}
+
+
+// virtual
+css::ucb::CommandInfo SAL_CALL
+CommandProcessorInfo::getCommandInfoByName(
+ const OUString& Name )
+{
+ css::ucb::CommandInfo aInfo;
+ if ( queryCommand( Name, aInfo ) )
+ return aInfo;
+
+ throw css::ucb::UnsupportedCommandException();
+}
+
+
+// virtual
+css::ucb::CommandInfo SAL_CALL
+CommandProcessorInfo::getCommandInfoByHandle( sal_Int32 Handle )
+{
+ css::ucb::CommandInfo aInfo;
+ if ( queryCommand( Handle, aInfo ) )
+ return aInfo;
+
+ throw css::ucb::UnsupportedCommandException();
+}
+
+
+// virtual
+sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByName(
+ const OUString& Name )
+{
+ css::ucb::CommandInfo aInfo;
+ return queryCommand( Name, aInfo );
+}
+
+
+// virtual
+sal_Bool SAL_CALL CommandProcessorInfo::hasCommandByHandle( sal_Int32 Handle )
+{
+ css::ucb::CommandInfo aInfo;
+ return queryCommand( Handle, aInfo );
+}
+
+
+// Non-Interface methods.
+
+
+void CommandProcessorInfo::reset()
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_xCommands.reset();
+}
+
+
+bool CommandProcessorInfo::queryCommand(
+ std::u16string_view rName,
+ css::ucb::CommandInfo& rCommand )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ getCommandsImpl();
+
+ const css::ucb::CommandInfo* pCommands
+ = m_xCommands->getConstArray();
+ sal_Int32 nCount = m_xCommands->getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const css::ucb::CommandInfo& rCurrCommand = pCommands[ n ];
+ if ( rCurrCommand.Name == rName )
+ {
+ rCommand = rCurrCommand;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool CommandProcessorInfo::queryCommand(
+ sal_Int32 nHandle,
+ css::ucb::CommandInfo& rCommand )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ getCommandsImpl();
+
+ const css::ucb::CommandInfo* pCommands = m_xCommands->getConstArray();
+ sal_Int32 nCount = m_xCommands->getLength();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const css::ucb::CommandInfo& rCurrCommand = pCommands[ n ];
+ if ( rCurrCommand.Handle == nHandle )
+ {
+ rCommand = rCurrCommand;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/contentinfo.hxx b/ucbhelper/source/provider/contentinfo.hxx
new file mode 100644
index 0000000000..b24a291ccb
--- /dev/null
+++ b/ucbhelper/source/provider/contentinfo.hxx
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX
+#define UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX
+
+#include <optional>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <mutex>
+
+namespace com::sun::star::ucb { class XCommandEnvironment; }
+
+namespace ucbhelper {
+
+
+
+
+class ContentImplHelper;
+
+/**
+ * This class provides a propertyset info ( the complete implementation of
+ * the interface XPropertySetInfo ) for an object derived from class
+ * ucb::ContentImplHelper. The implementation takes care about Additional
+ * Core Properties that may have been added to the content.
+ */
+class PropertySetInfo :
+ public cppu::WeakImplHelper<css::beans::XPropertySetInfo>
+{
+ css::uno::Reference< css::ucb::XCommandEnvironment >
+ m_xEnv;
+ std::optional<css::uno::Sequence< css::beans::Property >>
+ m_xProps;
+ std::mutex m_aMutex;
+ ContentImplHelper* m_pContent;
+
+private:
+ bool queryProperty( std::u16string_view rName,
+ css::beans::Property& rProp );
+ const css::uno::Sequence< css::beans::Property > & getPropertiesImpl();
+
+public:
+ PropertySetInfo( css::uno::Reference< css::ucb::XCommandEnvironment > xEnv,
+ ContentImplHelper* pContent );
+ virtual ~PropertySetInfo() 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;
+
+ // Non-Interface methods.
+ void reset();
+};
+
+
+
+
+/**
+ * This class provides a command info ( the complete implementation of
+ * the interface XCommandInfo ) for an object derived from class
+ * ucb::ContentImplHelper.
+ */
+class CommandProcessorInfo :
+ public cppu::WeakImplHelper<css::ucb::XCommandInfo>
+{
+ css::uno::Reference< css::ucb::XCommandEnvironment >
+ m_xEnv;
+ std::optional<css::uno::Sequence< css::ucb::CommandInfo >>
+ m_xCommands;
+ std::mutex m_aMutex;
+ ContentImplHelper* m_pContent;
+
+private:
+ bool queryCommand( std::u16string_view rName,
+ css::ucb::CommandInfo& rCommand );
+ bool queryCommand( sal_Int32 nHandle,
+ css::ucb::CommandInfo& rCommand );
+ const css::uno::Sequence< css::ucb::CommandInfo > & getCommandsImpl();
+
+public:
+ CommandProcessorInfo( css::uno::Reference< css::ucb::XCommandEnvironment > xEnv,
+ ContentImplHelper* pContent );
+ virtual ~CommandProcessorInfo() override;
+
+ // XCommandInfo
+ virtual css::uno::Sequence< css::ucb::CommandInfo > SAL_CALL getCommands() override;
+ virtual css::ucb::CommandInfo SAL_CALL getCommandInfoByName( const OUString& Name ) override;
+ virtual css::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;
+
+ // Non-Interface methods.
+ void reset();
+};
+
+} // namespace ucbhelper
+
+#endif /* ! UCBHELPER_SOURCE_PROVIDER_CONTENTINFO_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/interactionrequest.cxx b/ucbhelper/source/provider/interactionrequest.cxx
new file mode 100644
index 0000000000..0ac7ec9499
--- /dev/null
+++ b/ucbhelper/source/provider/interactionrequest.cxx
@@ -0,0 +1,626 @@
+/* -*- 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 <ucbhelper/interactionrequest.hxx>
+
+#include <rtl/ref.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <utility>
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+
+// InteractionRequest Implementation.
+
+
+namespace ucbhelper
+{
+
+struct InteractionRequest_Impl
+{
+ rtl::Reference< InteractionContinuation > m_xSelection;
+ css::uno::Any m_aRequest;
+ css::uno::Sequence<
+ css::uno::Reference<
+ css::task::XInteractionContinuation > > m_aContinuations;
+
+ InteractionRequest_Impl() {}
+ explicit InteractionRequest_Impl( uno::Any aRequest )
+ : m_aRequest(std::move( aRequest )) {}
+};
+
+}
+
+
+InteractionRequest::InteractionRequest()
+: m_pImpl( new InteractionRequest_Impl )
+{
+}
+
+
+InteractionRequest::InteractionRequest( const uno::Any & rRequest )
+: m_pImpl( new InteractionRequest_Impl( rRequest ) )
+{
+}
+
+
+// virtual
+InteractionRequest::~InteractionRequest()
+{
+}
+
+
+void InteractionRequest::setRequest( const uno::Any & rRequest )
+{
+ m_pImpl->m_aRequest = rRequest;
+}
+
+
+void InteractionRequest::setContinuations(
+ const uno::Sequence< uno::Reference<
+ task::XInteractionContinuation > > & rContinuations )
+{
+ m_pImpl->m_aContinuations = rContinuations;
+}
+
+
+rtl::Reference< InteractionContinuation > const &
+InteractionRequest::getSelection() const
+{
+ return m_pImpl->m_xSelection;
+}
+
+
+void InteractionRequest::setSelection(
+ const rtl::Reference< InteractionContinuation > & rxSelection )
+{
+ m_pImpl->m_xSelection = rxSelection;
+}
+
+
+// XInterface methods.
+
+
+// XInteractionRequest methods.
+
+
+// virtual
+uno::Any SAL_CALL InteractionRequest::getRequest()
+{
+ return m_pImpl->m_aRequest;
+}
+
+
+// virtual
+uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL
+InteractionRequest::getContinuations()
+{
+ return m_pImpl->m_aContinuations;
+}
+
+
+// InteractionContinuation Implementation.
+
+
+InteractionContinuation::InteractionContinuation(
+ InteractionRequest * pRequest )
+: m_pRequest( pRequest )
+{
+}
+
+
+// virtual
+InteractionContinuation::~InteractionContinuation()
+{
+}
+
+
+void InteractionContinuation::recordSelection()
+{
+ m_pRequest->setSelection( this );
+}
+
+
+// InteractionAbort Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionAbort::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< task::XInteractionAbort * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL InteractionAbort::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionAbort::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<task::XInteractionAbort>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionAbort::select()
+{
+ recordSelection();
+}
+
+
+// InteractionRetry Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionRetry::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< task::XInteractionRetry * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL InteractionRetry::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionRetry::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<task::XInteractionRetry>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionRetry::select()
+{
+ recordSelection();
+}
+
+
+// InteractionApprove Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionApprove::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< task::XInteractionApprove * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL InteractionApprove::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionApprove::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<task::XInteractionApprove>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionApprove::select()
+{
+ recordSelection();
+}
+
+
+// InteractionDisapprove Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionDisapprove::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< task::XInteractionDisapprove * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL InteractionDisapprove::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionDisapprove::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<task::XInteractionDisapprove>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionDisapprove::select()
+{
+ recordSelection();
+}
+
+
+// InteractionSupplyAuthentication Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionSupplyAuthentication::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< ucb::XInteractionSupplyAuthentication * >( this ),
+ static_cast< ucb::XInteractionSupplyAuthentication2 * >( this ));
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL
+InteractionSupplyAuthentication::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionSupplyAuthentication::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<ucb::XInteractionSupplyAuthentication2>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionSupplyAuthentication::select()
+{
+ recordSelection();
+}
+
+
+// XInteractionSupplyAuthentication methods.
+
+
+// virtual
+sal_Bool SAL_CALL
+InteractionSupplyAuthentication::canSetRealm()
+{
+ return m_bCanSetRealm;
+}
+
+
+// virtual
+void SAL_CALL
+InteractionSupplyAuthentication::setRealm( const OUString& Realm )
+{
+ OSL_ENSURE( m_bCanSetPassword,
+ "InteractionSupplyAuthentication::setRealm - Not supported!" );
+
+ if ( m_bCanSetRealm )
+ m_aRealm = Realm;
+}
+
+
+// virtual
+sal_Bool SAL_CALL
+InteractionSupplyAuthentication::canSetUserName()
+{
+ return m_bCanSetUserName;
+}
+
+
+// virtual
+void SAL_CALL
+InteractionSupplyAuthentication::setUserName( const OUString& UserName )
+{
+ OSL_ENSURE( m_bCanSetUserName,
+ "InteractionSupplyAuthentication::setUserName - Not supported!" );
+
+ if ( m_bCanSetUserName )
+ m_aUserName = UserName;
+}
+
+
+// virtual
+sal_Bool SAL_CALL
+InteractionSupplyAuthentication::canSetPassword()
+{
+ return m_bCanSetPassword;
+}
+
+
+// virtual
+void SAL_CALL
+InteractionSupplyAuthentication::setPassword( const OUString& Password )
+{
+ OSL_ENSURE( m_bCanSetPassword,
+ "InteractionSupplyAuthentication::setPassword - Not supported!" );
+
+ if ( m_bCanSetPassword )
+ m_aPassword = Password;
+}
+
+
+// virtual
+uno::Sequence< ucb::RememberAuthentication > SAL_CALL
+InteractionSupplyAuthentication::getRememberPasswordModes(
+ ucb::RememberAuthentication& Default )
+{
+ Default = m_eDefaultRememberPasswordMode;
+ return m_aRememberPasswordModes;
+}
+
+
+// virtual
+void SAL_CALL
+InteractionSupplyAuthentication::setRememberPassword(
+ ucb::RememberAuthentication Remember )
+{
+ m_eRememberPasswordMode = Remember;
+}
+
+
+// virtual
+sal_Bool SAL_CALL
+InteractionSupplyAuthentication::canSetAccount()
+{
+ return m_bCanSetAccount;
+}
+
+
+// virtual
+void SAL_CALL
+InteractionSupplyAuthentication::setAccount( const OUString& /*Account*/ )
+{
+ OSL_ENSURE( m_bCanSetAccount,
+ "InteractionSupplyAuthentication::setAccount - Not supported!" );
+}
+
+
+// virtual
+uno::Sequence< ucb::RememberAuthentication > SAL_CALL
+InteractionSupplyAuthentication::getRememberAccountModes(
+ ucb::RememberAuthentication& Default )
+{
+ Default = m_eDefaultRememberAccountMode;
+ return m_aRememberAccountModes;
+}
+
+
+// virtual
+void SAL_CALL InteractionSupplyAuthentication::setRememberAccount(
+ ucb::RememberAuthentication )
+{
+}
+
+
+// XInteractionSupplyAuthentication2 methods.
+
+
+// virtual
+sal_Bool SAL_CALL
+InteractionSupplyAuthentication::canUseSystemCredentials(
+ sal_Bool& Default )
+{
+ Default = false;
+ return m_bCanUseSystemCredentials;
+}
+
+
+// virtual
+void SAL_CALL InteractionSupplyAuthentication::setUseSystemCredentials(
+ sal_Bool UseSystemCredentials )
+{
+ if ( m_bCanUseSystemCredentials )
+ m_bUseSystemCredentials = UseSystemCredentials;
+}
+
+
+// InteractionReplaceExistingData Implementation.
+
+
+// XInterface methods.
+
+
+// virtual
+uno::Any SAL_CALL
+InteractionReplaceExistingData::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< ucb::XInteractionReplaceExistingData * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+
+// XTypeProvider methods.
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL
+InteractionReplaceExistingData::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+
+// virtual
+uno::Sequence< uno::Type > SAL_CALL InteractionReplaceExistingData::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<ucb::XInteractionReplaceExistingData>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+
+// XInteractionContinuation methods.
+
+
+// virtual
+void SAL_CALL InteractionReplaceExistingData::select()
+{
+ recordSelection();
+}
+
+// InteractionAuthFallback Implementation
+
+// XInterface methods.
+
+// virtual
+uno::Any SAL_CALL
+InteractionAuthFallback::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< ucb::XInteractionAuthFallback * >( this ));
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+// XInteractionContinuation methods.
+
+// virtual
+void SAL_CALL InteractionAuthFallback::select()
+{
+ recordSelection();
+}
+
+// XInteractionAuthFallback methods
+
+// virtual
+void SAL_CALL InteractionAuthFallback::setCode( const OUString& code )
+{
+ m_aCode = code;
+}
+
+const OUString& InteractionAuthFallback::getCode() const
+{
+ return m_aCode;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/propertyvalueset.cxx b/ucbhelper/source/provider/propertyvalueset.cxx
new file mode 100644
index 0000000000..b019d3b9c8
--- /dev/null
+++ b/ucbhelper/source/provider/propertyvalueset.cxx
@@ -0,0 +1,680 @@
+/* -*- 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 <vector>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/Converter.hpp>
+
+#include <osl/diagnose.h>
+#include <ucbhelper/propertyvalueset.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::container;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::script;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+
+enum class PropsSet {
+ NONE = 0x00000000,
+ String = 0x00000001,
+ Boolean = 0x00000002,
+ Byte = 0x00000004,
+ Short = 0x00000008,
+ Int = 0x00000010,
+ Long = 0x00000020,
+ Float = 0x00000040,
+ Double = 0x00000080,
+ Bytes = 0x00000100,
+ Date = 0x00000200,
+ Time = 0x00000400,
+ Timestamp = 0x00000800,
+ BinaryStream = 0x00001000,
+ CharacterStream = 0x00002000,
+ Ref = 0x00004000,
+ Blob = 0x00008000,
+ Clob = 0x00010000,
+ Array = 0x00020000,
+ Object = 0x00040000
+};
+namespace o3tl {
+ template<> struct typed_flags<PropsSet> : is_typed_flags<PropsSet, 0x0007ffff> {};
+}
+
+namespace ucbhelper_impl
+{
+
+
+struct PropertyValue
+{
+ OUString sPropertyName;
+
+ PropsSet nPropsSet;
+ PropsSet nOrigValue;
+
+ OUString aString; // getString
+ bool bBoolean; // getBoolean
+ sal_Int8 nByte; // getByte
+ sal_Int16 nShort; // getShort
+ sal_Int32 nInt; // getInt
+ sal_Int64 nLong; // getLong
+ float nFloat; // getFloat
+ double nDouble; // getDouble
+
+ Sequence< sal_Int8 > aBytes; // getBytes
+ Date aDate; // getDate
+ Time aTime; // getTime
+ DateTime aTimestamp; // getTimestamp
+ Reference< XInputStream > xBinaryStream; // getBinaryStream
+ Reference< XInputStream > xCharacterStream; // getCharacterStream
+ Reference< XRef > xRef; // getRef
+ Reference< XBlob > xBlob; // getBlob
+ Reference< XClob > xClob; // getClob
+ Reference< XArray > xArray; // getArray
+ Any aObject; // getObject
+
+ PropertyValue()
+ : nPropsSet( PropsSet::NONE ), nOrigValue( PropsSet::NONE ),
+ bBoolean(false),
+ nByte(0),
+ nShort(0),
+ nInt(0),
+ nLong(0),
+ nFloat(0.0),
+ nDouble(0.0)
+ {}
+};
+} // namespace ucbhelper_impl
+
+using namespace ucbhelper_impl;
+
+namespace ucbhelper
+{
+
+class PropertyValues : public std::vector< ucbhelper_impl::PropertyValue > {};
+
+} // namespace ucbhelper
+
+
+namespace ucbhelper {
+
+
+// PropertyValueSet Implementation.
+
+
+PropertyValueSet::PropertyValueSet(
+ const Reference< XComponentContext >& rxContext )
+: m_xContext( rxContext ),
+ m_pValues( new PropertyValues ),
+ m_bWasNull( false ),
+ m_bTriedToGetTypeConverter( false )
+
+{
+}
+
+
+// virtual
+PropertyValueSet::~PropertyValueSet()
+{
+}
+
+
+// XRow methods.
+
+
+template <class T, T ucbhelper_impl::PropertyValue::*_member_name_>
+T PropertyValueSet::getValue(PropsSet nTypeName, sal_Int32 columnIndex)
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ T aValue {}; /* default ctor */
+
+ m_bWasNull = true;
+
+ if ( ( columnIndex < 1 ) || ( o3tl::make_unsigned(columnIndex) > m_pValues->size() ) )
+ {
+ OSL_FAIL( "PropertyValueSet - index out of range!" );
+ return aValue;
+ }
+ ucbhelper_impl::PropertyValue& rValue = (*m_pValues)[ columnIndex - 1 ];
+
+ if ( rValue.nOrigValue == PropsSet::NONE )
+ return aValue;
+
+ if ( rValue.nPropsSet & nTypeName )
+ {
+ /* Values is present natively... */
+ aValue = rValue.*_member_name_;
+ m_bWasNull = false;
+ return aValue;
+ }
+
+ if ( !(rValue.nPropsSet & PropsSet::Object) )
+ {
+ /* Value is not (yet) available as Any. Create it. */
+ getObject( columnIndex, Reference< XNameAccess >() );
+ }
+
+ if ( rValue.nPropsSet & PropsSet::Object )
+ {
+ /* Value is available as Any. */
+
+ if ( rValue.aObject.hasValue() )
+ {
+ /* Try to convert into native value. */
+ if ( rValue.aObject >>= aValue )
+ {
+ rValue.*_member_name_ = aValue;
+ rValue.nPropsSet |= nTypeName;
+ m_bWasNull = false;
+ }
+ else
+ {
+ /* Last chance. Try type converter service... */
+
+ Reference< XTypeConverter > xConverter = getTypeConverter();
+ if ( xConverter.is() )
+ {
+ try
+ {
+ Any aConvAny = xConverter->convertTo(
+ rValue.aObject,
+ cppu::UnoType<T>::get() );
+
+ if ( aConvAny >>= aValue )
+ {
+ rValue.*_member_name_ = aValue;
+ rValue.nPropsSet |= nTypeName;
+ m_bWasNull = false;
+ }
+ }
+ catch (const IllegalArgumentException&)
+ {
+ }
+ catch (const CannotConvertException&)
+ {
+ }
+ }
+ }
+ }
+ }
+
+ return aValue;
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertyValueSet::wasNull()
+{
+ // This method can not be implemented correctly!!! Imagine different
+ // threads doing a getXYZ - wasNull calling sequence on the same
+ // implementation object...
+ return m_bWasNull;
+}
+
+
+// virtual
+OUString SAL_CALL PropertyValueSet::getString( sal_Int32 columnIndex )
+{
+ return getValue<OUString, &ucbhelper_impl::PropertyValue::aString>(PropsSet::String, columnIndex);
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertyValueSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue<bool, &ucbhelper_impl::PropertyValue::bBoolean>(PropsSet::Boolean, columnIndex);
+}
+
+
+// virtual
+sal_Int8 SAL_CALL PropertyValueSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int8, &ucbhelper_impl::PropertyValue::nByte>(PropsSet::Byte, columnIndex);
+}
+
+
+// virtual
+sal_Int16 SAL_CALL PropertyValueSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int16, &ucbhelper_impl::PropertyValue::nShort>(PropsSet::Short, columnIndex);
+}
+
+
+// virtual
+sal_Int32 SAL_CALL PropertyValueSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int32, &ucbhelper_impl::PropertyValue::nInt>(PropsSet::Int, columnIndex);
+}
+
+
+// virtual
+sal_Int64 SAL_CALL PropertyValueSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue<sal_Int64, &ucbhelper_impl::PropertyValue::nLong>(PropsSet::Long, columnIndex);
+}
+
+
+// virtual
+float SAL_CALL PropertyValueSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue<float, &ucbhelper_impl::PropertyValue::nFloat>(PropsSet::Float, columnIndex);
+}
+
+
+// virtual
+double SAL_CALL PropertyValueSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue<double, &ucbhelper_impl::PropertyValue::nDouble>(PropsSet::Double, columnIndex);
+}
+
+
+// virtual
+Sequence< sal_Int8 > SAL_CALL
+PropertyValueSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue<Sequence< sal_Int8 >, &ucbhelper_impl::PropertyValue::aBytes>(PropsSet::Bytes, columnIndex);
+}
+
+
+// virtual
+Date SAL_CALL PropertyValueSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue<Date, &ucbhelper_impl::PropertyValue::aDate>(PropsSet::Date, columnIndex);
+}
+
+
+// virtual
+Time SAL_CALL PropertyValueSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue<Time, &ucbhelper_impl::PropertyValue::aTime>(PropsSet::Time, columnIndex);
+}
+
+
+// virtual
+DateTime SAL_CALL PropertyValueSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue<DateTime, &ucbhelper_impl::PropertyValue::aTimestamp>(PropsSet::Timestamp, columnIndex);
+}
+
+
+// virtual
+Reference< XInputStream > SAL_CALL
+PropertyValueSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XInputStream >, &ucbhelper_impl::PropertyValue::xBinaryStream>(PropsSet::BinaryStream, columnIndex);
+}
+
+
+// virtual
+Reference< XInputStream > SAL_CALL
+PropertyValueSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XInputStream >, &ucbhelper_impl::PropertyValue::xCharacterStream>(PropsSet::CharacterStream, columnIndex);
+}
+
+
+// virtual
+Any SAL_CALL PropertyValueSet::getObject(
+ sal_Int32 columnIndex,
+ const Reference< XNameAccess >& )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ Any aValue;
+
+ m_bWasNull = true;
+
+ if ( ( columnIndex < 1 )
+ || ( o3tl::make_unsigned(columnIndex) > m_pValues->size() ) )
+ {
+ OSL_FAIL( "PropertyValueSet - index out of range!" );
+ }
+ else
+ {
+ ucbhelper_impl::PropertyValue& rValue
+ = (*m_pValues)[ columnIndex - 1 ];
+
+ if ( rValue.nPropsSet & PropsSet::Object )
+ {
+ // Values is present natively...
+ aValue = rValue.aObject;
+ m_bWasNull = false;
+ }
+ else
+ {
+ // Make Any from original value.
+
+ switch ( rValue.nOrigValue )
+ {
+ case PropsSet::NONE:
+ break;
+
+ case PropsSet::String:
+ aValue <<= rValue.aString;
+ break;
+
+ case PropsSet::Boolean:
+ aValue <<= rValue.bBoolean;
+ break;
+
+ case PropsSet::Byte:
+ aValue <<= rValue.nByte;
+ break;
+
+ case PropsSet::Short:
+ aValue <<= rValue.nShort;
+ break;
+
+ case PropsSet::Int:
+ aValue <<= rValue.nInt;
+ break;
+
+ case PropsSet::Long:
+ aValue <<= rValue.nLong;
+ break;
+
+ case PropsSet::Float:
+ aValue <<= rValue.nFloat;
+ break;
+
+ case PropsSet::Double:
+ aValue <<= rValue.nDouble;
+ break;
+
+ case PropsSet::Bytes:
+ aValue <<= rValue.aBytes;
+ break;
+
+ case PropsSet::Date:
+ aValue <<= rValue.aDate;
+ break;
+
+ case PropsSet::Time:
+ aValue <<= rValue.aTime;
+ break;
+
+ case PropsSet::Timestamp:
+ aValue <<= rValue.aTimestamp;
+ break;
+
+ case PropsSet::BinaryStream:
+ aValue <<= rValue.xBinaryStream;
+ break;
+
+ case PropsSet::CharacterStream:
+ aValue <<= rValue.xCharacterStream;
+ break;
+
+ case PropsSet::Ref:
+ aValue <<= rValue.xRef;
+ break;
+
+ case PropsSet::Blob:
+ aValue <<= rValue.xBlob;
+ break;
+
+ case PropsSet::Clob:
+ aValue <<= rValue.xClob;
+ break;
+
+ case PropsSet::Array:
+ aValue <<= rValue.xArray;
+ break;
+
+ case PropsSet::Object:
+ // Fall-through is intended!
+ default:
+ OSL_FAIL( "PropertyValueSet::getObject - "
+ "Wrong original type" );
+ break;
+ }
+
+ if ( aValue.hasValue() )
+ {
+ rValue.aObject = aValue;
+ rValue.nPropsSet |= PropsSet::Object;
+ m_bWasNull = false;
+ }
+ }
+ }
+
+ return aValue;
+}
+
+
+// virtual
+Reference< XRef > SAL_CALL PropertyValueSet::getRef( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XRef >, &ucbhelper_impl::PropertyValue::xRef>(PropsSet::Ref, columnIndex);
+}
+
+
+// virtual
+Reference< XBlob > SAL_CALL PropertyValueSet::getBlob( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XBlob >, &ucbhelper_impl::PropertyValue::xBlob>(PropsSet::Blob, columnIndex);
+}
+
+
+// virtual
+Reference< XClob > SAL_CALL PropertyValueSet::getClob( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XClob >, &ucbhelper_impl::PropertyValue::xClob>(PropsSet::Clob, columnIndex);
+}
+
+
+// virtual
+Reference< XArray > SAL_CALL PropertyValueSet::getArray( sal_Int32 columnIndex )
+{
+ return getValue<Reference< XArray >, &ucbhelper_impl::PropertyValue::xArray>(PropsSet::Array, columnIndex);
+}
+
+
+// XColumnLocate methods.
+
+
+// virtual
+sal_Int32 SAL_CALL PropertyValueSet::findColumn( const OUString& columnName )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( !columnName.isEmpty() )
+ {
+ sal_Int32 nCount = m_pValues->size();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ if ( (*m_pValues)[ n ].sPropertyName == columnName )
+ return n + 1; // Index is 1-based.
+ }
+ }
+ return 0;
+}
+
+
+// Non-interface methods.
+
+
+const Reference< XTypeConverter >& PropertyValueSet::getTypeConverter()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( !m_bTriedToGetTypeConverter && !m_xTypeConverter.is() )
+ {
+ m_bTriedToGetTypeConverter = true;
+ m_xTypeConverter = Converter::create(m_xContext);
+
+ OSL_ENSURE( m_xTypeConverter.is(),
+ "PropertyValueSet::getTypeConverter() - "
+ "Service 'com.sun.star.script.Converter' n/a!" );
+ }
+ return m_xTypeConverter;
+}
+
+
+template <class T, T ucbhelper_impl::PropertyValue::*_member_name_>
+void PropertyValueSet::appendValue(const OUString& rPropName, PropsSet nTypeName, const T& rValue)
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ ucbhelper_impl::PropertyValue aNewValue;
+ aNewValue.sPropertyName = rPropName;
+ aNewValue.nPropsSet = nTypeName;
+ aNewValue.nOrigValue = nTypeName;
+ aNewValue.*_member_name_ = rValue;
+
+ m_pValues->push_back( aNewValue );
+}
+
+
+void PropertyValueSet::appendString( const OUString& rPropName,
+ const OUString& rValue )
+{
+ appendValue<OUString, &ucbhelper_impl::PropertyValue::aString>(rPropName, PropsSet::String, rValue);
+}
+
+
+void PropertyValueSet::appendBoolean( const OUString& rPropName,
+ bool bValue )
+{
+ appendValue<bool, &ucbhelper_impl::PropertyValue::bBoolean>(rPropName, PropsSet::Boolean, bValue);
+}
+
+
+void PropertyValueSet::appendLong( const OUString& rPropName,
+ sal_Int64 nValue )
+{
+ appendValue<sal_Int64, &ucbhelper_impl::PropertyValue::nLong>(rPropName, PropsSet::Long, nValue);
+}
+
+
+void PropertyValueSet::appendTimestamp( const OUString& rPropName,
+ const DateTime& rValue )
+{
+ appendValue<DateTime, &ucbhelper_impl::PropertyValue::aTimestamp>(rPropName, PropsSet::Timestamp, rValue);
+}
+
+
+void PropertyValueSet::appendObject( const OUString& rPropName,
+ const Any& rValue )
+{
+ appendValue<Any, &ucbhelper_impl::PropertyValue::aObject>(rPropName, PropsSet::Object, rValue);
+}
+
+
+void PropertyValueSet::appendVoid( const OUString& rPropName )
+{
+ appendValue<Any, &ucbhelper_impl::PropertyValue::aObject>(rPropName, PropsSet::NONE, Any());
+}
+
+
+void PropertyValueSet::appendPropertySet(
+ const Reference< XPropertySet >& rxSet )
+{
+ if ( !rxSet.is() )
+ return;
+
+ Reference< XPropertySetInfo > xInfo = rxSet->getPropertySetInfo();
+ if ( !xInfo.is() )
+ return;
+
+ const Sequence< Property > aProps = xInfo->getProperties();
+
+ Reference< XPropertyAccess > xPropertyAccess( rxSet, UNO_QUERY );
+ if ( xPropertyAccess.is() )
+ {
+ // Efficient: Get all prop values with one ( remote) call.
+
+ const Sequence< css::beans::PropertyValue > aPropValues
+ = xPropertyAccess->getPropertyValues();
+
+ for ( const css::beans::PropertyValue& rPropValue : aPropValues )
+ {
+ // Find info for current property value.
+ auto pProp = std::find_if(aProps.begin(), aProps.end(),
+ [&rPropValue](const Property& rProp) { return rProp.Name == rPropValue.Name; });
+ if (pProp != aProps.end())
+ {
+ // Found!
+ appendObject( *pProp, rPropValue.Value );
+ }
+ }
+ }
+ else
+ {
+ // Get every single prop value with one ( remote) call.
+
+ for ( const Property& rProp : aProps )
+ {
+ try
+ {
+ Any aValue = rxSet->getPropertyValue( rProp.Name );
+
+ if ( aValue.hasValue() )
+ appendObject( rProp, aValue );
+ }
+ catch (const UnknownPropertyException&)
+ {
+ }
+ catch (const WrappedTargetException&)
+ {
+ }
+ }
+ }
+}
+
+
+bool PropertyValueSet::appendPropertySetValue(
+ const Reference< XPropertySet >& rxSet,
+ const Property& rProperty )
+{
+ if ( rxSet.is() )
+ {
+ try
+ {
+ Any aValue = rxSet->getPropertyValue( rProperty.Name );
+ if ( aValue.hasValue() )
+ {
+ appendObject( rProperty, aValue );
+ return true;
+ }
+ }
+ catch (const UnknownPropertyException&)
+ {
+ }
+ catch (const WrappedTargetException&)
+ {
+ }
+ }
+
+ // Error.
+ return false;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/providerhelper.cxx b/ucbhelper/source/provider/providerhelper.cxx
new file mode 100644
index 0000000000..a15ba5457b
--- /dev/null
+++ b/ucbhelper/source/provider/providerhelper.cxx
@@ -0,0 +1,497 @@
+/* -*- 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/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/PropertyExistException.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/ucb/Store.hpp>
+#include <com/sun/star/ucb/XPropertySetRegistry.hpp>
+#include <com/sun/star/ucb/XPropertySetRegistryFactory.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <ucbhelper/contenthelper.hxx>
+#include <ucbhelper/providerhelper.hxx>
+
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <unordered_map>
+#include <utility>
+
+using namespace com::sun::star;
+
+namespace ucbhelper_impl
+{
+
+typedef std::unordered_map
+<
+ OUString,
+ uno::WeakReference< ucb::XContent >
+>
+Contents;
+
+struct ContentProviderImplHelper_Impl
+{
+ uno::Reference< css::ucb::XPropertySetRegistry > m_xPropertySetRegistry;
+ Contents m_aContents;
+};
+
+} // namespace ucbhelper_impl
+
+namespace ucbhelper {
+
+ContentProviderImplHelper::ContentProviderImplHelper(
+ uno::Reference< uno::XComponentContext > xContext )
+: m_pImpl( new ucbhelper_impl::ContentProviderImplHelper_Impl ),
+ m_xContext(std::move( xContext ))
+{
+}
+
+// virtual
+ContentProviderImplHelper::~ContentProviderImplHelper()
+{
+}
+
+// virtual
+sal_Bool SAL_CALL ContentProviderImplHelper::supportsService(
+ const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// virtual
+sal_Int32 SAL_CALL ContentProviderImplHelper::compareContentIds(
+ const uno::Reference< css::ucb::XContentIdentifier >& Id1,
+ const uno::Reference< css::ucb::XContentIdentifier >& Id2 )
+{
+ // Simply do a string compare.
+
+ OUString aURL1( Id1->getContentIdentifier() );
+ OUString aURL2( Id2->getContentIdentifier() );
+
+ return aURL1.compareTo( aURL2 );
+}
+
+void ContentProviderImplHelper::cleanupRegisteredContents()
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ ucbhelper_impl::Contents::iterator it
+ = m_pImpl->m_aContents.begin();
+ while( it != m_pImpl->m_aContents.end() )
+ {
+ uno::Reference< ucb::XContent > xContent( (*it).second );
+ if ( !xContent.is() )
+ {
+ ucbhelper_impl::Contents::iterator tmp = it;
+ ++it;
+ m_pImpl->m_aContents.erase( tmp );
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+void ContentProviderImplHelper::removeContent( ContentImplHelper* pContent )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ cleanupRegisteredContents();
+
+ const OUString aURL(
+ pContent->getIdentifier()->getContentIdentifier() );
+
+ ucbhelper_impl::Contents::iterator it = m_pImpl->m_aContents.find( aURL );
+
+ if ( it != m_pImpl->m_aContents.end() )
+ m_pImpl->m_aContents.erase( it );
+}
+
+rtl::Reference< ContentImplHelper >
+ContentProviderImplHelper::queryExistingContent(
+ const uno::Reference< css::ucb::XContentIdentifier >& Identifier )
+{
+ return queryExistingContent( Identifier->getContentIdentifier() );
+}
+
+rtl::Reference< ContentImplHelper >
+ContentProviderImplHelper::queryExistingContent( const OUString& rURL )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ cleanupRegisteredContents();
+
+ // Check, if a content with given id already exists...
+
+ ucbhelper_impl::Contents::const_iterator it
+ = m_pImpl->m_aContents.find( rURL );
+ if ( it != m_pImpl->m_aContents.end() )
+ {
+ uno::Reference< ucb::XContent > xContent( (*it).second );
+ if ( xContent.is() )
+ {
+ return rtl::Reference< ContentImplHelper >(
+ static_cast< ContentImplHelper * >( xContent.get() ) );
+ }
+ }
+ return rtl::Reference< ContentImplHelper >();
+}
+
+void ContentProviderImplHelper::queryExistingContents(
+ ContentRefList& rContents )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ cleanupRegisteredContents();
+
+ for ( const auto& rContent : m_pImpl->m_aContents )
+ {
+ uno::Reference< ucb::XContent > xContent( rContent.second );
+ if ( xContent.is() )
+ {
+ rContents.emplace_back(
+ static_cast< ContentImplHelper * >( xContent.get() ) );
+ }
+ }
+}
+
+void ContentProviderImplHelper::registerNewContent(
+ const uno::Reference< ucb::XContent > & xContent )
+{
+ if ( !xContent.is() )
+ return;
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ cleanupRegisteredContents();
+
+ const OUString aURL(
+ xContent->getIdentifier()->getContentIdentifier() );
+ ucbhelper_impl::Contents::const_iterator it
+ = m_pImpl->m_aContents.find( aURL );
+ if ( it == m_pImpl->m_aContents.end() )
+ m_pImpl->m_aContents[ aURL ] = xContent;
+}
+
+uno::Reference< css::ucb::XPropertySetRegistry >
+ContentProviderImplHelper::getAdditionalPropertySetRegistry()
+{
+ // Get propertyset registry.
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_pImpl->m_xPropertySetRegistry.is() )
+ {
+ uno::Reference< css::ucb::XPropertySetRegistryFactory >
+ xRegFac = css::ucb::Store::create( m_xContext );
+
+ // Open/create a registry.
+ m_pImpl->m_xPropertySetRegistry
+ = xRegFac->createPropertySetRegistry( OUString() );
+
+ OSL_ENSURE( m_pImpl->m_xPropertySetRegistry.is(),
+ "ContentProviderImplHelper::getAdditionalPropertySet - "
+ "Error opening registry!" );
+ }
+
+ return m_pImpl->m_xPropertySetRegistry;
+}
+
+uno::Reference< css::ucb::XPersistentPropertySet >
+ContentProviderImplHelper::getAdditionalPropertySet(
+ const OUString& rKey, bool bCreate )
+{
+ // Get propertyset registry.
+ getAdditionalPropertySetRegistry();
+
+ if ( m_pImpl->m_xPropertySetRegistry.is() )
+ {
+ // Open/create persistent property set.
+ return m_pImpl->m_xPropertySetRegistry->openPropertySet(
+ rKey, bCreate );
+ }
+
+ return uno::Reference< css::ucb::XPersistentPropertySet >();
+}
+
+bool ContentProviderImplHelper::renameAdditionalPropertySet(
+ const OUString& rOldKey,
+ const OUString& rNewKey,
+ bool bRecursive )
+{
+ if ( rOldKey == rNewKey )
+ return true;
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( bRecursive )
+ {
+ // Get propertyset registry.
+ getAdditionalPropertySetRegistry();
+
+ if ( !m_pImpl->m_xPropertySetRegistry.is() )
+ return false;
+
+ uno::Reference< container::XNameAccess > xNameAccess(
+ m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
+ if ( !xNameAccess.is() )
+ return false;
+
+ const uno::Sequence< OUString > aKeys
+ = xNameAccess->getElementNames();
+ if ( aKeys.hasElements() )
+ {
+ OUString aOldKeyWithSlash = rOldKey;
+ OUString aOldKeyWithoutSlash;
+ if ( !aOldKeyWithSlash.endsWith("/") )
+ {
+ aOldKeyWithSlash += "/";
+ aOldKeyWithoutSlash = rOldKey;
+ }
+ else if ( !rOldKey.isEmpty() )
+ aOldKeyWithoutSlash
+ = rOldKey.copy( 0, rOldKey.getLength() - 1 );
+
+ for ( const OUString& rKey : aKeys )
+ {
+ if ( rKey.startsWith( aOldKeyWithSlash )
+ || rKey == aOldKeyWithoutSlash )
+ {
+ OUString aNewKey
+ = rKey.replaceAt(
+ 0, rOldKey.getLength(), rNewKey );
+ if ( !renameAdditionalPropertySet(
+ rKey, aNewKey, false ) )
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Get old property set, if exists.
+ uno::Reference< css::ucb::XPersistentPropertySet > xOldSet
+ = getAdditionalPropertySet( rOldKey, false );
+ if ( xOldSet.is() )
+ {
+ // Rename property set.
+ uno::Reference< container::XNamed > xNamed(
+ xOldSet, uno::UNO_QUERY );
+ if ( !xNamed.is() )
+ return false;
+
+ // ??? throws no exceptions and has no return value ???
+ xNamed->setName( rNewKey );
+ }
+ }
+ return true;
+}
+
+bool ContentProviderImplHelper::copyAdditionalPropertySet(
+ const OUString& rSourceKey,
+ const OUString& rTargetKey,
+ bool bRecursive )
+{
+ if ( rSourceKey == rTargetKey )
+ return true;
+
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( bRecursive )
+ {
+ // Get propertyset registry.
+ getAdditionalPropertySetRegistry();
+
+ if ( !m_pImpl->m_xPropertySetRegistry.is() )
+ return false;
+
+ uno::Reference< container::XNameAccess > xNameAccess(
+ m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
+ if ( !xNameAccess.is() )
+ return false;
+
+ const uno::Sequence< OUString > aKeys
+ = xNameAccess->getElementNames();
+ if ( aKeys.hasElements() )
+ {
+ OUString aSrcKeyWithSlash = rSourceKey;
+ OUString aSrcKeyWithoutSlash;
+ if ( !aSrcKeyWithSlash.endsWith("/") )
+ {
+ aSrcKeyWithSlash += "/";
+ aSrcKeyWithoutSlash = rSourceKey;
+ }
+ else if ( !rSourceKey.isEmpty() )
+ aSrcKeyWithoutSlash = rSourceKey.copy(
+ 0, rSourceKey.getLength() - 1 );
+
+ for ( const OUString& rKey : aKeys )
+ {
+ if ( rKey.startsWith(aSrcKeyWithSlash )
+ || rKey == aSrcKeyWithoutSlash )
+ {
+ OUString aNewKey
+ = rKey.replaceAt(
+ 0, rSourceKey.getLength(), rTargetKey );
+ if ( !copyAdditionalPropertySet(
+ rKey, aNewKey, false ) )
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Get old property set, if exists.
+ uno::Reference< css::ucb::XPersistentPropertySet >
+ xOldPropSet = getAdditionalPropertySet( rSourceKey, false );
+ if ( !xOldPropSet.is() )
+ return false;
+
+ uno::Reference< beans::XPropertySetInfo > xPropSetInfo
+ = xOldPropSet->getPropertySetInfo();
+ if ( !xPropSetInfo.is() )
+ return false;
+
+ uno::Reference< beans::XPropertyAccess > xOldPropAccess(
+ xOldPropSet, uno::UNO_QUERY );
+ if ( !xOldPropAccess.is() )
+ return false;
+
+ // Obtain all values from old set.
+ const uno::Sequence< beans::PropertyValue > aValues
+ = xOldPropAccess->getPropertyValues();
+
+ const uno::Sequence< beans::Property > aProps
+ = xPropSetInfo->getProperties();
+
+ if ( aValues.hasElements() )
+ {
+ // Fail, if property set with new key already exists.
+ uno::Reference< css::ucb::XPersistentPropertySet >
+ xNewPropSet
+ = getAdditionalPropertySet( rTargetKey, false );
+ if ( xNewPropSet.is() )
+ return false;
+
+ // Create new, empty set.
+ xNewPropSet = getAdditionalPropertySet( rTargetKey, true );
+ if ( !xNewPropSet.is() )
+ return false;
+
+ uno::Reference< beans::XPropertyContainer > xNewPropContainer(
+ xNewPropSet, uno::UNO_QUERY );
+ if ( !xNewPropContainer.is() )
+ return false;
+
+ for ( const beans::PropertyValue& rValue : aValues )
+ {
+ sal_Int16 nAttribs = 0;
+ auto pProp = std::find_if(aProps.begin(), aProps.end(),
+ [&rValue](const beans::Property& rProp) { return rProp.Name == rValue.Name; });
+ if (pProp != aProps.end())
+ nAttribs = pProp->Attributes;
+
+ try
+ {
+ xNewPropContainer->addProperty(
+ rValue.Name, nAttribs, rValue.Value );
+ }
+ catch ( beans::PropertyExistException & )
+ {
+ }
+ catch ( beans::IllegalTypeException & )
+ {
+ }
+ catch ( lang::IllegalArgumentException & )
+ {
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool ContentProviderImplHelper::removeAdditionalPropertySet(
+ const OUString& rKey, bool bRecursive )
+{
+ osl::MutexGuard aGuard( m_aMutex );
+
+ if ( bRecursive )
+ {
+ // Get propertyset registry.
+ getAdditionalPropertySetRegistry();
+
+ if ( !m_pImpl->m_xPropertySetRegistry.is() )
+ return false;
+
+ uno::Reference< container::XNameAccess > xNameAccess(
+ m_pImpl->m_xPropertySetRegistry, uno::UNO_QUERY );
+ if ( !xNameAccess.is() )
+ return false;
+
+ const uno::Sequence< OUString > aKeys
+ = xNameAccess->getElementNames();
+ if ( aKeys.hasElements() )
+ {
+ OUString aKeyWithSlash = rKey;
+ OUString aKeyWithoutSlash;
+ if ( !aKeyWithSlash.endsWith("/") )
+ {
+ aKeyWithSlash += "/";
+ aKeyWithoutSlash = rKey;
+ }
+ else if ( !rKey.isEmpty() )
+ aKeyWithoutSlash
+ = rKey.copy( 0, rKey.getLength() - 1 );
+
+ for ( const OUString& rCurrKey : aKeys )
+ {
+ if ( rCurrKey.startsWith(aKeyWithSlash )
+ || rCurrKey == aKeyWithoutSlash )
+ {
+ if ( !removeAdditionalPropertySet(
+ rCurrKey, false ) )
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Get propertyset registry.
+ getAdditionalPropertySetRegistry();
+
+ if ( !m_pImpl->m_xPropertySetRegistry.is() )
+ return false;
+
+ m_pImpl->m_xPropertySetRegistry->removePropertySet( rKey );
+ }
+ return true;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/registerucb.cxx b/ucbhelper/source/provider/registerucb.cxx
new file mode 100644
index 0000000000..baf0e5b3f6
--- /dev/null
+++ b/ucbhelper/source/provider/registerucb.cxx
@@ -0,0 +1,139 @@
+/* -*- 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 <ucbhelper/registerucb.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/ucb/DuplicateProviderException.hpp>
+#include <com/sun/star/ucb/XContentProviderManager.hpp>
+#include <com/sun/star/ucb/XParameterizedContentProvider.hpp>
+#include <com/sun/star/ucb/ContentProviderProxyFactory.hpp>
+#include <com/sun/star/ucb/XContentProviderFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+namespace ucbhelper {
+
+bool
+registerAtUcb(
+ uno::Reference< ucb::XContentProviderManager > const & rManager,
+ uno::Reference< uno::XComponentContext > const & rxContext,
+ OUString const & rName,
+ OUString const & rArguments,
+ OUString const & rTemplate)
+{
+ OSL_ENSURE(rxContext.is(),
+ "ucb::registerAtUcb(): No service factory");
+
+ bool bNoProxy = rArguments.startsWith("{noproxy}");
+ OUString
+ aProviderArguments(bNoProxy ?
+ rArguments.
+ copy(RTL_CONSTASCII_LENGTH("{noproxy}")) :
+ rArguments);
+
+ uno::Reference< ucb::XContentProvider > xProvider;
+
+ if (!rName.isEmpty())
+ {
+ // First, try to instantiate proxy for provider:
+ if (!bNoProxy)
+ {
+ uno::Reference< ucb::XContentProviderFactory > xProxyFactory;
+ try
+ {
+ xProxyFactory = ucb::ContentProviderProxyFactory::create( rxContext );
+ }
+ catch (uno::Exception const &) {}
+ OSL_ENSURE(xProxyFactory.is(), "No ContentProviderProxyFactory");
+ if (xProxyFactory.is())
+ xProvider = xProxyFactory->createContentProvider(rName);
+ }
+
+ // Then, try to instantiate provider directly:
+ if (!xProvider.is())
+ try
+ {
+ xProvider.set(
+ rxContext->getServiceManager()->createInstanceWithContext(rName, rxContext),
+ uno::UNO_QUERY);
+ }
+ catch (uno::RuntimeException const &) { throw; }
+ catch (uno::Exception const &) {}
+ }
+
+ uno::Reference< ucb::XParameterizedContentProvider >
+ xParameterized(xProvider, uno::UNO_QUERY);
+ if (xParameterized.is())
+ {
+ uno::Reference< ucb::XContentProvider > xInstance;
+ try
+ {
+ xInstance = xParameterized->registerInstance(rTemplate,
+ aProviderArguments,
+ true);
+ //@@@ if this call replaces an old instance, the commit-or-
+ // rollback code below will not work
+ }
+ catch (lang::IllegalArgumentException const &) {}
+
+ if (xInstance.is())
+ xProvider = xInstance;
+ }
+
+ bool bSuccess = false;
+ if (rManager.is() && (rName.isEmpty() || xProvider.is()))
+ {
+ try
+ {
+ rManager->registerContentProvider(xProvider, rTemplate, true);
+ bSuccess = true;
+ }
+ catch (ucb::DuplicateProviderException const &)
+ {
+ if (xParameterized.is())
+ try
+ {
+ xParameterized->deregisterInstance(rTemplate,
+ aProviderArguments);
+ }
+ catch (lang::IllegalArgumentException const &) {}
+ }
+ catch (...)
+ {
+ if (xParameterized.is())
+ try
+ {
+ xParameterized->deregisterInstance(rTemplate,
+ aProviderArguments);
+ }
+ catch (lang::IllegalArgumentException const &) {}
+ catch (uno::RuntimeException const &) {}
+ throw;
+ }
+ }
+ return bSuccess;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/resultset.cxx b/ucbhelper/source/provider/resultset.cxx
new file mode 100644
index 0000000000..61682f4fd5
--- /dev/null
+++ b/ucbhelper/source/provider/resultset.cxx
@@ -0,0 +1,1486 @@
+/* -*- 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 <memory>
+#include <mutex>
+#include <comphelper/interfacecontainer4.hxx>
+#include <comphelper/multiinterfacecontainer4.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <ucbhelper/resultset.hxx>
+#include <ucbhelper/resultsetmetadata.hxx>
+#include <ucbhelper/macros.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+
+namespace ucbhelper_impl
+{
+
+namespace {
+
+struct PropertyInfo
+{
+ const char* pName;
+ sal_Int32 nHandle;
+ sal_Int16 nAttributes;
+ const uno::Type& (*pGetCppuType)();
+};
+
+}
+
+static const uno::Type& sal_Int32_getCppuType()
+{
+ return cppu::UnoType<sal_Int32>::get();
+}
+
+static const uno::Type& sal_Bool_getCppuType()
+{
+ return cppu::UnoType<bool>::get();
+}
+
+const PropertyInfo aPropertyTable[] =
+{
+ { "IsRowCountFinal",
+ 1000,
+ beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY,
+ &sal_Bool_getCppuType
+ },
+ { "RowCount",
+ 1001,
+ beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY,
+ &sal_Int32_getCppuType
+ },
+ { nullptr,
+ 0,
+ 0,
+ nullptr
+ }
+};
+
+#define RESULTSET_PROPERTY_COUNT 2
+
+
+
+namespace {
+
+class PropertySetInfo :
+ public cppu::OWeakObject,
+ public lang::XTypeProvider,
+ public beans::XPropertySetInfo
+{
+ uno::Sequence< beans::Property > m_aProps;
+
+private:
+ bool queryProperty(
+ std::u16string_view aName, beans::Property& rProp ) const;
+
+public:
+ PropertySetInfo(
+ const PropertyInfo* pProps,
+ sal_Int32 nProps );
+
+ // 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;
+
+ // XPropertySetInfo
+ virtual uno::Sequence< beans::Property > SAL_CALL getProperties() override;
+ virtual beans::Property SAL_CALL getPropertyByName(
+ const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+};
+
+}
+
+typedef comphelper::OMultiTypeInterfaceContainerHelperVar4<OUString, css::beans::XPropertyChangeListener>
+ PropertyChangeListeners;
+
+} // namespace ucbhelper_impl
+
+using namespace ucbhelper_impl;
+
+namespace ucbhelper
+{
+
+
+// struct ResultSet_Impl.
+
+
+struct ResultSet_Impl
+{
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< css::ucb::XCommandEnvironment > m_xEnv;
+ uno::Reference< beans::XPropertySetInfo > m_xPropSetInfo;
+ uno::Reference< sdbc::XResultSetMetaData > m_xMetaData;
+ uno::Sequence< beans::Property > m_aProperties;
+ rtl::Reference< ResultSetDataSupplier > m_xDataSupplier;
+ std::mutex m_aMutex;
+ comphelper::OInterfaceContainerHelper4<lang::XEventListener> m_aDisposeEventListeners;
+ std::unique_ptr<PropertyChangeListeners> m_pPropertyChangeListeners;
+ sal_Int32 m_nPos;
+ bool m_bWasNull;
+ bool m_bAfterLast;
+
+ inline ResultSet_Impl(
+ uno::Reference< uno::XComponentContext > xContext,
+ const uno::Sequence< beans::Property >& rProperties,
+ rtl::Reference< ResultSetDataSupplier > xDataSupplier,
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv );
+};
+
+inline ResultSet_Impl::ResultSet_Impl(
+ uno::Reference< uno::XComponentContext > xContext,
+ const uno::Sequence< beans::Property >& rProperties,
+ rtl::Reference< ResultSetDataSupplier > xDataSupplier,
+ uno::Reference< css::ucb::XCommandEnvironment > xEnv )
+: m_xContext(std::move( xContext )),
+ m_xEnv(std::move( xEnv )),
+ m_aProperties( rProperties ),
+ m_xDataSupplier(std::move( xDataSupplier )),
+ m_nPos( 0 ), // Position is one-based. Zero means: before first element.
+ m_bWasNull( false ),
+ m_bAfterLast( false )
+{
+}
+
+
+// ResultSet Implementation.
+
+
+ResultSet::ResultSet(
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Sequence< beans::Property >& rProperties,
+ const rtl::Reference< ResultSetDataSupplier >& rDataSupplier )
+: m_pImpl( new ResultSet_Impl(
+ rxContext,
+ rProperties,
+ rDataSupplier,
+ uno::Reference< css::ucb::XCommandEnvironment >() ) )
+{
+ rDataSupplier->m_pResultSet = this;
+}
+
+
+ResultSet::ResultSet(
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Sequence< beans::Property >& rProperties,
+ const rtl::Reference< ResultSetDataSupplier >& rDataSupplier,
+ const uno::Reference< css::ucb::XCommandEnvironment >& rxEnv )
+: m_pImpl( new ResultSet_Impl( rxContext, rProperties, rDataSupplier, rxEnv ) )
+{
+ rDataSupplier->m_pResultSet = this;
+}
+
+
+// virtual
+ResultSet::~ResultSet()
+{
+}
+
+
+// XServiceInfo methods.
+
+OUString SAL_CALL ResultSet::getImplementationName()
+{
+ return "ResultSet";
+}
+
+sal_Bool SAL_CALL ResultSet::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL ResultSet::getSupportedServiceNames()
+{
+ return { RESULTSET_SERVICE_NAME };
+}
+
+
+// XComponent methods.
+
+
+// virtual
+void SAL_CALL ResultSet::dispose()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( m_pImpl->m_aDisposeEventListeners.getLength(aGuard) )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< lang::XComponent * >( this );
+ m_pImpl->m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt );
+ }
+
+ if ( m_pImpl->m_pPropertyChangeListeners )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< beans::XPropertySet * >( this );
+ m_pImpl->m_pPropertyChangeListeners->disposeAndClear( aGuard, aEvt );
+ }
+
+ m_pImpl->m_xDataSupplier->close();
+}
+
+
+// virtual
+void SAL_CALL ResultSet::addEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ m_pImpl->m_aDisposeEventListeners.addInterface( aGuard, Listener );
+}
+
+
+// virtual
+void SAL_CALL ResultSet::removeEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ m_pImpl->m_aDisposeEventListeners.removeInterface( aGuard, Listener );
+}
+
+
+// XResultSetMetaDataSupplier methods.
+
+
+// virtual
+uno::Reference< sdbc::XResultSetMetaData > SAL_CALL ResultSet::getMetaData()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !m_pImpl->m_xMetaData.is() )
+ m_pImpl->m_xMetaData = new ResultSetMetaData( m_pImpl->m_xContext,
+ m_pImpl->m_aProperties );
+
+ return m_pImpl->m_xMetaData;
+}
+
+
+// XResultSet methods.
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::next()
+{
+ // Note: Cursor is initially positioned before the first row.
+ // First call to 'next()' moves it to first row.
+
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ // getResult works zero-based!
+ if ( !m_pImpl->m_xDataSupplier->getResult( m_pImpl->m_nPos ) )
+ {
+ m_pImpl->m_bAfterLast = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ m_pImpl->m_nPos++;
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::isBeforeFirst()
+{
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ // getResult works zero-based!
+ if ( !m_pImpl->m_xDataSupplier->getResult( 0 ) )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return ( m_pImpl->m_nPos == 0 );
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::isAfterLast()
+{
+ m_pImpl->m_xDataSupplier->validate();
+ return m_pImpl->m_bAfterLast;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::isFirst()
+{
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return ( m_pImpl->m_nPos == 1 );
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::isLast()
+{
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+ if ( !nCount )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return ( m_pImpl->m_nPos == nCount );
+}
+
+
+// virtual
+void SAL_CALL ResultSet::beforeFirst()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = 0;
+ m_pImpl->m_xDataSupplier->validate();
+}
+
+
+// virtual
+void SAL_CALL ResultSet::afterLast()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = true;
+ m_pImpl->m_xDataSupplier->validate();
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::first()
+{
+ // getResult works zero-based!
+ if ( m_pImpl->m_xDataSupplier->getResult( 0 ) )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = 1;
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::last()
+{
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+ if ( nCount )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = nCount;
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSet::getRow()
+{
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return m_pImpl->m_nPos;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::absolute( sal_Int32 row )
+{
+/*
+ If the row number is positive, the cursor moves to the given row number
+ with respect to the beginning of the result set. The first row is row 1,
+ the second is row 2, and so on.
+
+ If the given row number is negative, the cursor moves to an absolute row
+ position with respect to the end of the result set. For example, calling
+ absolute( -1 ) positions the cursor on the last row, absolute( -2 )
+ indicates the next-to-last row, and so on.
+
+ An attempt to position the cursor beyond the first/last row in the result
+ set leaves the cursor before/after the first/last row, respectively.
+
+ Calling absolute( 1 ) is the same as calling first().
+
+ Calling absolute( -1 ) is the same as calling last().
+*/
+ if ( row < 0 )
+ {
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+
+ if ( ( row * -1 ) > nCount )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = 0;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+ else // |row| <= nCount
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = ( nCount + row + 1 );
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+ }
+ else if ( row == 0 )
+ {
+ // @throws SQLException
+ // ... if row is 0 ...
+ throw sdbc::SQLException();
+ }
+ else // row > 0
+ {
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+
+ if ( row <= nCount )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = row;
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+ else // row > nCount
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+ }
+
+ // unreachable...
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::relative( sal_Int32 rows )
+{
+/*
+ Attempting to move beyond the first/last row in the result set
+ positions the cursor before/after the first/last row.
+
+ Calling relative( 0 ) is valid, but does not change the cursor position.
+
+ Calling relative( 1 ) is different from calling next() because it makes
+ sense to call next() when there is no current row, for example, when
+ the cursor is positioned before the first row or after the last row of
+ the result set.
+*/
+ if ( m_pImpl->m_bAfterLast || ( m_pImpl->m_nPos == 0 ) )
+ {
+ // "No current row".
+ throw sdbc::SQLException();
+ }
+
+ if ( rows < 0 )
+ {
+ if ( ( m_pImpl->m_nPos + rows ) > 0 )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = ( m_pImpl->m_nPos + rows );
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+ else
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = 0;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+ }
+ else if ( rows == 0 )
+ {
+ // nop.
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+ else // rows > 0
+ {
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+ if ( ( m_pImpl->m_nPos + rows ) <= nCount )
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = false;
+ m_pImpl->m_nPos = ( m_pImpl->m_nPos + rows );
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+ else
+ {
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ m_pImpl->m_bAfterLast = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+ }
+ }
+
+ // unreachable...
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::previous()
+{
+/*
+ previous() is not the same as relative( -1 ) because it makes sense
+ to call previous() when there is no current row.
+*/
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( m_pImpl->m_bAfterLast )
+ {
+ m_pImpl->m_bAfterLast = false;
+ sal_Int32 nCount = m_pImpl->m_xDataSupplier->totalCount();
+ m_pImpl->m_nPos = nCount;
+ }
+ else if ( m_pImpl->m_nPos )
+ m_pImpl->m_nPos--;
+
+ if ( m_pImpl->m_nPos )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return true;
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+void SAL_CALL ResultSet::refreshRow()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+ if ( m_pImpl->m_bAfterLast || ( m_pImpl->m_nPos == 0 ) )
+ return;
+
+ m_pImpl->m_xDataSupplier->releasePropertyValues( m_pImpl->m_nPos );
+ m_pImpl->m_xDataSupplier->validate();
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::rowUpdated()
+{
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::rowInserted()
+{
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::rowDeleted()
+{
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+uno::Reference< uno::XInterface > SAL_CALL ResultSet::getStatement()
+{
+/*
+ returns the Statement that produced this ResultSet object. If the
+ result set was generated some other way, ... this method returns null.
+*/
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< uno::XInterface >();
+}
+
+
+// XRow methods.
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::wasNull()
+{
+ // This method can not be implemented correctly!!! Imagine different
+ // threads doing a getXYZ - wasNull calling sequence on the same
+ // implementation object...
+
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->wasNull();
+ }
+ }
+
+ m_pImpl->m_xDataSupplier->validate();
+ return m_pImpl->m_bWasNull;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSet::getString( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getString( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return OUString();
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getBoolean( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return false;
+}
+
+
+// virtual
+sal_Int8 SAL_CALL ResultSet::getByte( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getByte( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+sal_Int16 SAL_CALL ResultSet::getShort( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getShort( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSet::getInt( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getInt( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+sal_Int64 SAL_CALL ResultSet::getLong( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getLong( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+float SAL_CALL ResultSet::getFloat( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getFloat( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+double SAL_CALL ResultSet::getDouble( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getDouble( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return 0;
+}
+
+
+// virtual
+uno::Sequence< sal_Int8 > SAL_CALL
+ResultSet::getBytes( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getBytes( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Sequence< sal_Int8 >();
+}
+
+
+// virtual
+util::Date SAL_CALL ResultSet::getDate( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getDate( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return util::Date();
+}
+
+
+// virtual
+util::Time SAL_CALL ResultSet::getTime( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getTime( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return util::Time();
+}
+
+
+// virtual
+util::DateTime SAL_CALL
+ResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getTimestamp( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return util::DateTime();
+}
+
+
+// virtual
+uno::Reference< io::XInputStream > SAL_CALL
+ResultSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getBinaryStream( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< io::XInputStream >();
+}
+
+
+// virtual
+uno::Reference< io::XInputStream > SAL_CALL
+ResultSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getCharacterStream( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< io::XInputStream >();
+}
+
+
+// virtual
+uno::Any SAL_CALL ResultSet::getObject(
+ sal_Int32 columnIndex,
+ const uno::Reference< container::XNameAccess >& typeMap )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getObject( columnIndex, typeMap );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Any();
+}
+
+
+// virtual
+uno::Reference< sdbc::XRef > SAL_CALL
+ResultSet::getRef( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getRef( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< sdbc::XRef >();
+}
+
+
+// virtual
+uno::Reference< sdbc::XBlob > SAL_CALL
+ResultSet::getBlob( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getBlob( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< sdbc::XBlob >();
+}
+
+
+// virtual
+uno::Reference< sdbc::XClob > SAL_CALL
+ResultSet::getClob( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getClob( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< sdbc::XClob >();
+}
+
+
+// virtual
+uno::Reference< sdbc::XArray > SAL_CALL
+ResultSet::getArray( sal_Int32 columnIndex )
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ {
+ uno::Reference< sdbc::XRow > xValues
+ = m_pImpl->m_xDataSupplier->queryPropertyValues(
+ m_pImpl->m_nPos - 1 );
+ if ( xValues.is() )
+ {
+ m_pImpl->m_bWasNull = false;
+ m_pImpl->m_xDataSupplier->validate();
+ return xValues->getArray( columnIndex );
+ }
+ }
+
+ m_pImpl->m_bWasNull = true;
+ m_pImpl->m_xDataSupplier->validate();
+ return uno::Reference< sdbc::XArray >();
+}
+
+
+// XCloseable methods.
+
+
+// virtual
+void SAL_CALL ResultSet::close()
+{
+ m_pImpl->m_xDataSupplier->close();
+ m_pImpl->m_xDataSupplier->validate();
+}
+
+
+// XContentAccess methods.
+
+
+// virtual
+OUString SAL_CALL ResultSet::queryContentIdentifierString()
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ return m_pImpl->m_xDataSupplier->queryContentIdentifierString(
+ m_pImpl->m_nPos - 1 );
+
+ return OUString();
+}
+
+
+// virtual
+uno::Reference< css::ucb::XContentIdentifier > SAL_CALL
+ResultSet::queryContentIdentifier()
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ return m_pImpl->m_xDataSupplier->queryContentIdentifier(
+ m_pImpl->m_nPos - 1 );
+
+ return uno::Reference< css::ucb::XContentIdentifier >();
+}
+
+
+// virtual
+uno::Reference< css::ucb::XContent > SAL_CALL
+ResultSet::queryContent()
+{
+ if ( m_pImpl->m_nPos && !m_pImpl->m_bAfterLast )
+ return m_pImpl->m_xDataSupplier->queryContent( m_pImpl->m_nPos - 1 );
+
+ return uno::Reference< css::ucb::XContent >();
+}
+
+
+// XPropertySet methods.
+
+
+// virtual
+uno::Reference< beans::XPropertySetInfo > SAL_CALL
+ResultSet::getPropertySetInfo()
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !m_pImpl->m_xPropSetInfo.is() )
+ m_pImpl->m_xPropSetInfo
+ = new PropertySetInfo( aPropertyTable,
+ RESULTSET_PROPERTY_COUNT );
+ return m_pImpl->m_xPropSetInfo;
+}
+
+
+// virtual
+void SAL_CALL ResultSet::setPropertyValue( const OUString& aPropertyName,
+ const uno::Any& )
+{
+ if ( aPropertyName == "RowCount" )
+ {
+ // property is read-only.
+ throw lang::IllegalArgumentException();
+ }
+ else if ( aPropertyName == "IsRowCountFinal" )
+ {
+ // property is read-only.
+ throw lang::IllegalArgumentException();
+ }
+ else
+ {
+ throw beans::UnknownPropertyException(aPropertyName);
+ }
+}
+
+
+// virtual
+uno::Any SAL_CALL ResultSet::getPropertyValue(
+ const OUString& PropertyName )
+{
+ uno::Any aValue;
+
+ if ( PropertyName == "RowCount" )
+ {
+ aValue <<= m_pImpl->m_xDataSupplier->currentCount();
+ }
+ else if ( PropertyName == "IsRowCountFinal" )
+ {
+ aValue <<= m_pImpl->m_xDataSupplier->isCountFinal();
+ }
+ else
+ {
+ throw beans::UnknownPropertyException(PropertyName);
+ }
+
+ return aValue;
+}
+
+
+// virtual
+void SAL_CALL ResultSet::addPropertyChangeListener(
+ const OUString& aPropertyName,
+ const uno::Reference< beans::XPropertyChangeListener >& xListener )
+{
+ // Note: An empty property name means a listener for "all" properties.
+
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !aPropertyName.isEmpty() &&
+ aPropertyName != "RowCount" &&
+ aPropertyName != "IsRowCountFinal" )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ m_pImpl->m_pPropertyChangeListeners.reset(
+ new PropertyChangeListeners());
+
+ m_pImpl->m_pPropertyChangeListeners->addInterface(aGuard,
+ aPropertyName, xListener );
+}
+
+
+// virtual
+void SAL_CALL ResultSet::removePropertyChangeListener(
+ const OUString& aPropertyName,
+ const uno::Reference< beans::XPropertyChangeListener >& xListener )
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !aPropertyName.isEmpty() &&
+ aPropertyName != "RowCount" &&
+ aPropertyName != "IsRowCountFinal" )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if ( m_pImpl->m_pPropertyChangeListeners )
+ m_pImpl->m_pPropertyChangeListeners->removeInterface(aGuard,
+ aPropertyName, xListener );
+
+}
+
+
+// virtual
+void SAL_CALL ResultSet::addVetoableChangeListener(
+ const OUString&,
+ const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ // No constrained props, at the moment.
+}
+
+
+// virtual
+void SAL_CALL ResultSet::removeVetoableChangeListener(
+ const OUString&,
+ const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ // No constrained props, at the moment.
+}
+
+
+// Non-interface methods.
+
+
+void ResultSet::propertyChanged( const beans::PropertyChangeEvent& rEvt ) const
+{
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ return;
+
+ // Notify listeners interested especially in the changed property.
+ comphelper::OInterfaceContainerHelper4<beans::XPropertyChangeListener>* pPropsContainer
+ = m_pImpl->m_pPropertyChangeListeners->getContainer(aGuard,
+ rEvt.PropertyName );
+ if ( pPropsContainer )
+ {
+ pPropsContainer->notifyEach(aGuard, &beans::XPropertyChangeListener::propertyChange, rEvt);
+ }
+
+ // Notify listeners interested in all properties.
+ pPropsContainer
+ = m_pImpl->m_pPropertyChangeListeners->getContainer( aGuard, OUString() );
+ if ( pPropsContainer )
+ {
+ pPropsContainer->notifyEach( aGuard, &beans::XPropertyChangeListener::propertyChange, rEvt);
+ }
+}
+
+
+void ResultSet::rowCountChanged( sal_uInt32 nOld, sal_uInt32 nNew )
+{
+ OSL_ENSURE( nOld < nNew, "ResultSet::rowCountChanged - nOld >= nNew!" );
+
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ return;
+
+ propertyChanged(
+ beans::PropertyChangeEvent(
+ getXWeak(),
+ "RowCount",
+ false,
+ 1001,
+ uno::Any( nOld ), // old value
+ uno::Any( nNew ) ) ); // new value
+}
+
+
+void ResultSet::rowCountFinal()
+{
+ if ( !m_pImpl->m_pPropertyChangeListeners )
+ return;
+
+ propertyChanged(
+ beans::PropertyChangeEvent(
+ getXWeak(),
+ "IsRowCountFinal",
+ false,
+ 1000,
+ uno:: Any( false ), // old value
+ uno::Any( true ) ) ); // new value
+}
+
+
+const uno::Sequence< beans::Property >& ResultSet::getProperties() const
+{
+ return m_pImpl->m_aProperties;
+}
+
+
+const uno::Reference< css::ucb::XCommandEnvironment >&
+ResultSet::getEnvironment() const
+{
+ return m_pImpl->m_xEnv;
+}
+
+} // namespace ucbhelper
+
+namespace ucbhelper_impl {
+
+
+// PropertySetInfo Implementation.
+
+
+PropertySetInfo::PropertySetInfo(
+ const PropertyInfo* pProps,
+ sal_Int32 nProps )
+ : m_aProps( nProps )
+{
+
+ if ( !nProps )
+ return;
+
+ const PropertyInfo* pEntry = pProps;
+ beans::Property* pProperties = m_aProps.getArray();
+
+ for ( sal_Int32 n = 0; n < nProps; ++n )
+ {
+ beans::Property& rProp = pProperties[ n ];
+
+ rProp.Name = OUString::createFromAscii( pEntry->pName );
+ rProp.Handle = pEntry->nHandle;
+ rProp.Type = pEntry->pGetCppuType();
+ rProp.Attributes = pEntry->nAttributes;
+
+ pEntry++;
+ }
+}
+
+
+
+// XInterface methods.
+void SAL_CALL PropertySetInfo::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL PropertySetInfo::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+css::uno::Any SAL_CALL PropertySetInfo::queryInterface(
+ const css::uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider* >(this),
+ static_cast< beans::XPropertySetInfo* >(this)
+ );
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+}
+
+// XTypeProvider methods.
+
+
+XTYPEPROVIDER_IMPL_2( PropertySetInfo,
+ lang::XTypeProvider,
+ beans::XPropertySetInfo );
+
+
+// XPropertySetInfo methods.
+
+
+// virtual
+uno::Sequence< beans::Property > SAL_CALL PropertySetInfo::getProperties()
+{
+ return m_aProps;
+}
+
+
+// virtual
+beans::Property SAL_CALL PropertySetInfo::getPropertyByName(
+ const OUString& aName )
+{
+ beans::Property aProp;
+ if ( queryProperty( aName, aProp ) )
+ return aProp;
+
+ throw beans::UnknownPropertyException(aName);
+}
+
+
+// virtual
+sal_Bool SAL_CALL PropertySetInfo::hasPropertyByName(
+ const OUString& Name )
+{
+ beans::Property aProp;
+ return queryProperty( Name, aProp );
+}
+
+
+bool PropertySetInfo::queryProperty(
+ std::u16string_view aName, beans::Property& rProp ) const
+{
+ sal_Int32 nCount = m_aProps.getLength();
+ const beans::Property* pProps = m_aProps.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const beans::Property& rCurr = pProps[ n ];
+ if ( rCurr.Name == aName )
+ {
+ rProp = rCurr;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace ucbhelper_impl
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/resultsethelper.cxx b/ucbhelper/source/provider/resultsethelper.cxx
new file mode 100644
index 0000000000..788e6811a1
--- /dev/null
+++ b/ucbhelper/source/provider/resultsethelper.cxx
@@ -0,0 +1,252 @@
+/* -*- 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
+ - This implementation is far away from completion. It has no interface
+ for changes notifications etc.
+ */
+
+#include <com/sun/star/ucb/ListActionType.hpp>
+#include <com/sun/star/ucb/ListenerAlreadySetException.hpp>
+#include <com/sun/star/ucb/ServiceNotFoundException.hpp>
+#include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp>
+#include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp>
+#include <com/sun/star/ucb/XSourceInitialization.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <ucbhelper/resultsethelper.hxx>
+#include <utility>
+
+#include <osl/diagnose.h>
+
+using namespace com::sun::star;
+
+
+// ResultSetImplHelper Implementation.
+
+
+namespace ucbhelper {
+
+
+ResultSetImplHelper::ResultSetImplHelper(
+ uno::Reference< uno::XComponentContext > xContext,
+ css::ucb::OpenCommandArgument2 aCommand )
+: m_bStatic( false ),
+ m_bInitDone( false ),
+ m_aCommand(std::move( aCommand )),
+ m_xContext(std::move( xContext ))
+{
+}
+
+
+// virtual
+ResultSetImplHelper::~ResultSetImplHelper()
+{
+}
+
+
+// XServiceInfo methods.
+
+OUString SAL_CALL ResultSetImplHelper::getImplementationName()
+{
+ return "ResultSetImplHelper";
+}
+
+sal_Bool SAL_CALL ResultSetImplHelper::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService( this, ServiceName );
+}
+
+css::uno::Sequence< OUString > SAL_CALL ResultSetImplHelper::getSupportedServiceNames()
+{
+ return { DYNAMICRESULTSET_SERVICE_NAME };
+}
+
+// XComponent methods.
+
+
+// virtual
+void SAL_CALL ResultSetImplHelper::dispose()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_aDisposeEventListeners.getLength(aGuard) )
+ {
+ lang::EventObject aEvt;
+ aEvt.Source = static_cast< lang::XComponent * >( this );
+ m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt );
+ }
+}
+
+
+// virtual
+void SAL_CALL ResultSetImplHelper::addEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ m_aDisposeEventListeners.addInterface( aGuard, Listener );
+}
+
+
+// virtual
+void SAL_CALL ResultSetImplHelper::removeEventListener(
+ const uno::Reference< lang::XEventListener >& Listener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ m_aDisposeEventListeners.removeInterface( aGuard, Listener );
+}
+
+
+// XDynamicResultSet methods.
+
+
+// virtual
+uno::Reference< sdbc::XResultSet > SAL_CALL
+ResultSetImplHelper::getStaticResultSet()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_xListener.is() )
+ throw css::ucb::ListenerAlreadySetException();
+
+ init( true );
+ return m_xResultSet1;
+}
+
+
+// virtual
+void SAL_CALL ResultSetImplHelper::setListener(
+ const uno::Reference< css::ucb::XDynamicResultSetListener >& Listener )
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if ( m_bStatic || m_xListener.is() )
+ throw css::ucb::ListenerAlreadySetException();
+
+ m_xListener = Listener;
+
+
+ // Create "welcome event" and send it to listener.
+
+
+ // Note: We only have the implementation for a static result set at the
+ // moment (src590). The dynamic result sets passed to the listener
+ // are a fake. This implementation will never call "notify" at the
+ // listener to propagate any changes!!!
+
+ init( false );
+
+ uno::Any aInfo;
+ aInfo <<= css::ucb::WelcomeDynamicResultSetStruct(
+ m_xResultSet1 /* "old" */,
+ m_xResultSet2 /* "new" */ );
+
+ uno::Sequence< css::ucb::ListAction > aActions {
+ css::ucb::ListAction(
+ 0, // Position; not used
+ 0, // Count; not used
+ css::ucb::ListActionType::WELCOME,
+ aInfo ) };
+ aGuard.unlock();
+
+ Listener->notify(
+ css::ucb::ListEvent(
+ getXWeak(), aActions ) );
+}
+
+
+// virtual
+sal_Int16 SAL_CALL ResultSetImplHelper::getCapabilities()
+{
+ // ! css::ucb::ContentResultSetCapability::SORTED
+ return 0;
+}
+
+
+// virtual
+void SAL_CALL ResultSetImplHelper::connectToCache(
+ const uno::Reference< css::ucb::XDynamicResultSet > & xCache )
+{
+ if ( m_xListener.is() )
+ throw css::ucb::ListenerAlreadySetException();
+
+ if ( m_bStatic )
+ throw css::ucb::ListenerAlreadySetException();
+
+ uno::Reference< css::ucb::XSourceInitialization > xTarget( xCache, uno::UNO_QUERY );
+ if ( xTarget.is() )
+ {
+ uno::Reference< css::ucb::XCachedDynamicResultSetStubFactory > xStubFactory;
+ try
+ {
+ xStubFactory
+ = css::ucb::CachedDynamicResultSetStubFactory::create(
+ m_xContext );
+ }
+ catch ( uno::Exception const & )
+ {
+ }
+
+ if ( xStubFactory.is() )
+ {
+ xStubFactory->connectToCache(
+ this, xCache, m_aCommand.SortingInfo, nullptr );
+ return;
+ }
+ }
+ throw css::ucb::ServiceNotFoundException();
+}
+
+
+// Non-interface methods.
+
+
+void ResultSetImplHelper::init( bool bStatic )
+{
+ if ( m_bInitDone )
+ return;
+
+ if ( bStatic )
+ {
+ // virtual... derived class fills m_xResultSet1
+ initStatic();
+
+ OSL_ENSURE( m_xResultSet1.is(),
+ "ResultSetImplHelper::init - No 1st result set!" );
+ m_bStatic = true;
+ }
+ else
+ {
+ // virtual... derived class fills m_xResultSet1 and m_xResultSet2
+ initDynamic();
+
+ OSL_ENSURE( m_xResultSet1.is(),
+ "ResultSetImplHelper::init - No 1st result set!" );
+ OSL_ENSURE( m_xResultSet2.is(),
+ "ResultSetImplHelper::init - No 2nd result set!" );
+ m_bStatic = false;
+ }
+ m_bInitDone = true;
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/resultsetmetadata.cxx b/ucbhelper/source/provider/resultsetmetadata.cxx
new file mode 100644
index 0000000000..759aaf1e70
--- /dev/null
+++ b/ucbhelper/source/provider/resultsetmetadata.cxx
@@ -0,0 +1,397 @@
+/* -*- 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 <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XArray.hpp>
+#include <com/sun/star/sdbc/XBlob.hpp>
+#include <com/sun/star/sdbc/XClob.hpp>
+#include <com/sun/star/sdbc/XRef.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/Time.hpp>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/ucb/PropertiesManager.hpp>
+#include <ucbhelper/resultsetmetadata.hxx>
+#include <mutex>
+
+using namespace com::sun::star::beans;
+using namespace com::sun::star::io;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::util;
+
+
+namespace ucbhelper_impl {
+
+struct ResultSetMetaData_Impl
+{
+ std::mutex m_aMutex;
+ std::vector< ::ucbhelper::ResultSetColumnData > m_aColumnData;
+ bool m_bObtainedTypes;
+
+ explicit ResultSetMetaData_Impl( sal_Int32 nSize )
+ : m_aColumnData( nSize ), m_bObtainedTypes( false ) {}
+
+ explicit ResultSetMetaData_Impl(
+ std::vector< ::ucbhelper::ResultSetColumnData >&& rColumnData )
+ : m_aColumnData( std::move(rColumnData) ), m_bObtainedTypes( false ) {}
+};
+
+}
+
+using namespace ucbhelper_impl;
+
+namespace ucbhelper {
+
+
+// ResultSetMetaData Implementation.
+
+
+ResultSetMetaData::ResultSetMetaData(
+ const Reference< XComponentContext >& rxContext,
+ const Sequence< Property >& rProps )
+: m_pImpl( new ResultSetMetaData_Impl( rProps.getLength() ) ),
+ m_xContext( rxContext ),
+ m_aProps( rProps )
+{
+}
+
+
+ResultSetMetaData::ResultSetMetaData(
+ const Reference< XComponentContext >& rxContext,
+ const Sequence< Property >& rProps,
+ std::vector< ResultSetColumnData >&& rColumnData )
+: m_pImpl( new ResultSetMetaData_Impl( std::move(rColumnData) ) ),
+ m_xContext( rxContext ),
+ m_aProps( rProps )
+{
+ OSL_ENSURE( m_pImpl->m_aColumnData.size() == sal_uInt32( rProps.getLength() ),
+ "ResultSetMetaData ctor - different array sizes!" );
+}
+
+
+// virtual
+ResultSetMetaData::~ResultSetMetaData()
+{
+}
+
+
+// XResultSetMetaData methods.
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::getColumnCount()
+{
+ return m_aProps.getLength();
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isAutoIncrement( sal_Int32 /*column*/ )
+{
+ /*
+ Checks whether column is automatically numbered, which makes it
+ read-only.
+ */
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isCaseSensitive( sal_Int32 column )
+{
+ if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
+ return false;
+
+ return m_pImpl->m_aColumnData[ column - 1 ].isCaseSensitive;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isSearchable( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isCurrency( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::isNullable( sal_Int32 /*column*/ )
+{
+ return ColumnValue::NULLABLE;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isSigned( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::getColumnDisplaySize( sal_Int32 /*column*/ )
+{
+ /*
+ Gets the normal maximum width in characters for column.
+ */
+ return 16;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ /*
+ Gets the suggested column title for column, to be used in print-
+ outs and displays.
+ */
+
+ if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
+ return OUString();
+
+ return m_aProps.getConstArray()[ column - 1 ].Name;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ /*
+ Gets the name of column.
+ */
+
+ if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
+ return OUString();
+
+ return m_aProps.getConstArray()[ column - 1 ].Name;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ /*
+ Gets the schema name for the table from which column of this
+ result set was derived.
+ Because this feature is not widely supported, the return value
+ for many DBMSs will be an empty string.
+ */
+ return OUString();
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::getPrecision( sal_Int32 /*column*/ )
+{
+ return -1;
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::getScale( sal_Int32 /*column*/ )
+{
+ return 0;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getTableName( sal_Int32 /*column*/ )
+{
+ /*
+ Gets the name of the table from which column of this result set
+ was derived or "" if there is none (for example, for a join).
+ Because this feature is not widely supported, the return value
+ for many DBMSs will be an empty string.
+ */
+ return OUString();
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ /*
+ Gets the catalog name for the table from which column of this
+ result set was derived.
+ Because this feature is not widely supported, the return value
+ for many DBMSs will be an empty string.
+ */
+ return OUString();
+}
+
+
+// virtual
+sal_Int32 SAL_CALL ResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ /*
+ Gets the JDBC type for the value stored in column. ... The STRUCT
+ and DISTINCT type codes are always returned for structured and
+ distinct types, regardless of whether the value will be mapped
+ according to the standard mapping or be a custom mapping.
+ */
+
+ if ( ( column < 1 ) || ( column > m_aProps.getLength() ) )
+ return DataType::SQLNULL;
+
+ if ( m_aProps.getConstArray()[ column - 1 ].Type
+ == cppu::UnoType<void>::get() )
+ {
+ // No type given. Try UCB's Properties Manager...
+
+ std::unique_lock aGuard( m_pImpl->m_aMutex );
+
+ if ( !m_pImpl->m_bObtainedTypes )
+ {
+ try
+ {
+ Reference< XPropertySetInfo > xInfo = PropertiesManager::create( m_xContext );
+ // Less (remote) calls...
+
+ const Sequence< Property > aProps = xInfo->getProperties();
+
+ for ( Property& rProp : asNonConstRange(m_aProps) )
+ {
+ auto pProp = std::find_if(aProps.begin(), aProps.end(),
+ [&rProp](const Property& rProp1) { return rProp.Name == rProp1.Name; });
+ if (pProp != aProps.end())
+ {
+ // Found...
+ rProp.Type = pProp->Type;
+ }
+ }
+ }
+ catch ( RuntimeException& )
+ {
+ throw;
+ }
+ catch ( Exception& )
+ {
+ // createInstance
+ }
+
+ m_pImpl->m_bObtainedTypes = true;
+ }
+ }
+
+ const Type& rType = m_aProps.getConstArray()[ column - 1 ].Type;
+ sal_Int32 nType = DataType::OTHER;
+
+ if ( rType == cppu::UnoType<OUString>::get() )
+ nType = DataType::VARCHAR; // XRow::getString
+ else if ( rType == cppu::UnoType<bool>::get() )
+ nType = DataType::BIT; // XRow::getBoolean
+ else if ( rType == cppu::UnoType<sal_Int32>::get() )
+ nType = DataType::INTEGER; // XRow::getInt
+ else if ( rType == cppu::UnoType<sal_Int64>::get() )
+ nType = DataType::BIGINT; // XRow::getLong
+ else if ( rType == cppu::UnoType<sal_Int16>::get() )
+ nType = DataType::SMALLINT; // XRow::getShort
+ else if ( rType == cppu::UnoType<sal_Int8>::get() )
+ nType = DataType::TINYINT; // XRow::getByte
+ else if ( rType == cppu::UnoType<float>::get() )
+ nType = DataType::REAL; // XRow::getFloat
+ else if ( rType == cppu::UnoType<double>::get() )
+ nType = DataType::DOUBLE; // XRow::getDouble
+ else if ( rType == cppu::UnoType<Sequence<sal_Int8>>::get() )
+ nType = DataType::VARBINARY;// XRow::getBytes
+ else if ( rType == cppu::UnoType<Date>::get() )
+ nType = DataType::DATE; // XRow::getDate
+ else if ( rType == cppu::UnoType<Time>::get() )
+ nType = DataType::TIME; // XRow::getTime
+ else if ( rType == cppu::UnoType<DateTime>::get() )
+ nType = DataType::TIMESTAMP;// XRow::getTimestamp
+ else if ( rType == cppu::UnoType<XInputStream>::get() )
+ nType = DataType::LONGVARBINARY; // XRow::getBinaryStream
+// nType = DataType::LONGVARCHAR; // XRow::getCharacterStream
+ else if ( rType == cppu::UnoType<XClob>::get() )
+ nType = DataType::CLOB; // XRow::getClob
+ else if ( rType == cppu::UnoType<XBlob>::get() )
+ nType = DataType::BLOB; // XRow::getBlob
+ else if ( rType == cppu::UnoType<XArray>::get() )
+ nType = DataType::ARRAY;// XRow::getArray
+ else if ( rType == cppu::UnoType<XRef>::get() )
+ nType = DataType::REF;// XRow::getRef
+ else
+ nType = DataType::OBJECT;// XRow::getObject
+
+ return nType;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getColumnTypeName( sal_Int32 /*column*/ )
+{
+ /*
+ Gets the type name used by this particular data source for the
+ values stored in column. If the type code for the type of value
+ stored in column is STRUCT, DISTINCT or JAVA_OBJECT, this method
+ returns a fully-qualified SQL type name.
+ */
+ return OUString();
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isReadOnly( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isWritable( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+// virtual
+sal_Bool SAL_CALL ResultSetMetaData::isDefinitelyWritable( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+// virtual
+OUString SAL_CALL ResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ /*
+ Returns the fully-qualified name of the service whose instances
+ are manufactured if XResultSet::getObject is called to retrieve
+ a value from the column.
+ */
+ return OUString();
+}
+
+} // namespace ucbhelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simpleauthenticationrequest.cxx b/ucbhelper/source/provider/simpleauthenticationrequest.cxx
new file mode 100644
index 0000000000..972864d9aa
--- /dev/null
+++ b/ucbhelper/source/provider/simpleauthenticationrequest.cxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/ucb/URLAuthenticationRequest.hpp>
+#include <ucbhelper/simpleauthenticationrequest.hxx>
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+
+SimpleAuthenticationRequest::SimpleAuthenticationRequest(
+ const OUString & rURL,
+ const OUString & rServerName,
+ const OUString & rRealm,
+ const OUString & rUserName,
+ const OUString & rPassword,
+ bool bAllowUseSystemCredentials,
+ bool bAllowSessionStoring )
+{
+
+ // Fill request...
+ ucb::URLAuthenticationRequest aRequest;
+// aRequest.Message = // OUString
+// aRequest.Context = // XInterface
+ aRequest.Classification = task::InteractionClassification_ERROR;
+ aRequest.ServerName = rServerName;
+// aRequest.Diagnostic = // OUString
+ aRequest.HasRealm = !rRealm.isEmpty();
+ if ( aRequest.HasRealm )
+ aRequest.Realm = rRealm;
+ aRequest.HasUserName = true;
+ aRequest.UserName = rUserName;
+ aRequest.HasPassword = true;
+ aRequest.Password = rPassword;
+ aRequest.HasAccount = false;
+ aRequest.URL = rURL;
+
+ initialize(aRequest,
+ false,
+ true,
+ true,
+ aRequest.HasAccount,
+ bAllowUseSystemCredentials,
+ bAllowSessionStoring );
+}
+
+
+SimpleAuthenticationRequest::SimpleAuthenticationRequest(
+ const OUString & rURL,
+ const OUString & rServerName,
+ EntityType eRealmType,
+ const OUString & rRealm,
+ EntityType eUserNameType,
+ const OUString & rUserName,
+ EntityType ePasswordType,
+ const OUString & rPassword)
+{
+ // Fill request...
+ ucb::URLAuthenticationRequest aRequest;
+// aRequest.Message = // OUString
+// aRequest.Context = // XInterface
+ aRequest.Classification = task::InteractionClassification_ERROR;
+ aRequest.ServerName = rServerName;
+// aRequest.Diagnostic = // OUString
+ aRequest.HasRealm = eRealmType != ENTITY_NA;
+ if ( aRequest.HasRealm )
+ aRequest.Realm = rRealm;
+ aRequest.HasUserName = eUserNameType != ENTITY_NA;
+ if ( aRequest.HasUserName )
+ aRequest.UserName = rUserName;
+ aRequest.HasPassword = ePasswordType != ENTITY_NA;
+ if ( aRequest.HasPassword )
+ aRequest.Password = rPassword;
+ aRequest.HasAccount = false;
+ aRequest.URL = rURL;
+
+ initialize(aRequest,
+ eRealmType == ENTITY_MODIFY,
+ eUserNameType == ENTITY_MODIFY,
+ ePasswordType == ENTITY_MODIFY,
+ false,
+ false,
+ true );
+}
+
+
+void SimpleAuthenticationRequest::initialize(
+ const ucb::URLAuthenticationRequest & rRequest,
+ bool bCanSetRealm,
+ bool bCanSetUserName,
+ bool bCanSetPassword,
+ bool bCanSetAccount,
+ bool bAllowUseSystemCredentials,
+ bool bAllowSessionStoring )
+{
+ setRequest( uno::Any( rRequest ) );
+
+ // Fill continuations...
+ unsigned int nSize = 2;
+
+ if( bAllowSessionStoring )
+ nSize++;
+
+ uno::Sequence< ucb::RememberAuthentication > aRememberModes( nSize );
+ auto it = aRememberModes.getArray();
+ *it++ = ucb::RememberAuthentication_NO;
+
+ if( bAllowSessionStoring )
+ *it++ = ucb::RememberAuthentication_SESSION;
+
+ *it = ucb::RememberAuthentication_PERSISTENT;
+
+ m_xAuthSupplier
+ = new InteractionSupplyAuthentication(
+ this,
+ bCanSetRealm,
+ bCanSetUserName,
+ bCanSetPassword,
+ bCanSetAccount,
+ aRememberModes, // rRememberPasswordModes
+ ucb::RememberAuthentication_SESSION, // eDefaultRememberPasswordMode
+ aRememberModes, // rRememberAccountModes
+ ucb::RememberAuthentication_SESSION, // eDefaultRememberAccountMode
+ bAllowUseSystemCredentials // bCanUseSystemCredentials,
+ );
+
+ setContinuations(
+ { new InteractionAbort(this), new InteractionRetry(this), m_xAuthSupplier });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx b/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx
new file mode 100644
index 0000000000..e1dba7a35d
--- /dev/null
+++ b/ucbhelper/source/provider/simplecertificatevalidationrequest.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/ucb/CertificateValidationRequest.hpp>
+#include <ucbhelper/simplecertificatevalidationrequest.hxx>
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+
+SimpleCertificateValidationRequest::SimpleCertificateValidationRequest( sal_Int32 lCertificateValidity,
+ const css::uno::Reference<css::security::XCertificate>& certificate,
+ const OUString & hostname)
+{
+ // Fill request...
+ ucb::CertificateValidationRequest aRequest;
+ aRequest.CertificateValidity = lCertificateValidity;
+ aRequest.Certificate = certificate;
+ aRequest.HostName = hostname;
+
+ setRequest( uno::Any( aRequest ) );
+
+ setContinuations({ new InteractionAbort(this), new InteractionApprove(this) });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simpleinteractionrequest.cxx b/ucbhelper/source/provider/simpleinteractionrequest.cxx
new file mode 100644
index 0000000000..d846be5d35
--- /dev/null
+++ b/ucbhelper/source/provider/simpleinteractionrequest.cxx
@@ -0,0 +1,92 @@
+/* -*- 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 <ucbhelper/simpleinteractionrequest.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+
+SimpleInteractionRequest::SimpleInteractionRequest(
+ const uno::Any & rRequest,
+ const ContinuationFlags nContinuations )
+: InteractionRequest( rRequest )
+{
+ // Set continuations.
+ OSL_ENSURE( nContinuations != ContinuationFlags::NONE,
+ "SimpleInteractionRequest - No continuation!" );
+
+ std::vector< uno::Reference< task::XInteractionContinuation > > aContinuations;
+ if ( nContinuations & ContinuationFlags::Abort )
+ {
+ aContinuations.push_back( new InteractionAbort( this ) );
+ }
+ if ( nContinuations & ContinuationFlags::Retry )
+ {
+ aContinuations.push_back( new InteractionRetry( this ) );
+ }
+ if ( nContinuations & ContinuationFlags::Approve )
+ {
+ aContinuations.push_back( new InteractionApprove( this ) );
+ }
+ if ( nContinuations & ContinuationFlags::Disapprove )
+ {
+ aContinuations.push_back( new InteractionDisapprove( this ) );
+ }
+ setContinuations( comphelper::containerToSequence(aContinuations) );
+}
+
+
+ContinuationFlags SimpleInteractionRequest::getResponse() const
+{
+ rtl::Reference< InteractionContinuation > xSelection = getSelection();
+ if ( xSelection.is() )
+ {
+ InteractionContinuation * pSelection = xSelection.get();
+
+ uno::Reference< task::XInteractionAbort > xAbort(
+ pSelection, uno::UNO_QUERY );
+ if ( xAbort.is() )
+ return ContinuationFlags::Abort;
+
+ uno::Reference< task::XInteractionRetry > xRetry(
+ pSelection, uno::UNO_QUERY );
+ if ( xRetry.is() )
+ return ContinuationFlags::Retry;
+
+ uno::Reference< task::XInteractionApprove > xApprove(
+ pSelection, uno::UNO_QUERY );
+ if ( xApprove.is() )
+ return ContinuationFlags::Approve;
+
+ uno::Reference< task::XInteractionDisapprove > xDisapprove(
+ pSelection, uno::UNO_QUERY );
+ if ( xDisapprove.is() )
+ return ContinuationFlags::Disapprove;
+
+ OSL_FAIL( "SimpleInteractionRequest::getResponse - Unknown continuation!" );
+ }
+ return ContinuationFlags::NONE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simpleioerrorrequest.cxx b/ucbhelper/source/provider/simpleioerrorrequest.cxx
new file mode 100644
index 0000000000..0c0857f915
--- /dev/null
+++ b/ucbhelper/source/provider/simpleioerrorrequest.cxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include "simpleioerrorrequest.hxx"
+
+using namespace com::sun::star;
+using namespace ucbhelper;
+
+
+SimpleIOErrorRequest::SimpleIOErrorRequest(
+ const ucb::IOErrorCode eError,
+ const uno::Sequence< uno::Any > & rArgs,
+ const OUString & rMessage,
+ const uno::Reference< ucb::XCommandProcessor > & xContext )
+{
+ // Fill request...
+ ucb::InteractiveAugmentedIOException aRequest(
+ rMessage, xContext, task::InteractionClassification_ERROR, eError, rArgs);
+
+ setRequest( uno::Any( aRequest ) );
+
+ // Fill continuations...
+ setContinuations({ new InteractionAbort(this) });
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simpleioerrorrequest.hxx b/ucbhelper/source/provider/simpleioerrorrequest.hxx
new file mode 100644
index 0000000000..134f10a9aa
--- /dev/null
+++ b/ucbhelper/source/provider/simpleioerrorrequest.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 .
+ */
+
+#ifndef UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX
+#define UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX
+
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <ucbhelper/interactionrequest.hxx>
+
+namespace com::sun::star::ucb { class XCommandProcessor; }
+
+namespace ucbhelper {
+
+/**
+ * This class implements a simple IO error interaction request. Instances
+ * can be passed directly to XInteractionHandler::handle(...). Each
+ * instance contains an InteractiveIOException and one interaction
+ * continuation: "Abort".
+ *
+ * @see css::ucb::InteractiveIOException
+ * @see InteractionAbort
+ */
+class SimpleIOErrorRequest final : public ucbhelper::InteractionRequest
+{
+public:
+ /**
+ * Constructor.
+ *
+ * @param xContext contains the command processor that executes the
+ * command related to the request.
+ *
+ * @param eError is the error code to pass along with the request.
+ *
+ * qparam rArgs are additional parameters according to the specification
+ * of the error code. Refer to com/sun/star/ucb/IOErrorCode.idl
+ * for details.
+ */
+ SimpleIOErrorRequest( const css::ucb::IOErrorCode eError,
+ const css::uno::Sequence< css::uno::Any > & rArgs,
+ const OUString & rMessage,
+ const css::uno::Reference< css::ucb::XCommandProcessor > & xContext
+ );
+};
+
+} // namespace ucbhelper
+
+#endif /* ! UCBHELPER_SOURCE_PROVIDER_SIMPLEIOERRORREQUEST_HXX */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucbhelper/source/provider/simplenameclashresolverequest.cxx b/ucbhelper/source/provider/simplenameclashresolverequest.cxx
new file mode 100644
index 0000000000..652bdcdbb1
--- /dev/null
+++ b/ucbhelper/source/provider/simplenameclashresolverequest.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/ucb/NameClashResolveRequest.hpp>
+#include <com/sun/star/ucb/XInteractionSupplyName.hpp>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <ucbhelper/simplenameclashresolverequest.hxx>
+
+using namespace com::sun::star;
+
+namespace ucbhelper {
+
+/**
+ * This class implements a standard interaction continuation, namely the
+ * interface XInteractionSupplyName. Instances of this class can be passed
+ * along with an interaction request to indicate the possibility to
+ * supply a new name.
+ */
+class InteractionSupplyName : public InteractionContinuation,
+ public css::lang::XTypeProvider,
+ public css::ucb::XInteractionSupplyName
+{
+ OUString m_aName;
+
+public:
+ explicit InteractionSupplyName( InteractionRequest * pRequest )
+ : InteractionContinuation( pRequest ) {}
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL
+ queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire()
+ noexcept override;
+ virtual void SAL_CALL release()
+ noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL
+ getImplementationId() override;
+
+ // XInteractionContinuation
+ virtual void SAL_CALL select() override;
+
+ // XInteractionSupplyName
+ virtual void SAL_CALL setName( const OUString& Name ) override;
+
+ // Non-interface methods.
+
+ /**
+ * This method returns the name that was supplied by the interaction
+ * handler.
+ *
+ * @return the name.
+ */
+ const OUString & getName() const { return m_aName; }
+};
+
+void SAL_CALL InteractionSupplyName::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL InteractionSupplyName::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+uno::Any SAL_CALL
+InteractionSupplyName::queryInterface( const uno::Type & rType )
+{
+ uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< lang::XTypeProvider * >( this ),
+ static_cast< task::XInteractionContinuation * >( this ),
+ static_cast< ucb::XInteractionSupplyName * >( this ) );
+
+ return aRet.hasValue()
+ ? aRet : InteractionContinuation::queryInterface( rType );
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL InteractionSupplyName::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+uno::Sequence< uno::Type > SAL_CALL InteractionSupplyName::getTypes()
+{
+ static cppu::OTypeCollection s_aCollection(
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ cppu::UnoType<ucb::XInteractionSupplyName>::get() );
+
+ return s_aCollection.getTypes();
+}
+
+void SAL_CALL InteractionSupplyName::select()
+{
+ recordSelection();
+}
+
+void SAL_CALL
+InteractionSupplyName::setName( const OUString& Name )
+{
+ m_aName = Name;
+}
+
+SimpleNameClashResolveRequest::~SimpleNameClashResolveRequest() {}
+
+SimpleNameClashResolveRequest::SimpleNameClashResolveRequest(
+ const OUString & rTargetFolderURL,
+ const OUString & rClashingName )
+{
+ // Fill request...
+ ucb::NameClashResolveRequest aRequest;
+// aRequest.Message = // OUString
+// aRequest.Context = // XInterface
+ aRequest.Classification = task::InteractionClassification_QUERY;
+ aRequest.TargetFolderURL = rTargetFolderURL;
+ aRequest.ClashingName = rClashingName;
+ aRequest.ProposedNewName = OUString();
+
+ setRequest( uno::Any( aRequest ) );
+
+ // Fill continuations...
+ m_xNameSupplier = new InteractionSupplyName( this );
+
+ setContinuations({ new InteractionAbort(this), m_xNameSupplier,
+ new InteractionReplaceExistingData(this) });
+}
+
+OUString const & SimpleNameClashResolveRequest::getNewName() const
+{
+ return m_xNameSupplier->getName();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */