summaryrefslogtreecommitdiffstats
path: root/ucb/source/ucp/gio
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ucb/source/ucp/gio/gio_content.cxx1345
-rw-r--r--ucb/source/ucp/gio/gio_content.hxx187
-rw-r--r--ucb/source/ucp/gio/gio_datasupplier.cxx256
-rw-r--r--ucb/source/ucp/gio/gio_datasupplier.hxx88
-rw-r--r--ucb/source/ucp/gio/gio_inputstream.cxx91
-rw-r--r--ucb/source/ucp/gio/gio_inputstream.hxx58
-rw-r--r--ucb/source/ucp/gio/gio_mount.cxx211
-rw-r--r--ucb/source/ucp/gio/gio_mount.hxx88
-rw-r--r--ucb/source/ucp/gio/gio_outputstream.cxx78
-rw-r--r--ucb/source/ucp/gio/gio_outputstream.hxx62
-rw-r--r--ucb/source/ucp/gio/gio_provider.cxx139
-rw-r--r--ucb/source/ucp/gio/gio_provider.hxx52
-rw-r--r--ucb/source/ucp/gio/gio_resultset.cxx53
-rw-r--r--ucb/source/ucp/gio/gio_resultset.hxx46
-rw-r--r--ucb/source/ucp/gio/gio_seekable.cxx126
-rw-r--r--ucb/source/ucp/gio/gio_seekable.hxx60
-rw-r--r--ucb/source/ucp/gio/ucpgio.component26
17 files changed, 2966 insertions, 0 deletions
diff --git a/ucb/source/ucp/gio/gio_content.cxx b/ucb/source/ucp/gio/gio_content.cxx
new file mode 100644
index 000000000..fc31965a9
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_content.cxx
@@ -0,0 +1,1345 @@
+/* -*- 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 <rtl/uri.hxx>
+#include <utility>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sal/macros.h>
+#include <osl/time.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XActiveDataSink.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/ucb/ContentInfoAttribute.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp>
+#include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp>
+#include <com/sun/star/ucb/NameClashException.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+#include <com/sun/star/ucb/MissingInputStreamException.hpp>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/ucb/XDynamicResultSet.hpp>
+#include <com/sun/star/ucb/XContentCreator.hpp>
+
+#include <comphelper/seekableinput.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <ucbhelper/contentidentifier.hxx>
+#include <ucbhelper/propertyvalueset.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <ucbhelper/macros.hxx>
+#include <vcl/svapp.hxx>
+
+#include "gio_content.hxx"
+#include "gio_provider.hxx"
+#include "gio_resultset.hxx"
+#include "gio_inputstream.hxx"
+#include "gio_outputstream.hxx"
+#include "gio_mount.hxx"
+
+namespace gio
+{
+
+Content::Content(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ ContentProvider* pProvider,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier)
+ : ContentImplHelper( rxContext, pProvider, Identifier ),
+ m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(false)
+{
+ SAL_INFO("ucb.ucp.gio", "New Content ('" << m_xIdentifier->getContentIdentifier() << "')");
+}
+
+Content::Content(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ ContentProvider* pProvider,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier,
+ bool bIsFolder)
+ : ContentImplHelper( rxContext, pProvider, Identifier ),
+ m_pProvider( pProvider ), mpFile (nullptr), mpInfo( nullptr ), mbTransient(true)
+{
+ SAL_INFO("ucb.ucp.gio", "Create Content ('" << m_xIdentifier->getContentIdentifier() << "')");
+ mpInfo = g_file_info_new();
+ g_file_info_set_file_type(mpInfo, bIsFolder ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR);
+}
+
+Content::~Content()
+{
+ if (mpInfo) g_object_unref(mpInfo);
+ if (mpFile) g_object_unref(mpFile);
+}
+
+OUString Content::getParentURL()
+{
+ OUString sURL;
+ if (GFile* pFile = g_file_get_parent(getGFile()))
+ {
+ char* pPath = g_file_get_uri(pFile);
+ g_object_unref(pFile);
+ sURL = OUString::createFromAscii(pPath);
+ g_free(pPath);
+ }
+ return sURL;
+}
+
+void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ )
+{
+ //TODO
+ //stick a map from each CommandId to a new GCancellable and propagate
+ //it throughout the g_file_* calls
+}
+
+OUString SAL_CALL Content::getContentType()
+{
+ return isFolder(css::uno::Reference< css::ucb::XCommandEnvironment >())
+ ? OUString( GIO_FOLDER_TYPE )
+ : OUString( GIO_FILE_TYPE );
+}
+
+#define EXCEPT(aExcept) \
+do { \
+ if (bThrow) throw aExcept;\
+ aRet <<= aExcept;\
+} while(false)
+
+css::uno::Any convertToException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext, bool bThrow)
+{
+ css::uno::Any aRet;
+
+ gint eCode = pError->code;
+ OUString sMessage(pError->message, strlen(pError->message), RTL_TEXTENCODING_UTF8);
+ g_error_free(pError);
+
+ OUString sName;
+
+ css::uno::Sequence< css::uno::Any > aArgs{ css::uno::Any(sName) };
+
+ switch (eCode)
+ {
+ case G_IO_ERROR_FAILED:
+ { css::io::IOException aExcept(sMessage, rContext);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NOT_MOUNTED:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING_PATH, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NOT_FOUND:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_EXISTING, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_EXISTS:
+ { css::ucb::NameClashException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, sName);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_INVALID_ARGUMENT:
+ { css::lang::IllegalArgumentException aExcept(sMessage, rContext, -1 );
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_PERMISSION_DENIED:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_ACCESS_DENIED, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_IS_DIRECTORY:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NOT_REGULAR_FILE:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_FILE, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NOT_DIRECTORY:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NO_DIRECTORY, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_FILENAME_TOO_LONG:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NAME_TOO_LONG, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_FAILED_HANDLED: /* Operation failed and a helper program
+ has already interacted with the user. Do not display any error
+ dialog */
+ case G_IO_ERROR_PENDING:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_PENDING, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_CLOSED:
+ case G_IO_ERROR_CANCELLED:
+ case G_IO_ERROR_TOO_MANY_LINKS:
+ case G_IO_ERROR_WRONG_ETAG:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_GENERAL, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NOT_SUPPORTED:
+ case G_IO_ERROR_CANT_CREATE_BACKUP:
+ case G_IO_ERROR_WOULD_MERGE:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_NOT_SUPPORTED, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_NO_SPACE:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_OUT_OF_DISK_SPACE, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_INVALID_FILENAME:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_INVALID_CHARACTER, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_READ_ONLY:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_WRITE_PROTECTED, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_TIMED_OUT:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_DEVICE_NOT_READY, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_WOULD_RECURSE:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_RECURSIVE, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_BUSY:
+ case G_IO_ERROR_WOULD_BLOCK:
+ { css::ucb::InteractiveAugmentedIOException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, css::ucb::IOErrorCode_LOCKING_VIOLATION, aArgs);
+ EXCEPT(aExcept); }
+ break;
+ case G_IO_ERROR_HOST_NOT_FOUND:
+ { css::ucb::InteractiveNetworkResolveNameException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR, OUString());
+ EXCEPT(aExcept);}
+ break;
+ default:
+ case G_IO_ERROR_ALREADY_MOUNTED:
+ case G_IO_ERROR_NOT_EMPTY:
+ case G_IO_ERROR_NOT_SYMBOLIC_LINK:
+ case G_IO_ERROR_NOT_MOUNTABLE_FILE:
+ { css::ucb::InteractiveNetworkGeneralException aExcept(sMessage, rContext,
+ css::task::InteractionClassification_ERROR);
+ EXCEPT(aExcept);}
+ break;
+ }
+ return aRet;
+}
+
+void convertToIOException(GError *pError, const css::uno::Reference< css::uno::XInterface >& rContext)
+{
+ try
+ {
+ convertToException(pError, rContext);
+ }
+ catch (const css::io::IOException&)
+ {
+ throw;
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const css::uno::Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetRuntimeException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+}
+
+css::uno::Any Content::mapGIOError( GError *pError )
+{
+ if (!pError)
+ return getBadArgExcept();
+
+ return convertToException(pError, static_cast< cppu::OWeakObject * >(this), false);
+}
+
+css::uno::Any Content::getBadArgExcept()
+{
+ return css::uno::Any( css::lang::IllegalArgumentException(
+ "Wrong argument type!",
+ static_cast< cppu::OWeakObject * >( this ), -1) );
+}
+
+namespace {
+
+class MountOperation
+{
+ ucb::ucp::gio::glib::MainContextRef mContext;
+ GMainLoop *mpLoop;
+ GMountOperation *mpAuthentication;
+ GError *mpError;
+ static void Completed(GObject *source, GAsyncResult *res, gpointer user_data);
+public:
+ explicit MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv);
+ ~MountOperation();
+ GError *Mount(GFile *pFile);
+};
+
+}
+
+MountOperation::MountOperation(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv) : mpError(nullptr)
+{
+ ucb::ucp::gio::glib::MainContextRef oldContext(g_main_context_ref_thread_default());
+ mContext.reset(g_main_context_new());
+ mpLoop = g_main_loop_new(mContext.get(), FALSE);
+ g_main_context_push_thread_default(mContext.get());
+ mpAuthentication = ooo_mount_operation_new(std::move(oldContext), xEnv);
+}
+
+void MountOperation::Completed(GObject *source, GAsyncResult *res, gpointer user_data)
+{
+ MountOperation *pThis = static_cast<MountOperation*>(user_data);
+ g_file_mount_enclosing_volume_finish(G_FILE(source), res, &(pThis->mpError));
+ g_main_loop_quit(pThis->mpLoop);
+}
+
+GError *MountOperation::Mount(GFile *pFile)
+{
+ g_file_mount_enclosing_volume(pFile, G_MOUNT_MOUNT_NONE, mpAuthentication, nullptr, MountOperation::Completed, this);
+ {
+ //HACK: At least the gdk_threads_set_lock_functions(GdkThreadsEnter,
+ // GdkThreadsLeave) call in vcl/unx/gtk/app/gtkinst.cxx will lead to
+ // GdkThreadsLeave unlock the SolarMutex down to zero at the end of
+ // g_main_loop_run, so we need ~SolarMutexReleaser to raise it back to
+ // the original value again:
+ if (comphelper::SolarMutex::get()->IsCurrentThread())
+ {
+ SolarMutexReleaser rel;
+ g_main_loop_run(mpLoop);
+ }
+ else
+ {
+ g_main_loop_run(mpLoop);
+ }
+ }
+ return mpError;
+}
+
+MountOperation::~MountOperation()
+{
+ g_object_unref(mpAuthentication);
+ g_main_context_pop_thread_default(mContext.get());
+ g_main_loop_unref(mpLoop);
+}
+
+GFileInfo* Content::getGFileInfo(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv, GError **ppError)
+{
+ GError * err = nullptr;
+ if (mpInfo == nullptr && !mbTransient) {
+ for (bool retried = false;; retried = true) {
+ mpInfo = g_file_query_info(
+ getGFile(), "*", G_FILE_QUERY_INFO_NONE, nullptr, &err);
+ if (mpInfo != nullptr) {
+ break;
+ }
+ assert(err != nullptr);
+ if (err->code != G_IO_ERROR_NOT_MOUNTED || retried) {
+ break;
+ }
+ SAL_INFO(
+ "ucb.ucp.gio",
+ "G_IO_ERROR_NOT_MOUNTED \"" << err->message
+ << "\", trying to mount");
+ g_error_free(err);
+ err = MountOperation(xEnv).Mount(getGFile());
+ if (err != nullptr) {
+ break;
+ }
+ }
+ }
+ if (ppError != nullptr) {
+ *ppError = err;
+ } else if (err != nullptr) {
+ SAL_WARN(
+ "ucb.ucp.gio",
+ "ignoring GError \"" << err->message << "\" for <"
+ << m_xIdentifier->getContentIdentifier() << ">");
+ g_error_free(err);
+ }
+ return mpInfo;
+}
+
+GFile* Content::getGFile()
+{
+ if (!mpFile)
+ mpFile = g_file_new_for_uri(OUStringToOString(m_xIdentifier->getContentIdentifier(), RTL_TEXTENCODING_UTF8).getStr());
+ return mpFile;
+}
+
+bool Content::isFolder(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
+{
+ GFileInfo *pInfo = getGFileInfo(xEnv);
+ return pInfo && (g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY);
+}
+
+static css::util::DateTime getDateFromUnix (time_t t)
+{
+ TimeValue tv;
+ tv.Nanosec = 0;
+ tv.Seconds = t;
+ oslDateTime dt;
+
+ if ( osl_getDateTimeFromTimeValue( &tv, &dt ) )
+ return css::util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours,
+ dt.Day, dt.Month, dt.Year, false);
+ else
+ return css::util::DateTime();
+}
+
+css::uno::Reference< css::sdbc::XRow > Content::getPropertyValues(
+ const css::uno::Sequence< css::beans::Property >& rProperties,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
+{
+ rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_xContext );
+
+ GFileInfo *pInfo = nullptr;
+ for( const css::beans::Property& rProp : rProperties )
+ {
+ if ( rProp.Name == "IsDocument" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE))
+ xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_REGULAR ||
+ g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_UNKNOWN ) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "IsFolder" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) )
+ xRow->appendBoolean( rProp, ( g_file_info_get_file_type( pInfo ) == G_FILE_TYPE_DIRECTORY ));
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "Title" )
+ {
+ getFileInfo(xEnv, &pInfo, false);
+ if (pInfo != nullptr && g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME))
+ {
+ const char *pName = g_file_info_get_display_name(pInfo);
+ xRow->appendString( rProp, OUString(pName, strlen(pName), RTL_TEXTENCODING_UTF8) );
+ }
+ else
+ xRow->appendVoid(rProp);
+ }
+ else if ( rProp.Name == "IsReadOnly" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE ) )
+ xRow->appendBoolean( rProp, !g_file_info_get_attribute_boolean( pInfo, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "DateCreated" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CREATED ) )
+ xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CREATED)) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "DateModified" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED ) )
+ xRow->appendTimestamp( rProp, getDateFromUnix(g_file_info_get_attribute_uint64(pInfo, G_FILE_ATTRIBUTE_TIME_CHANGED)) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "Size" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_SIZE) )
+ xRow->appendLong( rProp, ( g_file_info_get_size( pInfo ) ));
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "IsVolume" )
+ {
+ //What do we use this for ?
+ xRow->appendBoolean( rProp, false );
+ }
+ else if ( rProp.Name == "IsCompactDisc" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT ) )
+ xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "IsRemoveable" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) )
+ xRow->appendBoolean( rProp, g_file_info_get_attribute_boolean(pInfo, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT ) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "IsFloppy" )
+ {
+ xRow->appendBoolean( rProp, false );
+ }
+ else if ( rProp.Name == "IsHidden" )
+ {
+ getFileInfo(xEnv, &pInfo, true);
+ if (pInfo != nullptr && g_file_info_has_attribute( pInfo, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) )
+ xRow->appendBoolean( rProp, ( g_file_info_get_is_hidden ( pInfo ) ) );
+ else
+ xRow->appendVoid( rProp );
+ }
+ else if ( rProp.Name == "CreatableContentsInfo" )
+ {
+ xRow->appendObject( rProp, css::uno::Any( queryCreatableContentsInfo( xEnv ) ) );
+ }
+ else
+ {
+ SAL_WARN(
+ "ucb.ucp.gio",
+ "Looking for unsupported property " << rProp.Name);
+ xRow->appendVoid(rProp);
+ }
+ }
+
+ return xRow;
+}
+
+static css::lang::IllegalAccessException
+getReadOnlyException( const css::uno::Reference< css::uno::XInterface >& rContext )
+{
+ return css::lang::IllegalAccessException ("Property is read-only!", rContext );
+}
+
+void Content::queryChildren( ContentRefList& rChildren )
+{
+ // Obtain a list with a snapshot of all currently instantiated contents
+ // from provider and extract the contents which are direct children
+ // of this content.
+
+ ucbhelper::ContentRefList aAllContents;
+ m_xProvider->queryExistingContents( aAllContents );
+
+ OUString aURL = m_xIdentifier->getContentIdentifier();
+ sal_Int32 nURLPos = aURL.lastIndexOf( '/' );
+
+ if ( nURLPos != ( aURL.getLength() - 1 ) )
+ aURL += "/";
+
+ sal_Int32 nLen = aURL.getLength();
+
+ for ( const auto& rContent : aAllContents )
+ {
+ ucbhelper::ContentImplHelperRef xChild = rContent;
+ OUString aChildURL = xChild->getIdentifier()->getContentIdentifier();
+
+ // Is aURL a prefix of aChildURL?
+ if ( ( aChildURL.getLength() > nLen ) && aChildURL.startsWith( aURL ) )
+ {
+ sal_Int32 nPos = aChildURL.indexOf( '/', nLen );
+
+ if ( ( nPos == -1 ) || ( nPos == ( aChildURL.getLength() - 1 ) ) )
+ {
+ // No further slashes / only a final slash. It's a child!
+ rChildren.emplace_back(static_cast< ::gio::Content * >(xChild.get() ) );
+ }
+ }
+ }
+}
+
+bool Content::exchangeIdentity( const css::uno::Reference< css::ucb::XContentIdentifier >& xNewId )
+{
+ if ( !xNewId.is() )
+ return false;
+
+ css::uno::Reference< css::ucb::XContent > xThis = this;
+
+ if ( mbTransient )
+ {
+ m_xIdentifier = xNewId;
+ return false;
+ }
+
+ OUString aOldURL = m_xIdentifier->getContentIdentifier();
+
+ // Exchange own identity.
+ if ( exchange( xNewId ) )
+ {
+ // Process instantiated children...
+ ContentRefList aChildren;
+ queryChildren( aChildren );
+
+ for ( const auto& rChild : aChildren )
+ {
+ ContentRef xChild = rChild;
+
+ // Create new content identifier for the child...
+ css::uno::Reference< css::ucb::XContentIdentifier > xOldChildId = xChild->getIdentifier();
+ OUString aOldChildURL = xOldChildId->getContentIdentifier();
+ OUString aNewChildURL = aOldChildURL.replaceAt(
+ 0, aOldURL.getLength(), xNewId->getContentIdentifier() );
+
+ css::uno::Reference< css::ucb::XContentIdentifier > xNewChildId
+ = new ::ucbhelper::ContentIdentifier( aNewChildURL );
+
+ if ( !xChild->exchangeIdentity( xNewChildId ) )
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void Content::getFileInfo(
+ css::uno::Reference<css::ucb::XCommandEnvironment> const & env, GFileInfo ** info, bool fail)
+{
+ assert(info != nullptr);
+ if (*info != nullptr)
+ return;
+
+ GError * err = nullptr;
+ *info = getGFileInfo(env, &err);
+ if (*info == nullptr && !mbTransient && fail)
+ {
+ ucbhelper::cancelCommandExecution(mapGIOError(err), env);
+ }
+ else if (err != nullptr)
+ {
+ g_error_free(err);
+ }
+}
+
+css::uno::Sequence< css::uno::Any > Content::setPropertyValues(
+ const css::uno::Sequence< css::beans::PropertyValue >& rValues,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
+{
+ GError *pError=nullptr;
+ GFileInfo *pNewInfo=nullptr;
+ GFileInfo *pInfo = getGFileInfo(xEnv, &pError);
+ if (pInfo)
+ pNewInfo = g_file_info_dup(pInfo);
+ else
+ {
+ if (!mbTransient)
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ else
+ {
+ if (pError)
+ g_error_free(pError);
+ pNewInfo = g_file_info_new();
+ }
+ }
+
+ sal_Int32 nCount = rValues.getLength();
+
+ css::beans::PropertyChangeEvent aEvent;
+ aEvent.Source = static_cast< cppu::OWeakObject * >( this );
+ aEvent.Further = false;
+ aEvent.PropertyHandle = -1;
+
+ sal_Int32 nChanged = 0, nTitlePos = -1;
+ OUString aNewTitle;
+ css::uno::Sequence< css::beans::PropertyChangeEvent > aChanges(nCount);
+ auto aChangesRange = asNonConstRange(aChanges);
+
+ css::uno::Sequence< css::uno::Any > aRet( nCount );
+ auto aRetRange = asNonConstRange(aRet);
+ const css::beans::PropertyValue* pValues = rValues.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const css::beans::PropertyValue& rValue = pValues[ n ];
+ SAL_INFO("ucb.ucp.gio", "Set prop '" << rValue.Name << "'");
+ if ( rValue.Name == "ContentType" ||
+ rValue.Name == "MediaType" ||
+ rValue.Name == "IsDocument" ||
+ rValue.Name == "IsFolder" ||
+ rValue.Name == "Size" ||
+ rValue.Name == "CreatableContentsInfo" )
+ {
+ aRetRange[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
+ }
+ else if ( rValue.Name == "Title" )
+ {
+ if (!( rValue.Value >>= aNewTitle ))
+ {
+ aRetRange[ n ] <<= css::beans::IllegalTypeException
+ ( "Property value has wrong type!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ continue;
+ }
+
+ if ( aNewTitle.isEmpty() )
+ {
+ aRetRange[ n ] <<= css::lang::IllegalArgumentException
+ ( "Empty title not allowed!",
+ static_cast< cppu::OWeakObject * >( this ), -1 );
+ continue;
+
+ }
+
+ OString sNewTitle = OUStringToOString(aNewTitle, RTL_TEXTENCODING_UTF8);
+ const char *newName = sNewTitle.getStr();
+ const char *oldName = g_file_info_get_name( pInfo);
+
+ if (!newName || !oldName || strcmp(newName, oldName))
+ {
+ SAL_INFO("ucb.ucp.gio", "Set new name to '" << newName << "'");
+
+ aEvent.PropertyName = "Title";
+ if (oldName)
+ aEvent.OldValue <<= OUString(oldName, strlen(oldName), RTL_TEXTENCODING_UTF8);
+ aEvent.NewValue <<= aNewTitle;
+ aChangesRange[ nChanged ] = aEvent;
+ nTitlePos = nChanged++;
+
+ g_file_info_set_name(pNewInfo, newName);
+ }
+ }
+ else
+ {
+ SAL_WARN("ucb.ucp.gio", "Unknown property " << rValue.Name);
+ aRetRange[ n ] <<= getReadOnlyException( static_cast< cppu::OWeakObject * >(this) );
+ }
+ }
+
+ if (nChanged)
+ {
+ bool bOk = true;
+ if (!mbTransient)
+ {
+ if ((bOk = doSetFileInfo(pNewInfo)))
+ {
+ for (sal_Int32 i = 0; i < nChanged; ++i)
+ aRetRange[ i ] = getBadArgExcept();
+ }
+ }
+
+ if (bOk)
+ {
+ if (nTitlePos > -1)
+ {
+ OUString aNewURL = getParentURL();
+ if (!aNewURL.isEmpty() && aNewURL[aNewURL.getLength() - 1] != '/')
+ aNewURL += "/";
+ aNewURL += aNewTitle;
+
+ css::uno::Reference< css::ucb::XContentIdentifier > xNewId
+ = new ::ucbhelper::ContentIdentifier( aNewURL );
+
+ if (!exchangeIdentity( xNewId ) )
+ {
+ aRetRange[ nTitlePos ] <<= css::uno::Exception
+ ( "Exchange failed!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ }
+
+ if (!mbTransient) //Discard and refetch
+ {
+ g_object_unref(mpInfo);
+ mpInfo = nullptr;
+ }
+
+ if (mpInfo)
+ {
+ g_file_info_copy_into(pNewInfo, mpInfo);
+ g_object_unref(pNewInfo);
+ }
+ else
+ mpInfo = pNewInfo;
+
+ pNewInfo = nullptr;
+
+ if (mpFile) //Discard and refetch
+ {
+ g_object_unref(mpFile);
+ mpFile = nullptr;
+ }
+ }
+
+ aChanges.realloc( nChanged );
+ notifyPropertiesChange( aChanges );
+ }
+
+ if (pNewInfo)
+ g_object_unref(pNewInfo);
+
+ return aRet;
+}
+
+bool Content::doSetFileInfo(GFileInfo *pNewInfo)
+{
+ g_assert (!mbTransient);
+
+ bool bOk = true;
+ GFile *pFile = getGFile();
+ if(!g_file_set_attributes_from_info(pFile, pNewInfo, G_FILE_QUERY_INFO_NONE, nullptr, nullptr))
+ bOk = false;
+ return bOk;
+}
+
+const int TRANSFER_BUFFER_SIZE = 65536;
+
+void Content::copyData( const css::uno::Reference< css::io::XInputStream >& xIn,
+ const css::uno::Reference< css::io::XOutputStream >& xOut )
+{
+ css::uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE );
+
+ g_return_if_fail( xIn.is() && xOut.is() );
+
+ while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 )
+ xOut->writeBytes( theData );
+
+ xOut->closeOutput();
+}
+
+bool Content::feedSink( const css::uno::Reference< css::uno::XInterface >& xSink )
+{
+ if ( !xSink.is() )
+ return false;
+
+ css::uno::Reference< css::io::XOutputStream > xOut(xSink, css::uno::UNO_QUERY );
+ css::uno::Reference< css::io::XActiveDataSink > xDataSink(xSink, css::uno::UNO_QUERY );
+
+ if ( !xOut.is() && !xDataSink.is() )
+ return false;
+
+ GError *pError=nullptr;
+ GFileInputStream *pStream = g_file_read(getGFile(), nullptr, &pError);
+ if (!pStream)
+ convertToException(pError, static_cast< cppu::OWeakObject * >(this));
+
+ css::uno::Reference< css::io::XInputStream > xIn(
+ new comphelper::OSeekableInputWrapper(
+ new ::gio::InputStream(pStream), m_xContext));
+
+ if ( xOut.is() )
+ copyData( xIn, xOut );
+
+ if ( xDataSink.is() )
+ xDataSink->setInputStream( xIn );
+
+ return true;
+}
+
+css::uno::Any Content::open(const css::ucb::OpenCommandArgument2 & rOpenCommand,
+ const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv )
+{
+ bool bIsFolder = isFolder(xEnv);
+
+ if (!g_file_query_exists(getGFile(), nullptr))
+ {
+ css::uno::Sequence< css::uno::Any > aArgs{ css::uno::Any(
+ m_xIdentifier->getContentIdentifier()) };
+ css::uno::Any aErr(
+ css::ucb::InteractiveAugmentedIOException(OUString(), static_cast< cppu::OWeakObject * >( this ),
+ css::task::InteractionClassification_ERROR,
+ bIsFolder ? css::ucb::IOErrorCode_NOT_EXISTING_PATH : css::ucb::IOErrorCode_NOT_EXISTING, aArgs)
+ );
+
+ ucbhelper::cancelCommandExecution(aErr, xEnv);
+ }
+
+ css::uno::Any aRet;
+
+ bool bOpenFolder = (
+ ( rOpenCommand.Mode == css::ucb::OpenMode::ALL ) ||
+ ( rOpenCommand.Mode == css::ucb::OpenMode::FOLDERS ) ||
+ ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENTS )
+ );
+
+ if ( bOpenFolder && bIsFolder )
+ {
+ css::uno::Reference< css::ucb::XDynamicResultSet > xSet
+ = new DynamicResultSet( m_xContext, this, rOpenCommand, xEnv );
+ aRet <<= xSet;
+ }
+ else if ( rOpenCommand.Sink.is() )
+ {
+ if (
+ ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) ||
+ ( rOpenCommand.Mode == css::ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE )
+ )
+ {
+ ucbhelper::cancelCommandExecution(
+ css::uno::Any ( css::ucb::UnsupportedOpenModeException
+ ( OUString(), static_cast< cppu::OWeakObject * >( this ),
+ sal_Int16( rOpenCommand.Mode ) ) ),
+ xEnv );
+ }
+
+ if ( !feedSink( rOpenCommand.Sink ) )
+ {
+ // Note: rOpenCommand.Sink may contain an XStream
+ // implementation. Support for this type of
+ // sink is optional...
+ SAL_WARN("ucb.ucp.gio", "Failed to load data from '" << m_xIdentifier->getContentIdentifier() << "'");
+
+ ucbhelper::cancelCommandExecution(
+ css::uno::Any (css::ucb::UnsupportedDataSinkException
+ ( OUString(), static_cast< cppu::OWeakObject * >( this ),
+ rOpenCommand.Sink ) ),
+ xEnv );
+ }
+ }
+ else
+ SAL_INFO("ucb.ucp.gio", "Open falling through ...");
+ return aRet;
+}
+
+css::uno::Any SAL_CALL Content::execute(
+ const css::ucb::Command& aCommand,
+ sal_Int32 /*CommandId*/,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
+{
+ SAL_INFO("ucb.ucp.gio", "Content::execute " << aCommand.Name);
+ css::uno::Any aRet;
+
+ if ( aCommand.Name == "getPropertyValues" )
+ {
+ css::uno::Sequence< css::beans::Property > Properties;
+ if ( !( aCommand.Argument >>= Properties ) )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ aRet <<= getPropertyValues( Properties, xEnv );
+ }
+ else if ( aCommand.Name == "getPropertySetInfo" )
+ aRet <<= getPropertySetInfo( xEnv, false );
+ else if ( aCommand.Name == "getCommandInfo" )
+ aRet <<= getCommandInfo( xEnv, false );
+ else if ( aCommand.Name == "open" )
+ {
+ css::ucb::OpenCommandArgument2 aOpenCommand;
+ if ( !( aCommand.Argument >>= aOpenCommand ) )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ aRet = open( aOpenCommand, xEnv );
+ }
+ else if ( aCommand.Name == "transfer" )
+ {
+ css::ucb::TransferInfo transferArgs;
+ if ( !( aCommand.Argument >>= transferArgs ) )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ transfer( transferArgs, xEnv );
+ }
+ else if ( aCommand.Name == "setPropertyValues" )
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aProperties;
+ if ( !( aCommand.Argument >>= aProperties ) || !aProperties.hasElements() )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ aRet <<= setPropertyValues( aProperties, xEnv );
+ }
+ else if (aCommand.Name == "createNewContent"
+ && isFolder( xEnv ) )
+ {
+ css::ucb::ContentInfo arg;
+ if ( !( aCommand.Argument >>= arg ) )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ aRet <<= createNewContent( arg );
+ }
+ else if ( aCommand.Name == "insert" )
+ {
+ css::ucb::InsertCommandArgument arg;
+ if ( !( aCommand.Argument >>= arg ) )
+ ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv );
+ insert( arg.Data, arg.ReplaceExisting, xEnv );
+ }
+ else if ( aCommand.Name == "delete" )
+ {
+ bool bDeletePhysical = false;
+ aCommand.Argument >>= bDeletePhysical;
+
+ //If no delete physical, try and trashcan it, if that doesn't work go
+ //ahead and try and delete it anyway
+ if (!bDeletePhysical && !g_file_trash(getGFile(), nullptr, nullptr))
+ bDeletePhysical = true;
+
+ if (bDeletePhysical)
+ {
+ GError *pError = nullptr;
+ if (!g_file_delete( getGFile(), nullptr, &pError))
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ }
+
+ destroy( bDeletePhysical );
+ }
+ else
+ {
+ SAL_WARN("ucb.ucp.gio", "Unknown command " << aCommand.Name);
+
+ ucbhelper::cancelCommandExecution
+ ( css::uno::Any( css::ucb::UnsupportedCommandException
+ ( OUString(),
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+
+ return aRet;
+}
+
+void Content::destroy( bool bDeletePhysical )
+{
+ css::uno::Reference< css::ucb::XContent > xThis = this;
+
+ deleted();
+
+ ::gio::Content::ContentRefList aChildren;
+ queryChildren( aChildren );
+
+ for ( auto& rChild : aChildren )
+ {
+ rChild->destroy( bDeletePhysical );
+ }
+}
+
+void Content::insert(const css::uno::Reference< css::io::XInputStream > &xInputStream,
+ bool bReplaceExisting, const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv )
+{
+ GError *pError = nullptr;
+ GFileInfo *pInfo = getGFileInfo(xEnv);
+
+ if ( pInfo &&
+ g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_TYPE) &&
+ g_file_info_get_file_type(pInfo) == G_FILE_TYPE_DIRECTORY )
+ {
+ SAL_INFO("ucb.ucp.gio", "Make directory");
+ if( !g_file_make_directory( getGFile(), nullptr, &pError))
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ return;
+ }
+
+ if ( !xInputStream.is() )
+ {
+ ucbhelper::cancelCommandExecution( css::uno::Any
+ ( css::ucb::MissingInputStreamException
+ ( OUString(), static_cast< cppu::OWeakObject * >( this ) ) ),
+ xEnv );
+ }
+
+ GFileOutputStream* pOutStream = nullptr;
+ if ( bReplaceExisting )
+ {
+ if (!(pOutStream = g_file_replace(getGFile(), nullptr, false, G_FILE_CREATE_PRIVATE, nullptr, &pError)))
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ }
+ else
+ {
+ if (!(pOutStream = g_file_create (getGFile(), G_FILE_CREATE_PRIVATE, nullptr, &pError)))
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ }
+
+ css::uno::Reference < css::io::XOutputStream > xOutput = new ::gio::OutputStream(pOutStream);
+ copyData( xInputStream, xOutput );
+
+ if (mbTransient)
+ {
+ mbTransient = false;
+ inserted();
+ }
+}
+
+const GFileCopyFlags DEFAULT_COPYDATA_FLAGS =
+ static_cast<GFileCopyFlags>(G_FILE_COPY_OVERWRITE|G_FILE_COPY_TARGET_DEFAULT_PERMS);
+
+void Content::transfer( const css::ucb::TransferInfo& aTransferInfo, const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv )
+{
+ OUString sDest = m_xIdentifier->getContentIdentifier();
+ if (!sDest.endsWith("/")) {
+ sDest += "/";
+ }
+ if (!aTransferInfo.NewTitle.isEmpty())
+ {
+ sDest += rtl::Uri::encode( aTransferInfo.NewTitle,
+ rtl_UriCharClassPchar,
+ rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8 );
+ }
+ else
+ sDest += OUString::createFromAscii(g_file_get_basename(getGFile()));
+
+ GFile *pDest = g_file_new_for_uri(OUStringToOString(sDest, RTL_TEXTENCODING_UTF8).getStr());
+ GFile *pSource = g_file_new_for_uri(OUStringToOString(aTransferInfo.SourceURL, RTL_TEXTENCODING_UTF8).getStr());
+
+ bool bSuccess = false;
+ GError *pError = nullptr;
+ if (aTransferInfo.MoveData)
+ bSuccess = g_file_move(pSource, pDest, G_FILE_COPY_OVERWRITE, nullptr, nullptr, nullptr, &pError);
+ else
+ bSuccess = g_file_copy(pSource, pDest, DEFAULT_COPYDATA_FLAGS, nullptr, nullptr, nullptr, &pError);
+ g_object_unref(pSource);
+ g_object_unref(pDest);
+ if (!bSuccess) {
+ SAL_INFO(
+ "ucb.ucp.gio",
+ "transfer <" << aTransferInfo.SourceURL << "> to <" << sDest << "> (MoveData = "
+ << int(aTransferInfo.MoveData) << ") failed with \"" << pError->message << "\"");
+ ucbhelper::cancelCommandExecution(mapGIOError(pError), xEnv);
+ }
+}
+
+css::uno::Sequence< css::ucb::ContentInfo > Content::queryCreatableContentsInfo(
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv)
+{
+ if ( isFolder( xEnv ) )
+ {
+
+ // Minimum set of props we really need
+ css::uno::Sequence< css::beans::Property > props
+ {
+ { "Title", -1, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID | css::beans::PropertyAttribute::BOUND }
+ };
+
+ return
+ {
+ { GIO_FILE_TYPE, ( css::ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | css::ucb::ContentInfoAttribute::KIND_DOCUMENT ), props },
+ { GIO_FOLDER_TYPE, css::ucb::ContentInfoAttribute::KIND_FOLDER, props }
+ };
+ }
+ else
+ {
+ return {};
+ }
+}
+
+css::uno::Sequence< css::ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo()
+{
+ return queryCreatableContentsInfo( css::uno::Reference< css::ucb::XCommandEnvironment >() );
+}
+
+css::uno::Reference< css::ucb::XContent >
+ SAL_CALL Content::createNewContent( const css::ucb::ContentInfo& Info )
+{
+ bool create_document;
+ const char *name;
+
+ if ( Info.Type == GIO_FILE_TYPE )
+ create_document = true;
+ else if ( Info.Type == GIO_FOLDER_TYPE )
+ create_document = false;
+ else
+ {
+ SAL_WARN("ucb.ucp.gio", "Failed to create new content '" << Info.Type << "'");
+ return css::uno::Reference< css::ucb::XContent >();
+ }
+
+ SAL_INFO("ucb.ucp.gio", "createNewContent (" << create_document << ")");
+ OUString aURL = m_xIdentifier->getContentIdentifier();
+
+ if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() )
+ aURL += "/";
+
+ name = create_document ? "[New_Content]" : "[New_Collection]";
+ aURL += OUString::createFromAscii( name );
+
+ css::uno::Reference< css::ucb::XContentIdentifier > xId(new ::ucbhelper::ContentIdentifier(aURL));
+
+ try
+ {
+ return new ::gio::Content( m_xContext, m_pProvider, xId, !create_document );
+ } catch ( css::ucb::ContentCreationException & )
+ {
+ return css::uno::Reference< css::ucb::XContent >();
+ }
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL Content::getTypes()
+{
+ if ( isFolder( css::uno::Reference< css::ucb::XCommandEnvironment >() ) )
+ {
+ static cppu::OTypeCollection s_aFolderCollection
+ (CPPU_TYPE_REF( css::lang::XTypeProvider ),
+ CPPU_TYPE_REF( css::lang::XServiceInfo ),
+ CPPU_TYPE_REF( css::lang::XComponent ),
+ CPPU_TYPE_REF( css::ucb::XContent ),
+ CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
+ CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
+ CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
+ CPPU_TYPE_REF( css::beans::XPropertyContainer ),
+ CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
+ CPPU_TYPE_REF( css::container::XChild ),
+ CPPU_TYPE_REF( css::ucb::XContentCreator ) );
+ return s_aFolderCollection.getTypes();
+ }
+ else
+ {
+ static cppu::OTypeCollection s_aFileCollection
+ (CPPU_TYPE_REF( css::lang::XTypeProvider ),
+ CPPU_TYPE_REF( css::lang::XServiceInfo ),
+ CPPU_TYPE_REF( css::lang::XComponent ),
+ CPPU_TYPE_REF( css::ucb::XContent ),
+ CPPU_TYPE_REF( css::ucb::XCommandProcessor ),
+ CPPU_TYPE_REF( css::beans::XPropertiesChangeNotifier ),
+ CPPU_TYPE_REF( css::ucb::XCommandInfoChangeNotifier ),
+ CPPU_TYPE_REF( css::beans::XPropertyContainer ),
+ CPPU_TYPE_REF( css::beans::XPropertySetInfoChangeNotifier ),
+ CPPU_TYPE_REF( css::container::XChild ) );
+
+ return s_aFileCollection.getTypes();
+ }
+}
+
+css::uno::Sequence< css::beans::Property > Content::getProperties(
+ const css::uno::Reference< css::ucb::XCommandEnvironment > & /*xEnv*/ )
+{
+ static const css::beans::Property aGenericProperties[] =
+ {
+ css::beans::Property( "IsDocument",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "IsFolder",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "Title",
+ -1, cppu::UnoType<OUString>::get(),
+ css::beans::PropertyAttribute::BOUND ),
+ css::beans::Property( "IsReadOnly",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "DateCreated",
+ -1, cppu::UnoType<css::util::DateTime>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "DateModified",
+ -1, cppu::UnoType<css::util::DateTime>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "Size",
+ -1, cppu::UnoType<sal_Int64>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "IsVolume",
+ 1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "IsCompactDisc",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "IsRemoveable",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "IsHidden",
+ -1, cppu::UnoType<bool>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY ),
+ css::beans::Property( "CreatableContentsInfo",
+ -1, cppu::UnoType<css::uno::Sequence< css::ucb::ContentInfo >>::get(),
+ css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY )
+ };
+
+ const int nProps = SAL_N_ELEMENTS(aGenericProperties);
+ return css::uno::Sequence< css::beans::Property > ( aGenericProperties, nProps );
+}
+
+css::uno::Sequence< css::ucb::CommandInfo > Content::getCommands( const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv)
+{
+ static const css::ucb::CommandInfo aCommandInfoTable[] =
+ {
+ // Required commands
+ css::ucb::CommandInfo
+ ( "getCommandInfo",
+ -1, cppu::UnoType<void>::get() ),
+ css::ucb::CommandInfo
+ ( "getPropertySetInfo",
+ -1, cppu::UnoType<void>::get() ),
+ css::ucb::CommandInfo
+ ( "getPropertyValues",
+ -1, cppu::UnoType<css::uno::Sequence< css::beans::Property >>::get() ),
+ css::ucb::CommandInfo
+ ( "setPropertyValues",
+ -1, cppu::UnoType<css::uno::Sequence< css::beans::PropertyValue >>::get() ),
+
+ // Optional standard commands
+ css::ucb::CommandInfo
+ ( "delete",
+ -1, cppu::UnoType<bool>::get() ),
+ css::ucb::CommandInfo
+ ( "insert",
+ -1, cppu::UnoType<css::ucb::InsertCommandArgument>::get() ),
+ css::ucb::CommandInfo
+ ( "open",
+ -1, cppu::UnoType<css::ucb::OpenCommandArgument2>::get() ),
+
+ // Folder Only, omitted if not a folder
+ css::ucb::CommandInfo
+ ( "transfer",
+ -1, cppu::UnoType<css::ucb::TransferInfo>::get() ),
+ css::ucb::CommandInfo
+ ( "createNewContent",
+ -1, cppu::UnoType<css::ucb::ContentInfo>::get() )
+ };
+
+ const int nProps = SAL_N_ELEMENTS(aCommandInfoTable);
+ return css::uno::Sequence< css::ucb::CommandInfo >(aCommandInfoTable, isFolder(xEnv) ? nProps : nProps - 2);
+}
+
+XTYPEPROVIDER_COMMON_IMPL( Content );
+
+void SAL_CALL Content::acquire() noexcept
+{
+ ContentImplHelper::acquire();
+}
+
+void SAL_CALL Content::release() noexcept
+{
+ ContentImplHelper::release();
+}
+
+css::uno::Any SAL_CALL Content::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType, static_cast< css::ucb::XContentCreator * >( this ) );
+ return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface(rType);
+}
+
+OUString SAL_CALL Content::getImplementationName()
+{
+ return "com.sun.star.comp.GIOContent";
+}
+
+css::uno::Sequence< OUString > SAL_CALL Content::getSupportedServiceNames()
+{
+ css::uno::Sequence<OUString> aSNS { "com.sun.star.ucb.GIOContent" };
+ return aSNS;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_content.hxx b/ucb/source/ucp/gio/gio_content.hxx
new file mode 100644
index 000000000..0c80da5cd
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_content.hxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/TransferInfo.hpp>
+#include <com/sun/star/ucb/XContentCreator.hpp>
+#include <ucbhelper/contenthelper.hxx>
+#include <gio/gio.h>
+
+#include <vector>
+
+namespace com::sun::star {
+ namespace beans {
+ struct Property;
+ struct PropertyValue;
+ }
+ namespace sdbc {
+ class XRow;
+ }
+}
+namespace ucbhelper
+{
+ class Content;
+}
+
+
+namespace gio
+{
+
+
+inline constexpr OUStringLiteral GIO_FILE_TYPE = u"application/vnd.sun.staroffice.gio-file";
+inline constexpr OUStringLiteral GIO_FOLDER_TYPE = u"application/vnd.sun.staroffice.gio-folder";
+
+css::uno::Any convertToException(GError *pError,
+ const css::uno::Reference< css::uno::XInterface >& rContext, bool bThrow=true);
+/// @throws css::io::IOException
+/// @throws css::uno::RuntimeException
+void convertToIOException(GError *pError,
+ const css::uno::Reference< css::uno::XInterface >& rContext);
+
+class ContentProvider;
+class Content : public ::ucbhelper::ContentImplHelper, public css::ucb::XContentCreator
+{
+private:
+ ContentProvider *m_pProvider;
+ GFile* mpFile;
+ GFileInfo *mpInfo;
+ bool mbTransient;
+
+ GFileInfo *getGFileInfo(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv,
+ GError **ppError=nullptr);
+ bool isFolder(const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv);
+
+ css::uno::Any mapGIOError( GError *error );
+ css::uno::Any getBadArgExcept();
+
+ css::uno::Reference< css::sdbc::XRow >
+ getPropertyValues(
+ const css::uno::Sequence< css::beans::Property >& rProperties,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv );
+private:
+ typedef rtl::Reference< Content > ContentRef;
+ typedef std::vector< ContentRef > ContentRefList;
+
+ void queryChildren( ContentRefList& rChildren );
+
+ bool doSetFileInfo ( GFileInfo *pNewInfo );
+
+ /// @throws css::uno::Exception
+ css::uno::Any open(const css::ucb::OpenCommandArgument2 & rArg,
+ const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv );
+
+ /// @throws css::uno::Exception
+ void transfer( const css::ucb::TransferInfo& rTransferInfo,
+ const css::uno::Reference< css::ucb::XCommandEnvironment > & xEnv );
+
+ /// @throws css::uno::Exception
+ void insert( const css::uno::Reference< css::io::XInputStream > & xInputStream,
+ bool bReplaceExisting, const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv );
+
+ /// @throws css::uno::Exception
+ void destroy( bool bDeletePhysical );
+
+ static void copyData( const css::uno::Reference< css::io::XInputStream >& xIn,
+ const css::uno::Reference< css::io::XOutputStream >& xOut );
+
+ css::uno::Sequence< css::uno::Any >
+ setPropertyValues( const css::uno::Sequence<
+ css::beans::PropertyValue >& rValues,
+ const css::uno::Reference<
+ css::ucb::XCommandEnvironment >& xEnv );
+
+ bool feedSink( const css::uno::Reference< css::uno::XInterface>& aSink );
+
+ bool exchangeIdentity(const css::uno::Reference< css::ucb::XContentIdentifier >& xNewId);
+
+ void getFileInfo(
+ css::uno::Reference<css::ucb::XCommandEnvironment> const & env, GFileInfo ** info,
+ bool fail);
+
+public:
+ /// @throws css::ucb::ContentCreationException
+ Content( const css::uno::Reference<
+ css::uno::XComponentContext >& rxContext, ContentProvider *pProvider,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier);
+
+ /// @throws css::ucb::ContentCreationException
+ Content( const css::uno::Reference<
+ css::uno::XComponentContext >& rxContext, ContentProvider *pProvider,
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier,
+ bool bIsFolder);
+
+ virtual ~Content() override;
+
+ virtual css::uno::Sequence< css::beans::Property >
+ getProperties( const css::uno::Reference<
+ css::ucb::XCommandEnvironment > & xEnv ) override;
+
+ virtual css::uno::Sequence< css::ucb::CommandInfo >
+ getCommands( const css::uno::Reference<
+ css::ucb::XCommandEnvironment > & xEnv ) override;
+
+ virtual OUString getParentURL() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire()
+ noexcept override;
+ virtual void SAL_CALL release()
+ noexcept override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ virtual OUString SAL_CALL
+ getContentType() override;
+
+ virtual css::uno::Any SAL_CALL
+ execute( const css::ucb::Command& aCommand,
+ sal_Int32 CommandId,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override;
+
+ virtual void SAL_CALL abort( sal_Int32 CommandId ) override;
+
+ virtual css::uno::Sequence< css::ucb::ContentInfo >
+ SAL_CALL queryCreatableContentsInfo() override;
+ virtual css::uno::Reference< css::ucb::XContent >
+ SAL_CALL createNewContent( const css::ucb::ContentInfo& Info ) override;
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< css::ucb::ContentInfo >
+ queryCreatableContentsInfo(
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv);
+
+ GFile* getGFile();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_datasupplier.cxx b/ucb/source/ucp/gio/gio_datasupplier.cxx
new file mode 100644
index 000000000..fd4335dc5
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_datasupplier.cxx
@@ -0,0 +1,256 @@
+/* -*- 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>
+#include <ucbhelper/providerhelper.hxx>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+
+#include "gio_datasupplier.hxx"
+#include "gio_content.hxx"
+
+using namespace gio;
+
+namespace gio
+{
+
+DataSupplier::DataSupplier( const rtl::Reference< ::gio::Content >& rContent, sal_Int32 nOpenMode )
+ : mxContent(rContent), mnOpenMode(nOpenMode), mbCountFinal(false)
+{
+}
+
+bool DataSupplier::getData()
+{
+ if (mbCountFinal)
+ return true;
+
+ GFile *pFile = mxContent->getGFile();
+
+ GFileEnumerator* pEnumerator = g_file_enumerate_children(pFile, "*",
+ G_FILE_QUERY_INFO_NONE, nullptr, nullptr);
+
+ if (!pEnumerator)
+ return false;
+
+ GFileInfo *pInfo = nullptr;
+ while ((pInfo = g_file_enumerator_next_file (pEnumerator, nullptr, nullptr)))
+ {
+ switch ( mnOpenMode )
+ {
+ case css::ucb::OpenMode::FOLDERS:
+ if (g_file_info_get_file_type(pInfo) != G_FILE_TYPE_DIRECTORY)
+ continue;
+ break;
+ case css::ucb::OpenMode::DOCUMENTS:
+ if (g_file_info_get_file_type(pInfo) != G_FILE_TYPE_REGULAR)
+ continue;
+ break;
+ case css::ucb::OpenMode::ALL:
+ default:
+ break;
+ }
+
+ maResults.emplace_back( new ResultListEntry( pInfo ) );
+ g_object_unref(pInfo);
+ }
+
+ mbCountFinal = true;
+
+ g_file_enumerator_close(pEnumerator, nullptr, nullptr);
+ return true;
+}
+
+DataSupplier::~DataSupplier()
+{
+}
+
+OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
+{
+ if ( nIndex < maResults.size() )
+ {
+ OUString aId = maResults[ nIndex ]->aId;
+ if ( aId.getLength() )
+ {
+ // Already cached.
+ return aId;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ GFile *pFile = mxContent->getGFile();
+ char* parent = g_file_get_uri(pFile);
+ OUString aId = OUString::createFromAscii( parent );
+ g_free(parent);
+
+ char *escaped_name =
+ g_uri_escape_string( g_file_info_get_name(maResults[ nIndex ]->pInfo) , nullptr, false);
+
+ if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() )
+ aId += "/";
+
+ aId += OUString::createFromAscii( escaped_name );
+
+ g_free( escaped_name );
+
+ maResults[ nIndex ]->aId = aId;
+ return aId;
+ }
+
+ return OUString();
+}
+
+css::uno::Reference< css::ucb::XContentIdentifier > DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
+{
+ if ( nIndex < maResults.size() )
+ {
+ css::uno::Reference< css::ucb::XContentIdentifier > xId = maResults[ nIndex ]->xId;
+ if ( xId.is() )
+ {
+ // Already cached.
+ return xId;
+ }
+ }
+
+ OUString aId = queryContentIdentifierString( nIndex );
+ if ( aId.getLength() )
+ {
+ css::uno::Reference< css::ucb::XContentIdentifier > xId = new ucbhelper::ContentIdentifier( aId );
+ maResults[ nIndex ]->xId = xId;
+ return xId;
+ }
+
+ return css::uno::Reference< css::ucb::XContentIdentifier >();
+}
+
+css::uno::Reference< css::ucb::XContent > DataSupplier::queryContent( sal_uInt32 nIndex )
+{
+ if ( nIndex < maResults.size() )
+ {
+ css::uno::Reference< css::ucb::XContent > xContent = maResults[ nIndex ]->xContent;
+ if ( xContent.is() )
+ {
+ // Already cached.
+ return xContent;
+ }
+ }
+
+ css::uno::Reference< css::ucb::XContentIdentifier > xId = queryContentIdentifier( nIndex );
+ if ( xId.is() )
+ {
+ try
+ {
+ css::uno::Reference< css::ucb::XContent > xContent = mxContent->getProvider()->queryContent( xId );
+ maResults[ nIndex ]->xContent = xContent;
+ return xContent;
+ }
+ catch ( css::ucb::IllegalIdentifierException& )
+ {
+ }
+ }
+ return css::uno::Reference< css::ucb::XContent >();
+}
+
+bool DataSupplier::getResult( sal_uInt32 nIndex )
+{
+ if ( maResults.size() > nIndex ) // Result already present.
+ return true;
+
+ if ( getData() && maResults.size() > nIndex )
+ return true;
+
+ return false;
+}
+
+sal_uInt32 DataSupplier::totalCount()
+{
+ getData();
+ return maResults.size();
+}
+
+sal_uInt32 DataSupplier::currentCount()
+{
+ return maResults.size();
+}
+
+bool DataSupplier::isCountFinal()
+{
+ return mbCountFinal;
+}
+
+css::uno::Reference< css::sdbc::XRow > DataSupplier::queryPropertyValues( sal_uInt32 nIndex )
+{
+ if ( nIndex < maResults.size() )
+ {
+ css::uno::Reference< css::sdbc::XRow > xRow = maResults[ nIndex ]->xRow;
+ if ( xRow.is() )
+ {
+ // Already cached.
+ return xRow;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ css::uno::Reference< css::ucb::XContent > xContent( queryContent( nIndex ) );
+ if ( xContent.is() )
+ {
+ try
+ {
+ css::uno::Reference< css::ucb::XCommandProcessor > xCmdProc(
+ xContent, css::uno::UNO_QUERY_THROW );
+ sal_Int32 nCmdId( xCmdProc->createCommandIdentifier() );
+ css::ucb::Command aCmd;
+ aCmd.Name = "getPropertyValues";
+ aCmd.Handle = -1;
+ aCmd.Argument <<= getResultSet()->getProperties();
+ css::uno::Any aResult( xCmdProc->execute(
+ aCmd, nCmdId, getResultSet()->getEnvironment() ) );
+ css::uno::Reference< css::sdbc::XRow > xRow;
+ if ( aResult >>= xRow )
+ {
+ maResults[ nIndex ]->xRow = xRow;
+ return xRow;
+ }
+ }
+ catch ( css::uno::Exception const & )
+ {
+ }
+ }
+ }
+ return css::uno::Reference< css::sdbc::XRow >();
+}
+
+void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
+{
+ if ( nIndex < maResults.size() )
+ maResults[ nIndex ]->xRow.clear();
+}
+
+void DataSupplier::close()
+{
+}
+
+void DataSupplier::validate()
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_datasupplier.hxx b/ucb/source/ucp/gio/gio_datasupplier.hxx
new file mode 100644
index 000000000..4a0e0b36e
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_datasupplier.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ucbhelper/resultset.hxx>
+#include "gio_content.hxx"
+#include <memory>
+#include <vector>
+
+namespace gio
+{
+
+class Content;
+
+struct ResultListEntry
+{
+ OUString aId;
+ css::uno::Reference< css::ucb::XContentIdentifier > xId;
+ css::uno::Reference< css::ucb::XContent > xContent;
+ css::uno::Reference< css::sdbc::XRow > xRow;
+ GFileInfo *pInfo;
+
+ explicit ResultListEntry( GFileInfo *pInInfo ) : pInfo(pInInfo)
+ {
+ g_object_ref( pInfo );
+ }
+
+ ~ResultListEntry()
+ {
+ g_object_unref( pInfo );
+ }
+};
+
+typedef std::vector< std::unique_ptr<ResultListEntry> > ResultList;
+
+class DataSupplier : public ucbhelper::ResultSetDataSupplier
+{
+private:
+ rtl::Reference< ::gio::Content > mxContent;
+ sal_Int32 mnOpenMode;
+ bool mbCountFinal;
+ bool getData();
+ ResultList maResults;
+public:
+ DataSupplier( const rtl::Reference< Content >& rContent, sal_Int32 nOpenMode );
+ virtual ~DataSupplier() override;
+
+ virtual OUString queryContentIdentifierString( sal_uInt32 nIndex ) override;
+ virtual css::uno::Reference< css::ucb::XContentIdentifier >
+ queryContentIdentifier( sal_uInt32 nIndex ) override;
+ virtual css::uno::Reference< css::ucb::XContent >
+ queryContent( sal_uInt32 nIndex ) override;
+
+ virtual bool getResult( sal_uInt32 nIndex ) override;
+
+ virtual sal_uInt32 totalCount() override;
+ virtual sal_uInt32 currentCount() override;
+ virtual bool isCountFinal() override;
+
+ virtual css::uno::Reference< css::sdbc::XRow >
+ queryPropertyValues( sal_uInt32 nIndex ) override;
+ virtual void releasePropertyValues( sal_uInt32 nIndex ) override;
+
+ virtual void close() override;
+
+ virtual void validate() override;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_inputstream.cxx b/ucb/source/ucp/gio/gio_inputstream.cxx
new file mode 100644
index 000000000..c6df4572b
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_inputstream.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 <sal/config.h>
+
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+
+#include "gio_inputstream.hxx"
+#include "gio_content.hxx"
+
+namespace gio
+{
+
+InputStream::InputStream(GFileInputStream *pStream): mpStream(pStream)
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+}
+
+InputStream::~InputStream()
+{
+ closeInput();
+}
+
+sal_Int32 SAL_CALL InputStream::available()
+{
+ return 0;
+}
+
+void SAL_CALL InputStream::closeInput()
+{
+ if (mpStream)
+ g_input_stream_close(G_INPUT_STREAM(mpStream), nullptr, nullptr);
+}
+
+void SAL_CALL InputStream::skipBytes( sal_Int32 nBytesToSkip )
+{
+ // Conservatively call readBytes and discard the read data, but given this
+ // InputStream will always be wrapped in comphelper::OSeekableInputWrapper,
+ // this function will never be called anyway:
+ css::uno::Sequence<sal_Int8> data;
+ readBytes(data, nBytesToSkip);
+}
+
+sal_Int32 SAL_CALL InputStream::readBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ try
+ {
+ aData.realloc( nBytesToRead );
+ }
+ catch ( const css::uno::Exception & )
+ {
+ throw css::io::BufferSizeExceededException();
+ }
+
+ gsize nBytesRead = 0;
+ GError *pError=nullptr;
+ if (!g_input_stream_read_all(G_INPUT_STREAM(mpStream), aData.getArray(), nBytesToRead, &nBytesRead, nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+ aData.realloc(nBytesRead);
+ return nBytesRead;
+}
+
+sal_Int32 SAL_CALL InputStream::readSomeBytes( css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
+{
+ return readBytes(aData, nMaxBytesToRead);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_inputstream.hxx b/ucb/source/ucp/gio/gio_inputstream.hxx
new file mode 100644
index 000000000..9608bc5b3
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_inputstream.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+
+#include <gio/gio.h>
+
+namespace gio
+{
+
+class InputStream final : public cppu::WeakImplHelper<css::io::XInputStream>
+{
+private:
+ GFileInputStream *mpStream;
+
+public:
+ explicit InputStream ( GFileInputStream *pStream );
+ virtual ~InputStream() override;
+
+ // XInputStream
+ virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence< sal_Int8 > & aData,
+ sal_Int32 nBytesToRead ) override;
+
+ virtual sal_Int32 SAL_CALL readSomeBytes( css::uno::Sequence< sal_Int8 > & aData,
+ sal_Int32 nMaxBytesToRead ) override;
+
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+
+ virtual sal_Int32 SAL_CALL available() override;
+
+ virtual void SAL_CALL closeInput() override;
+};
+
+} // namespace gio
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_mount.cxx b/ucb/source/ucp/gio/gio_mount.cxx
new file mode 100644
index 000000000..1d2dbcea8
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_mount.cxx
@@ -0,0 +1,211 @@
+/* -*- 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 <utility>
+
+#include "gio_mount.hxx"
+#include <ucbhelper/simpleauthenticationrequest.hxx>
+#include <string.h>
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#if defined __clang__
+#if __has_warning("-Wdeprecated-volatile")
+#pragma clang diagnostic ignored "-Wdeprecated-volatile"
+#endif
+#endif
+#endif
+G_DEFINE_TYPE (OOoMountOperation, ooo_mount_operation, G_TYPE_MOUNT_OPERATION);
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static void ooo_mount_operation_ask_password (GMountOperation *op,
+ const char *message, const char *default_user, const char *default_domain,
+ GAskPasswordFlags flags);
+
+static void ooo_mount_operation_init (OOoMountOperation *op)
+{
+ op->m_pPrevPassword = nullptr;
+ op->m_pPrevUsername = nullptr;
+}
+
+static void ooo_mount_operation_finalize (GObject *object)
+{
+ OOoMountOperation *mount_op = OOO_MOUNT_OPERATION (object);
+ if (mount_op->m_pPrevUsername)
+ free(mount_op->m_pPrevUsername);
+ if (mount_op->m_pPrevPassword)
+ free(mount_op->m_pPrevPassword);
+ mount_op->context.reset();
+
+ G_OBJECT_CLASS (ooo_mount_operation_parent_class)->finalize (object);
+}
+
+static void ooo_mount_operation_class_init (OOoMountOperationClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = ooo_mount_operation_finalize;
+
+ GMountOperationClass *mount_op_class = G_MOUNT_OPERATION_CLASS (klass);
+ mount_op_class->ask_password = ooo_mount_operation_ask_password;
+}
+
+namespace {
+
+// Temporarily undo the g_main_context_push_thread_default done in the surrounding MountOperation
+// ctor (in ucb/source/ucp/gio/gio_content.cxx):
+struct GlibThreadDefaultMainContextScope {
+public:
+ GlibThreadDefaultMainContextScope(GMainContext * context): context_(context)
+ { g_main_context_push_thread_default(context_); }
+
+ ~GlibThreadDefaultMainContextScope() { g_main_context_pop_thread_default(context_); }
+
+private:
+ GMainContext * context_;
+};
+
+}
+
+static void ooo_mount_operation_ask_password (GMountOperation *op,
+ const char * /*message*/, const char *default_user,
+ const char *default_domain, GAskPasswordFlags flags)
+{
+ css::uno::Reference< css::task::XInteractionHandler > xIH;
+
+ OOoMountOperation *pThis = reinterpret_cast<OOoMountOperation*>(op);
+ GlibThreadDefaultMainContextScope scope(pThis->context.get());
+
+ const css::uno::Reference< css::ucb::XCommandEnvironment > &xEnv = *(pThis->pEnv);
+
+ if (xEnv.is())
+ xIH = xEnv->getInteractionHandler();
+
+ if (!xIH.is())
+ {
+ g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
+ return;
+ }
+
+ OUString aDomain, aUserName, aPassword;
+
+ if (default_user)
+ aUserName = OUString(default_user, strlen(default_user), RTL_TEXTENCODING_UTF8);
+
+ ucbhelper::SimpleAuthenticationRequest::EntityType eUserName =
+ (flags & G_ASK_PASSWORD_NEED_USERNAME)
+ ? ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
+ : aUserName.isEmpty() ? ucbhelper::SimpleAuthenticationRequest::ENTITY_NA
+ : ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED;
+
+ ucbhelper::SimpleAuthenticationRequest::EntityType ePassword =
+ (flags & G_ASK_PASSWORD_NEED_PASSWORD)
+ ? ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
+ : ucbhelper::SimpleAuthenticationRequest::ENTITY_NA;
+
+ OUString aPrevPassword, aPrevUsername;
+ if (pThis->m_pPrevUsername)
+ aPrevUsername = OUString(pThis->m_pPrevUsername, strlen(pThis->m_pPrevUsername), RTL_TEXTENCODING_UTF8);
+ if (pThis->m_pPrevPassword)
+ aPrevPassword = OUString(pThis->m_pPrevPassword, strlen(pThis->m_pPrevPassword), RTL_TEXTENCODING_UTF8);
+
+ //The damn dialog is stupidly broken, so do like webdav, i.e. "#102871#"
+ if ( aUserName.isEmpty() )
+ aUserName = aPrevUsername;
+
+ if ( aPassword.isEmpty() )
+ aPassword = aPrevPassword;
+
+ ucbhelper::SimpleAuthenticationRequest::EntityType eDomain =
+ (flags & G_ASK_PASSWORD_NEED_DOMAIN)
+ ? ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY
+ : ucbhelper::SimpleAuthenticationRequest::ENTITY_NA;
+
+ if (default_domain)
+ aDomain = OUString(default_domain, strlen(default_domain), RTL_TEXTENCODING_UTF8);
+
+ rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest
+ = new ucbhelper::SimpleAuthenticationRequest (OUString() /* FIXME: provide URL here */, OUString(), eDomain, aDomain, eUserName, aUserName, ePassword, aPassword);
+
+ xIH->handle( xRequest );
+
+ rtl::Reference< ucbhelper::InteractionContinuation > xSelection = xRequest->getSelection();
+
+ if ( !xSelection.is() )
+ {
+ g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
+ return;
+ }
+
+ css::uno::Reference< css::task::XInteractionAbort > xAbort(xSelection.get(), css::uno::UNO_QUERY );
+ if ( xAbort.is() )
+ {
+ g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED);
+ return;
+ }
+
+ const rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp = xRequest->getAuthenticationSupplier();
+ aUserName = xSupp->getUserName();
+ aPassword = xSupp->getPassword();
+
+ if (flags & G_ASK_PASSWORD_NEED_USERNAME)
+ g_mount_operation_set_username(op, OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8).getStr());
+
+ if (flags & G_ASK_PASSWORD_NEED_PASSWORD)
+ g_mount_operation_set_password(op, OUStringToOString(aPassword, RTL_TEXTENCODING_UTF8).getStr());
+
+ if (flags & G_ASK_PASSWORD_NEED_DOMAIN)
+ g_mount_operation_set_domain(op, OUStringToOString(xSupp->getRealm(), RTL_TEXTENCODING_UTF8).getStr());
+
+ switch (xSupp->getRememberPasswordMode())
+ {
+ default:
+ case css::ucb::RememberAuthentication_NO:
+ g_mount_operation_set_password_save(op, G_PASSWORD_SAVE_NEVER);
+ break;
+ case css::ucb::RememberAuthentication_SESSION:
+ g_mount_operation_set_password_save(op, G_PASSWORD_SAVE_FOR_SESSION);
+ break;
+ case css::ucb::RememberAuthentication_PERSISTENT:
+ g_mount_operation_set_password_save(op, G_PASSWORD_SAVE_PERMANENTLY);
+ break;
+ }
+
+ if (pThis->m_pPrevPassword)
+ free(pThis->m_pPrevPassword);
+ pThis->m_pPrevPassword = strdup(OUStringToOString(aPassword, RTL_TEXTENCODING_UTF8).getStr());
+ if (pThis->m_pPrevUsername)
+ free(pThis->m_pPrevUsername);
+ pThis->m_pPrevUsername = strdup(OUStringToOString(aUserName, RTL_TEXTENCODING_UTF8).getStr());
+ g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED);
+}
+
+GMountOperation *ooo_mount_operation_new(ucb::ucp::gio::glib::MainContextRef && context, const css::uno::Reference< css::ucb::XCommandEnvironment >& rEnv)
+{
+ OOoMountOperation *pRet = static_cast<OOoMountOperation*>(g_object_new (OOO_TYPE_MOUNT_OPERATION, nullptr));
+ pRet->context = std::move(context);
+ pRet->pEnv = &rEnv;
+ return &pRet->parent_instance;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_mount.hxx b/ucb/source/ucp/gio/gio_mount.hxx
new file mode 100644
index 000000000..2ddcaebf5
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_mount.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <memory>
+
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define OOO_TYPE_MOUNT_OPERATION (ooo_mount_operation_get_type ())
+#define OOO_MOUNT_OPERATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OOO_TYPE_MOUNT_OPERATION, OOoMountOperation))
+#define OOO_MOUNT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OOO_TYPE_MOUNT_OPERATION, OOoMountOperationClass))
+#define OOO_IS_MOUNT_OPERATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OOO_TYPE_MOUNT_OPERATION))
+#define OOO_IS_MOUNT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OOO_TYPE_MOUNT_OPERATION))
+#define OOO_MOUNT_OPERATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OOO_TYPE_MOUNT_OPERATION, OOoMountOperationClass))
+
+namespace ucb::ucp::gio::glib {
+
+namespace detail {
+
+struct MainContextUnref {
+ void operator ()(GMainContext * context) {
+ if (context != nullptr) {
+ g_main_context_unref(context);
+ }
+ }
+};
+
+}
+
+using MainContextRef = std::unique_ptr<GMainContext, detail::MainContextUnref>;
+
+}
+
+struct OOoMountOperation
+{
+ GMountOperation parent_instance;
+
+ ucb::ucp::gio::glib::MainContextRef context;
+ const css::uno::Reference< css::ucb::XCommandEnvironment > *pEnv;
+ char *m_pPrevUsername;
+ char *m_pPrevPassword;
+
+private:
+ // Managed via ooo_mount_operation_new and ooo_mount_operation_finalize:
+ OOoMountOperation() = delete;
+ ~OOoMountOperation() = delete;
+};
+
+struct OOoMountOperationClass
+{
+ GMountOperationClass parent_class;
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+};
+
+
+GType ooo_mount_operation_get_type();
+GMountOperation *ooo_mount_operation_new(ucb::ucp::gio::glib::MainContextRef && context, const css::uno::Reference< css::ucb::XCommandEnvironment >& rEnv);
+
+G_END_DECLS
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_outputstream.cxx b/ucb/source/ucp/gio/gio_outputstream.cxx
new file mode 100644
index 000000000..1f334f4df
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_outputstream.cxx
@@ -0,0 +1,78 @@
+/* -*- 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/io/NotConnectedException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+
+#include "gio_outputstream.hxx"
+#include "gio_content.hxx"
+
+namespace gio
+{
+
+OutputStream::OutputStream(GFileOutputStream *pStream) : Seekable(G_SEEKABLE(pStream)), mpStream(pStream)
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+}
+
+OutputStream::~OutputStream()
+{
+ closeOutput();
+}
+
+void SAL_CALL OutputStream::writeBytes( const css::uno::Sequence< sal_Int8 >& rData )
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ GError *pError=nullptr;
+ if (!g_output_stream_write_all(G_OUTPUT_STREAM(mpStream), rData.getConstArray(), rData.getLength(), nullptr, nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+}
+
+void SAL_CALL OutputStream::flush()
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ GError *pError=nullptr;
+ if (!g_output_stream_flush(G_OUTPUT_STREAM(mpStream), nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+}
+
+void SAL_CALL OutputStream::closeOutput()
+{
+ if (mpStream)
+ g_output_stream_close(G_OUTPUT_STREAM(mpStream), nullptr, nullptr);
+}
+
+css::uno::Any OutputStream::queryInterface( const css::uno::Type &type )
+{
+ css::uno::Any aRet = ::cppu::queryInterface ( type,
+ static_cast< XOutputStream * >( this ) );
+
+ return aRet.hasValue() ? aRet : Seekable::queryInterface( type );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_outputstream.hxx b/ucb/source/ucp/gio/gio_outputstream.hxx
new file mode 100644
index 000000000..40bdbcfc4
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_outputstream.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/weak.hxx>
+
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+#include "gio_seekable.hxx"
+
+namespace gio
+{
+
+class OutputStream final :
+ public css::io::XOutputStream,
+ public Seekable
+{
+private:
+ GFileOutputStream *mpStream;
+
+public:
+ explicit OutputStream ( GFileOutputStream *pStream );
+ virtual ~OutputStream() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type & type ) override;
+ virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OWeakObject::release(); }
+
+ // XOutputStream
+ virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override;
+
+ virtual void SAL_CALL flush() override;
+
+
+ virtual void SAL_CALL closeOutput() override;
+};
+
+} // namespace gio
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_provider.cxx b/ucb/source/ucp/gio/gio_provider.cxx
new file mode 100644
index 000000000..b6dd31fbb
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_provider.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 <sal/log.hxx>
+#include <ucbhelper/contenthelper.hxx>
+#include <ucbhelper/macros.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+#include "gio_provider.hxx"
+#include "gio_content.hxx"
+
+namespace gio
+{
+css::uno::Reference< css::ucb::XContent > SAL_CALL
+ContentProvider::queryContent(
+ const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier )
+{
+ SAL_INFO("ucb.ucp.gio", "QueryContent: " << Identifier->getContentIdentifier());
+ osl::MutexGuard aGuard( m_aMutex );
+
+ // Check, if a content with given id already exists...
+ css::uno::Reference< css::ucb::XContent > xContent = queryExistingContent( Identifier );
+ if ( xContent.is() )
+ return xContent;
+
+ try
+ {
+ xContent = new ::gio::Content(m_xContext, this, Identifier);
+ }
+ catch ( css::ucb::ContentCreationException const & )
+ {
+ throw css::ucb::IllegalIdentifierException();
+ }
+
+ if ( !xContent->getIdentifier().is() )
+ throw css::ucb::IllegalIdentifierException();
+
+ return xContent;
+}
+
+ContentProvider::ContentProvider(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext )
+: ::ucbhelper::ContentProviderImplHelper( rxContext )
+{
+}
+
+ContentProvider::~ContentProvider()
+{
+}
+
+// XInterface
+void SAL_CALL ContentProvider::acquire()
+ noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ContentProvider::release()
+ noexcept
+{
+ OWeakObject::release();
+}
+
+css::uno::Any SAL_CALL ContentProvider::queryInterface( const css::uno::Type & rType )
+{
+ css::uno::Any aRet = cppu::queryInterface( rType,
+ static_cast< css::lang::XTypeProvider* >(this),
+ static_cast< css::lang::XServiceInfo* >(this),
+ static_cast< css::ucb::XContentProvider* >(this)
+ );
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
+}
+
+XTYPEPROVIDER_IMPL_3( ContentProvider,
+ css::lang::XTypeProvider,
+ css::lang::XServiceInfo,
+ css::ucb::XContentProvider );
+
+css::uno::Sequence< OUString > SAL_CALL ContentProvider::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.GIOContentProvider" };
+}
+
+OUString SAL_CALL ContentProvider::getImplementationName()
+{
+ return "com.sun.star.comp.GIOContentProvider";
+}
+
+sal_Bool SAL_CALL ContentProvider::supportsService(const OUString& aServiceName)
+{
+ return cppu::supportsService(this, aServiceName);
+}
+
+
+}
+
+// gio creates threads we don't want in online's forkit
+static bool isDisabled()
+{
+ const char *pDisable = getenv("UNODISABLELIBRARY");
+ if (!pDisable)
+ return false;
+ OString aDisable(pDisable, strlen(pDisable));
+ return aDisable.indexOf("ucpgio1") >= 0;
+}
+
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ucb_gio_ContentProvider_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ if (isDisabled())
+ return nullptr;
+#if !GLIB_CHECK_VERSION(2,36,0)
+ g_type_init();
+#endif
+ return cppu::acquire(new gio::ContentProvider(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_provider.hxx b/ucb/source/ucp/gio/gio_provider.hxx
new file mode 100644
index 000000000..f90d09805
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_provider.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ucbhelper/providerhelper.hxx>
+
+namespace gio
+{
+class ContentProvider : public ::ucbhelper::ContentProviderImplHelper
+{
+public:
+ explicit ContentProvider(const css::uno::Reference<css::uno::XComponentContext>& rxContext);
+ virtual ~ContentProvider() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& rType) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XContentProvider
+ virtual css::uno::Reference<css::ucb::XContent> SAL_CALL
+ queryContent(const css::uno::Reference<css::ucb::XContentIdentifier>& Identifier) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_resultset.cxx b/ucb/source/ucp/gio/gio_resultset.cxx
new file mode 100644
index 000000000..ee836bd0e
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_resultset.cxx
@@ -0,0 +1,53 @@
+/* -*- 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 "gio_datasupplier.hxx"
+#include "gio_resultset.hxx"
+
+using namespace com::sun::star::lang;
+using namespace com::sun::star::ucb;
+using namespace com::sun::star::uno;
+
+using namespace gio;
+
+DynamicResultSet::DynamicResultSet(
+ const Reference< XComponentContext >& rxContext,
+ const rtl::Reference< Content >& rxContent,
+ const OpenCommandArgument2& rCommand,
+ const Reference< XCommandEnvironment >& rxEnv )
+ : ResultSetImplHelper( rxContext, rCommand ),
+ m_xContent( rxContent ),
+ m_xEnv( rxEnv )
+{
+}
+
+void DynamicResultSet::initStatic()
+{
+ m_xResultSet1 = new ::ucbhelper::ResultSet(
+ m_xContext, m_aCommand.Properties,
+ new DataSupplier( m_xContent, m_aCommand.Mode ), m_xEnv );
+}
+
+void DynamicResultSet::initDynamic()
+{
+ initStatic();
+ m_xResultSet2 = m_xResultSet1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_resultset.hxx b/ucb/source/ucp/gio/gio_resultset.hxx
new file mode 100644
index 000000000..f5ea95e14
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_resultset.hxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ucbhelper/resultsethelper.hxx>
+#include "gio_content.hxx"
+
+namespace gio
+{
+
+ class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper
+ {
+ rtl::Reference< Content > m_xContent;
+ css::uno::Reference< css::ucb::XCommandEnvironment > m_xEnv;
+
+ private:
+ virtual void initStatic() override;
+ virtual void initDynamic() override;
+
+ public:
+ DynamicResultSet(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const rtl::Reference< Content >& rxContent,
+ const css::ucb::OpenCommandArgument2& rCommand,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& rxEnv );
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_seekable.cxx b/ucb/source/ucp/gio/gio_seekable.cxx
new file mode 100644
index 000000000..1f1da5948
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_seekable.cxx
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+
+#include "gio_seekable.hxx"
+#include "gio_content.hxx"
+
+namespace gio
+{
+
+Seekable::Seekable(GSeekable *pStream) : mpStream(pStream)
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+}
+
+Seekable::~Seekable()
+{
+}
+
+void SAL_CALL Seekable::truncate()
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ if (!g_seekable_can_truncate(mpStream))
+ throw css::io::IOException("Truncate unsupported",
+ static_cast< cppu::OWeakObject * >(this));
+
+ GError *pError=nullptr;
+ if (!g_seekable_truncate(mpStream, 0, nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+}
+
+void SAL_CALL Seekable::seek( sal_Int64 location )
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ if (!g_seekable_can_seek(mpStream))
+ throw css::io::IOException("Seek unsupported",
+ static_cast< cppu::OWeakObject * >(this));
+
+ GError *pError=nullptr;
+ if (!g_seekable_seek(mpStream, location, G_SEEK_SET, nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+}
+
+sal_Int64 SAL_CALL Seekable::getPosition()
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ return g_seekable_tell(mpStream);
+}
+
+sal_Int64 SAL_CALL Seekable::getLength()
+{
+ if (!mpStream)
+ throw css::io::NotConnectedException();
+
+ bool bOk = false;
+ sal_uInt64 nSize = 0;
+
+ GFileInfo* pInfo = G_IS_FILE_INPUT_STREAM(mpStream)
+ ? g_file_input_stream_query_info(G_FILE_INPUT_STREAM(mpStream), G_FILE_ATTRIBUTE_STANDARD_SIZE, nullptr, nullptr)
+ : g_file_output_stream_query_info(G_FILE_OUTPUT_STREAM(mpStream), G_FILE_ATTRIBUTE_STANDARD_SIZE, nullptr, nullptr);
+
+ if (pInfo)
+ {
+ if (g_file_info_has_attribute(pInfo, G_FILE_ATTRIBUTE_STANDARD_SIZE))
+ {
+ nSize = g_file_info_get_size(pInfo);
+ bOk = true;
+ }
+ g_object_unref(pInfo);
+ }
+
+ if (!bOk)
+ {
+ GError *pError=nullptr;
+ sal_Int64 nCurr = getPosition();
+ if (!g_seekable_seek(mpStream, 0, G_SEEK_END, nullptr, &pError))
+ convertToIOException(pError, static_cast< cppu::OWeakObject * >(this));
+ nSize = getPosition();
+ seek(nCurr);
+ }
+
+ return nSize;
+}
+
+css::uno::Any Seekable::queryInterface( const css::uno::Type &type )
+{
+ css::uno::Any aRet = ::cppu::queryInterface ( type,
+ static_cast< XSeekable * >( this ) );
+
+ if (!aRet.hasValue() && g_seekable_can_truncate(mpStream))
+ aRet = ::cppu::queryInterface ( type, static_cast< XTruncate * >( this ) );
+
+ return aRet.hasValue() ? aRet : OWeakObject::queryInterface( type );
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/gio_seekable.hxx b/ucb/source/ucp/gio/gio_seekable.hxx
new file mode 100644
index 000000000..9bf284b89
--- /dev/null
+++ b/ucb/source/ucp/gio/gio_seekable.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <cppuhelper/weak.hxx>
+
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+
+#include <gio/gio.h>
+
+namespace gio
+{
+class Seekable : public css::io::XTruncate, public css::io::XSeekable, public ::cppu::OWeakObject
+{
+private:
+ GSeekable* mpStream;
+
+public:
+ explicit Seekable(GSeekable* pStream);
+ virtual ~Seekable() override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& type) override;
+ virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OWeakObject::release(); }
+
+ // XSeekable
+ virtual void SAL_CALL seek(sal_Int64 location) override;
+
+ virtual sal_Int64 SAL_CALL getPosition() override;
+
+ virtual sal_Int64 SAL_CALL getLength() override;
+
+ // XTruncate
+ virtual void SAL_CALL truncate() override;
+};
+
+} // namespace gio
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/gio/ucpgio.component b/ucb/source/ucp/gio/ucpgio.component
new file mode 100644
index 000000000..7d128067a
--- /dev/null
+++ b/ucb/source/ucp/gio/ucpgio.component
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.GIOContentProvider"
+ constructor="ucb_gio_ContentProvider_get_implementation" single-instance="true">
+ <service name="com.sun.star.ucb.GIOContentProvider"/>
+ </implementation>
+</component>