diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /ucb/source/ucp/file | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ucb/source/ucp/file')
31 files changed, 10245 insertions, 0 deletions
diff --git a/ucb/source/ucp/file/bc.cxx b/ucb/source/ucp/file/bc.cxx new file mode 100644 index 0000000000..8d66f26fa8 --- /dev/null +++ b/ucb/source/ucp/file/bc.cxx @@ -0,0 +1,1170 @@ +/* -*- 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 <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ref.hxx> + +#include <comphelper/diagnose_ex.hxx> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <comphelper/fileurl.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <utility> +#include "filglob.hxx" +#include "filid.hxx" +#include "filrow.hxx" +#include "bc.hxx" +#include "prov.hxx" +#include "filerror.hxx" +#include "filinsreq.hxx" + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +class fileaccess::PropertyListeners +{ + typedef comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener> ContainerHelper; + std::unordered_map<OUString, ContainerHelper> m_aMap; + +public: + void disposeAndClear(std::unique_lock<std::mutex>& rGuard, const lang::EventObject& rEvt) + { + // create a copy, because do not fire event in a guarded section + std::unordered_map<OUString, ContainerHelper> tempMap = std::move(m_aMap); + for (auto& rPair : tempMap) + rPair.second.disposeAndClear(rGuard, rEvt); + } + void addInterface(std::unique_lock<std::mutex>& rGuard, const OUString& rKey, const uno::Reference<beans::XPropertiesChangeListener>& rListener) + { + m_aMap[rKey].addInterface(rGuard, rListener); + } + void removeInterface(std::unique_lock<std::mutex>& rGuard, const OUString& rKey, const uno::Reference<beans::XPropertiesChangeListener>& rListener) + { + // search container with id rKey + auto iter = m_aMap.find(rKey); + // container found? + if (iter != m_aMap.end()) + iter->second.removeInterface(rGuard, rListener); + } + std::vector< OUString > getContainedTypes(std::unique_lock<std::mutex>& rGuard) const + { + std::vector<OUString> aInterfaceTypes; + aInterfaceTypes.reserve(m_aMap.size()); + for (const auto& rPair : m_aMap) + // are interfaces added to this container? + if (rPair.second.getLength(rGuard)) + // yes, put the type in the array + aInterfaceTypes.push_back(rPair.first); + return aInterfaceTypes; + } + comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener>* getContainer(std::unique_lock<std::mutex>& , const OUString& rKey) + { + auto iter = m_aMap.find(rKey); + if (iter != m_aMap.end()) + return &iter->second; + return nullptr; + } +}; + + +/****************************************************************************************/ +/* */ +/* BaseContent */ +/* */ +/****************************************************************************************/ + + +// Private Constructor for just inserted Contents + +BaseContent::BaseContent( TaskManager* pMyShell, + OUString parentName, + bool bFolder ) + : m_pMyShell( pMyShell ), + m_aUncPath(std::move( parentName )), + m_bFolder( bFolder ), + m_nState( JustInserted ) +{ + m_pMyShell->m_pProvider->acquire(); + // No registering, since we have no name +} + + +// Constructor for full featured Contents + +BaseContent::BaseContent( TaskManager* pMyShell, + const Reference< XContentIdentifier >& xContentIdentifier, + OUString aUncPath ) + : m_pMyShell( pMyShell ), + m_xContentIdentifier( xContentIdentifier ), + m_aUncPath(std::move( aUncPath )), + m_bFolder( false ), + m_nState( FullFeatured ) +{ + m_pMyShell->m_pProvider->acquire(); + m_pMyShell->registerNotifier( m_aUncPath,this ); + m_pMyShell->insertDefaultProperties( m_aUncPath ); +} + + +BaseContent::~BaseContent( ) +{ + if( ( m_nState & FullFeatured ) || ( m_nState & Deleted ) ) + { + m_pMyShell->deregisterNotifier( m_aUncPath,this ); + } + m_pMyShell->m_pProvider->release(); +} + + +// XComponent + + +void SAL_CALL +BaseContent::addEventListener( const Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +void SAL_CALL +BaseContent::removeEventListener( const Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +void SAL_CALL +BaseContent::dispose() +{ + lang::EventObject aEvt; + aEvt.Source = static_cast< XContent* >( this ); + + std::unique_lock aGuard( m_aMutex ); + + std::unique_ptr<PropertyListeners> pPropertyListener = std::move(m_pPropertyListener); + + m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + m_aContentEventListeners.disposeAndClear( aGuard, aEvt ); + + if( pPropertyListener ) + pPropertyListener->disposeAndClear( aGuard, aEvt ); + + m_aPropertySetInfoChangeListeners.disposeAndClear( aGuard, aEvt ); +} + +// XServiceInfo +OUString SAL_CALL +BaseContent::getImplementationName() +{ + return "com.sun.star.comp.ucb.FileContent"; +} + +sal_Bool SAL_CALL +BaseContent::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +Sequence< OUString > SAL_CALL +BaseContent::getSupportedServiceNames() +{ + Sequence<OUString> ret { "com.sun.star.ucb.FileContent" }; + return ret; +} + +// XCommandProcessor + + +sal_Int32 SAL_CALL +BaseContent::createCommandIdentifier() +{ + return m_pMyShell->getCommandId(); +} + + +void SAL_CALL +BaseContent::abort( sal_Int32 /*CommandId*/ ) +{ +} + + +Any SAL_CALL +BaseContent::execute( const Command& aCommand, + sal_Int32 CommandId, + const Reference< XCommandEnvironment >& Environment ) +{ + if( ! CommandId ) + // A Command with commandid zero cannot be aborted + CommandId = createCommandIdentifier(); + + m_pMyShell->startTask( CommandId, + Environment ); + + Any aAny; + + if (aCommand.Name == "getPropertySetInfo") // No exceptions + { + aAny <<= getPropertySetInfo(); + } + else if (aCommand.Name == "getCommandInfo") // no exceptions + { + aAny <<= getCommandInfo(); + } + else if ( aCommand.Name == "setPropertyValues" ) + { + Sequence< beans::PropertyValue > sPropertyValues; + + if( ! ( aCommand.Argument >>= sPropertyValues ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT ); + else + aAny <<= setPropertyValues( CommandId,sPropertyValues ); // calls endTask by itself + } + else if ( aCommand.Name == "getPropertyValues" ) + { + Sequence< beans::Property > ListOfRequestedProperties; + + if( ! ( aCommand.Argument >>= ListOfRequestedProperties ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT ); + else + aAny <<= getPropertyValues( CommandId, + ListOfRequestedProperties ); + } + else if ( aCommand.Name == "open" ) + { + OpenCommandArgument2 aOpenArgument; + if( ! ( aCommand.Argument >>= aOpenArgument ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_OPEN_ARGUMENT ); + else + { + Reference< XDynamicResultSet > result = open( CommandId,aOpenArgument ); + if( result.is() ) + aAny <<= result; + } + } + else if ( aCommand.Name == "delete" ) + { + if( ! aCommand.Argument.has< bool >() ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_DELETE_ARGUMENT ); + else + deleteContent( CommandId ); + } + else if ( aCommand.Name == "transfer" ) + { + TransferInfo aTransferInfo; + if( ! ( aCommand.Argument >>= aTransferInfo ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_TRANSFER_ARGUMENT ); + else + transfer( CommandId, aTransferInfo ); + } + else if ( aCommand.Name == "insert" ) + { + InsertCommandArgument aInsertArgument; + if( ! ( aCommand.Argument >>= aInsertArgument ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_INSERT_ARGUMENT ); + else + insert( CommandId,aInsertArgument ); + } + else if ( aCommand.Name == "getCasePreservingURL" ) + { + Reference< sdbc::XRow > xRow = getPropertyValues( CommandId, { { "CasePreservingURL", -1, cppu::UnoType<sal_Bool>::get(), 0 } }); + OUString CasePreservingURL = xRow->getString(1); + if(!xRow->wasNull()) + aAny <<= CasePreservingURL; + } + else if ( aCommand.Name == "createNewContent" ) + { + ucb::ContentInfo aArg; + if ( !( aCommand.Argument >>= aArg ) ) + m_pMyShell->installError( CommandId, + TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT ); + else + aAny <<= createNewContent( aArg ); + } + else + m_pMyShell->installError( CommandId, + TASKHANDLER_UNSUPPORTED_COMMAND ); + + + // This is the only function allowed to throw an exception + endTask( CommandId ); + + return aAny; +} + + +void SAL_CALL +BaseContent::addPropertiesChangeListener( + const Sequence< OUString >& PropertyNames, + const Reference< beans::XPropertiesChangeListener >& Listener ) +{ + if( ! Listener.is() ) + return; + + std::unique_lock aGuard( m_aMutex ); + + if( ! m_pPropertyListener ) + m_pPropertyListener.reset( new PropertyListeners ); + + + if( !PropertyNames.hasElements() ) + m_pPropertyListener->addInterface( aGuard, OUString(),Listener ); + else + { + Reference< beans::XPropertySetInfo > xProp = m_pMyShell->info_p( m_aUncPath ); + for( const auto& rName : PropertyNames ) + if( xProp->hasPropertyByName( rName ) ) + m_pPropertyListener->addInterface( aGuard, rName,Listener ); + } +} + + +void SAL_CALL +BaseContent::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames, + const Reference< beans::XPropertiesChangeListener >& Listener ) +{ + if( ! Listener.is() ) + return; + + std::unique_lock aGuard( m_aMutex ); + + if( ! m_pPropertyListener ) + return; + + for( const auto& rName : PropertyNames ) + m_pPropertyListener->removeInterface( aGuard, rName,Listener ); + + m_pPropertyListener->removeInterface( aGuard, OUString(), Listener ); +} + + +// XContent + + +Reference< ucb::XContentIdentifier > SAL_CALL +BaseContent::getIdentifier() +{ + return m_xContentIdentifier; +} + + +OUString SAL_CALL +BaseContent::getContentType() +{ + if( !( m_nState & Deleted ) ) + { + if( m_nState & JustInserted ) + { + if ( m_bFolder ) + return TaskManager::FolderContentType; + else + return TaskManager::FileContentType; + } + else + { + try + { + // Who am I ? + Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { "IsDocument", -1, cppu::UnoType<sal_Bool>::get(), 0 } }); + bool IsDocument = xRow->getBoolean( 1 ); + + if ( !xRow->wasNull() ) + { + if ( IsDocument ) + return TaskManager::FileContentType; + else + return TaskManager::FolderContentType; + } + else + { + OSL_FAIL( "BaseContent::getContentType - Property value was null!" ); + } + } + catch (const sdbc::SQLException&) + { + TOOLS_WARN_EXCEPTION("ucb.ucp.file", ""); + } + } + } + + return OUString(); +} + + +void SAL_CALL +BaseContent::addContentEventListener( + const Reference< XContentEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aContentEventListeners.addInterface( aGuard, Listener ); +} + + +void SAL_CALL +BaseContent::removeContentEventListener( + const Reference< XContentEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aContentEventListeners.removeInterface( aGuard, Listener ); +} + + +// XPropertyContainer + + +void SAL_CALL +BaseContent::addProperty( + const OUString& Name, + sal_Int16 Attributes, + const Any& DefaultValue ) +{ + if( ( m_nState & JustInserted ) || ( m_nState & Deleted ) || Name.isEmpty() ) + { + throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 ); + } + + m_pMyShell->associate( m_aUncPath,Name,DefaultValue,Attributes ); +} + + +void SAL_CALL +BaseContent::removeProperty( const OUString& Name ) +{ + + if( m_nState & Deleted ) + throw beans::UnknownPropertyException( Name ); + + m_pMyShell->deassociate( m_aUncPath, Name ); +} + + +// XContentCreator + + +Sequence< ContentInfo > SAL_CALL +BaseContent::queryCreatableContentsInfo() +{ + return TaskManager::queryCreatableContentsInfo(); +} + + +Reference< XContent > SAL_CALL +BaseContent::createNewContent( const ContentInfo& Info ) +{ + // Check type. + if ( Info.Type.isEmpty() ) + return Reference< XContent >(); + + bool bFolder = Info.Type == TaskManager::FolderContentType; + if ( !bFolder ) + { + if ( Info.Type != TaskManager::FileContentType ) + { + // Neither folder nor file to create! + return Reference< XContent >(); + } + } + + // Who am I ? + bool IsDocument = false; + + try + { + Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { "IsDocument", -1, cppu::UnoType<sal_Bool>::get(), 0 } }); + IsDocument = xRow->getBoolean( 1 ); + + if ( xRow->wasNull() ) + { + IsDocument = false; +// OSL_FAIL( // "BaseContent::createNewContent - Property value was null!" ); +// return Reference< XContent >(); + } + } + catch (const sdbc::SQLException&) + { + TOOLS_WARN_EXCEPTION("ucb.ucp.file", ""); + return Reference< XContent >(); + } + + OUString dstUncPath; + + if( IsDocument ) + { + // KSO: Why is a document a XContentCreator? This is quite unusual. + dstUncPath = getParentName( m_aUncPath ); + } + else + dstUncPath = m_aUncPath; + + return new BaseContent( m_pMyShell, dstUncPath, bFolder ); +} + + +// XPropertySetInfoChangeNotifier + + +void SAL_CALL +BaseContent::addPropertySetInfoChangeListener( + const Reference< beans::XPropertySetInfoChangeListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aPropertySetInfoChangeListeners.addInterface( aGuard, Listener ); +} + + +void SAL_CALL +BaseContent::removePropertySetInfoChangeListener( + const Reference< beans::XPropertySetInfoChangeListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aPropertySetInfoChangeListeners.removeInterface( aGuard, Listener ); +} + + +// XChild + + +Reference< XInterface > SAL_CALL +BaseContent::getParent() +{ + OUString ParentUnq = getParentName( m_aUncPath ); + OUString ParentUrl; + + + bool err = fileaccess::TaskManager::getUrlFromUnq( ParentUnq, ParentUrl ); + if( err ) + return Reference< XInterface >( nullptr ); + + rtl::Reference<FileContentIdentifier> Identifier = new FileContentIdentifier( ParentUnq ); + + try + { + return Reference<XInterface>( m_pMyShell->m_pProvider->queryContent( Identifier ), UNO_QUERY ); + } + catch (const IllegalIdentifierException&) + { + return Reference< XInterface >(); + } +} + + +void SAL_CALL +BaseContent::setParent( + const Reference< XInterface >& ) +{ + throw lang::NoSupportException( THROW_WHERE ); +} + + +// Private Methods + + +Reference< XCommandInfo > +BaseContent::getCommandInfo() +{ + if( m_nState & Deleted ) + return Reference< XCommandInfo >(); + + return m_pMyShell->info_c(); +} + + +Reference< beans::XPropertySetInfo > +BaseContent::getPropertySetInfo() +{ + if( m_nState & Deleted ) + return Reference< beans::XPropertySetInfo >(); + + return m_pMyShell->info_p( m_aUncPath ); +} + +Reference< sdbc::XRow > +BaseContent::getPropertyValues( + sal_Int32 nMyCommandIdentifier, + const Sequence< beans::Property >& PropertySet ) +{ + sal_Int32 nProps = PropertySet.getLength(); + if ( !nProps ) + return Reference< sdbc::XRow >(); + + if( m_nState & Deleted ) + { + Sequence< Any > aValues( nProps ); + return Reference< sdbc::XRow >( new XRow_impl( m_pMyShell, aValues ) ); + } + + if( m_nState & JustInserted ) + { + Sequence< Any > aValues( nProps ); + Any* pValues = aValues.getArray(); + + const beans::Property* pProps = PropertySet.getConstArray(); + + for ( sal_Int32 n = 0; n < nProps; ++n ) + { + const beans::Property& rProp = pProps[ n ]; + Any& rValue = pValues[ n ]; + + if ( rProp.Name == "ContentType" ) + { + rValue <<= (m_bFolder ? TaskManager::FolderContentType + : TaskManager::FileContentType); + } + else if ( rProp.Name == "IsFolder" ) + { + rValue <<= m_bFolder; + } + else if ( rProp.Name == "IsDocument" ) + { + rValue <<= !m_bFolder; + } + } + + return Reference< sdbc::XRow >( + new XRow_impl( m_pMyShell, aValues ) ); + } + + return m_pMyShell->getv( nMyCommandIdentifier, + m_aUncPath, + PropertySet ); +} + + +Sequence< Any > +BaseContent::setPropertyValues( + sal_Int32 nMyCommandIdentifier, + const Sequence< beans::PropertyValue >& Values ) +{ + if( m_nState & Deleted ) + { // To do + return Sequence< Any >( Values.getLength() ); + } + + static constexpr OUString Title(u"Title"_ustr); + + // Special handling for files which have to be inserted + if( m_nState & JustInserted ) + { + for( const auto& rValue : Values ) + { + if( rValue.Name == Title ) + { + OUString NewTitle; + if( rValue.Value >>= NewTitle ) + { + if ( m_nState & NameForInsertionSet ) + { + // User wants to set another Title before "insert". + // m_aUncPath contains previous own URI. + + sal_Int32 nLastSlash = m_aUncPath.lastIndexOf( '/' ); + bool bTrailingSlash = false; + if ( nLastSlash == m_aUncPath.getLength() - 1 ) + { + bTrailingSlash = true; + nLastSlash + = m_aUncPath.lastIndexOf( '/', nLastSlash ); + } + + OSL_ENSURE( nLastSlash != -1, + "BaseContent::setPropertyValues: " + "Invalid URL!" ); + + OUStringBuffer aBuf( + m_aUncPath.subView( 0, nLastSlash + 1 ) ); + + if ( !NewTitle.isEmpty() ) + { + aBuf.append( NewTitle ); + if ( bTrailingSlash ) + aBuf.append( '/' ); + } + else + { + m_nState &= ~NameForInsertionSet; + } + + m_aUncPath = aBuf.makeStringAndClear(); + } + else + { + if ( !NewTitle.isEmpty() ) + { + // Initial Title before "insert". + // m_aUncPath contains parent's URI. + + if( !m_aUncPath.endsWith( "/" ) ) + m_aUncPath += "/"; + + m_aUncPath += rtl::Uri::encode( NewTitle, + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + m_nState |= NameForInsertionSet; + } + } + } + } + } + + return Sequence< Any >( Values.getLength() ); + } + else + { + Sequence< Any > ret = m_pMyShell->setv( m_aUncPath, // Does not handle Title + Values ); + auto retRange = asNonConstRange(ret); + + // Special handling Title: Setting Title is equivalent to a renaming of the underlying file + for( sal_Int32 i = 0; i < Values.getLength(); ++i ) + { + if( Values[i].Name != Title ) + continue; // handled by setv + + OUString NewTitle; + if( !( Values[i].Value >>= NewTitle ) ) + { + retRange[i] <<= beans::IllegalTypeException( THROW_WHERE ); + break; + } + else if( NewTitle.isEmpty() ) + { + retRange[i] <<= lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 ); + break; + } + + + OUString aDstName = getParentName( m_aUncPath ); + if( !aDstName.endsWith("/") ) + aDstName += "/"; + + aDstName += rtl::Uri::encode( NewTitle, + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + + m_pMyShell->move( nMyCommandIdentifier, // move notifies the children also; + m_aUncPath, + aDstName, + NameClash::KEEP ); + + try + { + endTask( nMyCommandIdentifier ); + } + catch(const Exception& e) + { + retRange[i] <<= e; + } + + // NameChanges come back through a ContentEvent + break; // only handling Title + } // end for + + return ret; + } +} + + +Reference< XDynamicResultSet > +BaseContent::open( + sal_Int32 nMyCommandIdentifier, + const OpenCommandArgument2& aCommandArgument ) +{ + Reference< XDynamicResultSet > retValue; + + if( m_nState & Deleted ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND ); + } + else if( m_nState & JustInserted ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND ); + } + else + { + if( aCommandArgument.Mode == OpenMode::DOCUMENT || + aCommandArgument.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE ) + + { + Reference< io::XOutputStream > outputStream( aCommandArgument.Sink,UNO_QUERY ); + if( outputStream.is() ) + { + m_pMyShell->page( nMyCommandIdentifier, + m_aUncPath, + outputStream ); + } + + bool bLock = ( aCommandArgument.Mode != OpenMode::DOCUMENT_SHARE_DENY_NONE ); + + Reference< io::XActiveDataSink > activeDataSink( aCommandArgument.Sink,UNO_QUERY ); + if( activeDataSink.is() ) + { + activeDataSink->setInputStream( m_pMyShell->open( nMyCommandIdentifier, + m_aUncPath, + bLock ) ); + } + + Reference< io::XActiveDataStreamer > activeDataStreamer( aCommandArgument.Sink,UNO_QUERY ); + if( activeDataStreamer.is() ) + { + activeDataStreamer->setStream( m_pMyShell->open_rw( nMyCommandIdentifier, + m_aUncPath, + bLock ) ); + } + } + else if ( aCommandArgument.Mode == OpenMode::ALL || + aCommandArgument.Mode == OpenMode::FOLDERS || + aCommandArgument.Mode == OpenMode::DOCUMENTS ) + { + retValue = m_pMyShell->ls( nMyCommandIdentifier, + m_aUncPath, + aCommandArgument.Mode, + aCommandArgument.Properties, + aCommandArgument.SortingInfo ); + } +// else if( aCommandArgument.Mode == +// OpenMode::DOCUMENT_SHARE_DENY_NONE || +// aCommandArgument.Mode == +// OpenMode::DOCUMENT_SHARE_DENY_WRITE ) +// m_pMyShell->installError( nMyCommandIdentifier, +// TASKHANDLING_UNSUPPORTED_OPEN_MODE, +// aCommandArgument.Mode); + else + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_UNSUPPORTED_OPEN_MODE, + aCommandArgument.Mode); + } + + return retValue; +} + + +void +BaseContent::deleteContent( sal_Int32 nMyCommandIdentifier ) +{ + if( m_nState & Deleted ) + return; + + if( m_pMyShell->remove( nMyCommandIdentifier,m_aUncPath ) ) + { + std::unique_lock aGuard( m_aMutex ); + m_nState |= Deleted; + } +} + + +void +BaseContent::transfer( sal_Int32 nMyCommandIdentifier, + const TransferInfo& aTransferInfo ) +{ + if( m_nState & Deleted ) + return; + + if( !comphelper::isFileUrl(aTransferInfo.SourceURL) ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_TRANSFER_INVALIDSCHEME ); + return; + } + + OUString srcUnc; + if( fileaccess::TaskManager::getUnqFromUrl( aTransferInfo.SourceURL,srcUnc ) ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_TRANSFER_INVALIDURL ); + return; + } + + OUString srcUncPath = srcUnc; + + // Determine the new title ! + OUString NewTitle; + if( !aTransferInfo.NewTitle.isEmpty() ) + NewTitle = rtl::Uri::encode( aTransferInfo.NewTitle, + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + else + NewTitle = srcUncPath.copy( 1 + srcUncPath.lastIndexOf( '/' ) ); + + // Is destination a document or a folder ? + Reference< sdbc::XRow > xRow = getPropertyValues( nMyCommandIdentifier,{ { "IsDocument", -1, cppu::UnoType<sal_Bool>::get(), 0 } } ); + bool IsDocument = xRow->getBoolean( 1 ); + if( xRow->wasNull() ) + { // Destination file type could not be determined + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_TRANSFER_DESTFILETYPE ); + return; + } + + OUString dstUncPath; + if( IsDocument ) + { // as sibling + sal_Int32 lastSlash = m_aUncPath.lastIndexOf( '/' ); + dstUncPath = m_aUncPath.copy(0,lastSlash ); + } + else + // as child + dstUncPath = m_aUncPath; + + dstUncPath += "/" + NewTitle; + + sal_Int32 NameClash = aTransferInfo.NameClash; + + if( aTransferInfo.MoveData ) + m_pMyShell->move( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash ); + else + m_pMyShell->copy( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash ); +} + + +void BaseContent::insert( sal_Int32 nMyCommandIdentifier, + const InsertCommandArgument& aInsertArgument ) +{ + if( m_nState & FullFeatured ) + { + m_pMyShell->write( nMyCommandIdentifier, + m_aUncPath, + aInsertArgument.ReplaceExisting, + aInsertArgument.Data ); + return; + } + + if( ! ( m_nState & JustInserted ) ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND ); + return; + } + + // Inserts the content, which has the flag m_bIsFresh + + if( ! (m_nState & NameForInsertionSet) ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_NONAMESET_INSERT_COMMAND ); + return; + } + + // Inserting a document or a file? + bool bDocument = false; + + Reference< sdbc::XRow > xRow = getPropertyValues( -1, { { "IsDocument", -1, cppu::UnoType<sal_Bool>::get(), 0 } }); + + bool contentTypeSet = true; // is set to false, if contentType not set + try + { + bDocument = xRow->getBoolean( 1 ); + if( xRow->wasNull() ) + contentTypeSet = false; + + } + catch (const sdbc::SQLException&) + { + TOOLS_WARN_EXCEPTION("ucb.ucp.file", ""); + contentTypeSet = false; + } + + if( ! contentTypeSet ) + { + m_pMyShell->installError( nMyCommandIdentifier, + TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND ); + return; + } + + + bool success = false; + if( bDocument ) + success = m_pMyShell->mkfil( nMyCommandIdentifier, + m_aUncPath, + aInsertArgument.ReplaceExisting, + aInsertArgument.Data ); + else + { + while( ! success ) + { + success = m_pMyShell->mkdir( nMyCommandIdentifier, + m_aUncPath, + aInsertArgument.ReplaceExisting ); + if( success ) + break; + + XInteractionRequestImpl aRequestImpl( + rtl::Uri::decode( + OUString(getTitle(m_aUncPath)), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8), + getXWeak(), + m_pMyShell,nMyCommandIdentifier); + uno::Reference<task::XInteractionRequest> const& xReq(aRequestImpl.getRequest()); + + m_pMyShell->handleTask( nMyCommandIdentifier, xReq ); + if (aRequestImpl.aborted() || aRequestImpl.newName().isEmpty()) + // means aborting + break; + + // determine new uncpath + m_pMyShell->clearError( nMyCommandIdentifier ); + m_aUncPath = getParentName( m_aUncPath ); + if( !m_aUncPath.endsWith( "/" ) ) + m_aUncPath += "/"; + + m_aUncPath += rtl::Uri::encode( aRequestImpl.newName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + } + } + + if ( ! success ) + return; + + m_xContentIdentifier.set( new FileContentIdentifier( m_aUncPath ) ); + + m_pMyShell->registerNotifier( m_aUncPath,this ); + m_pMyShell->insertDefaultProperties( m_aUncPath ); + + std::unique_lock aGuard( m_aMutex ); + m_nState = FullFeatured; +} + + +void BaseContent::endTask( sal_Int32 CommandId ) +{ + // This is the only function allowed to throw an exception + m_pMyShell->endTask( CommandId,m_aUncPath,this ); +} + + +std::optional<ContentEventNotifier> +BaseContent::cDEL() +{ + std::unique_lock aGuard( m_aMutex ); + + m_nState |= Deleted; + + if( m_aContentEventListeners.getLength(aGuard) == 0 ) + return {}; + + return ContentEventNotifier( m_pMyShell, + this, + m_xContentIdentifier, + m_aContentEventListeners.getElements(aGuard) ); +} + + +std::optional<ContentEventNotifier> +BaseContent::cEXC( const OUString& aNewName ) +{ + std::unique_lock aGuard( m_aMutex ); + + Reference< XContentIdentifier > xOldRef = m_xContentIdentifier; + m_aUncPath = aNewName; + m_xContentIdentifier = new FileContentIdentifier( aNewName ); + + if( m_aContentEventListeners.getLength(aGuard) == 0 ) + return {}; + return ContentEventNotifier( m_pMyShell, + this, + m_xContentIdentifier, + xOldRef, + m_aContentEventListeners.getElements(aGuard) ); +} + + +std::optional<ContentEventNotifier> +BaseContent::cCEL() +{ + std::unique_lock aGuard( m_aMutex ); + if( m_aContentEventListeners.getLength(aGuard) == 0 ) + return {}; + return ContentEventNotifier( m_pMyShell, + this, + m_xContentIdentifier, + m_aContentEventListeners.getElements(aGuard) ); +} + +std::optional<PropertySetInfoChangeNotifier> +BaseContent::cPSL() +{ + std::unique_lock aGuard( m_aMutex ); + if( m_aPropertySetInfoChangeListeners.getLength(aGuard) == 0 ) + return {}; + return PropertySetInfoChangeNotifier( this, m_aPropertySetInfoChangeListeners.getElements(aGuard) ); +} + + +std::optional<PropertyChangeNotifier> +BaseContent::cPCL() +{ + std::unique_lock aGuard( m_aMutex ); + + if (!m_pPropertyListener) + return {}; + + const std::vector< OUString > seqNames = m_pPropertyListener->getContainedTypes(aGuard); + if( seqNames.empty() ) + return {}; + + ListenerMap listener; + for( const auto& rName : seqNames ) + { + comphelper::OInterfaceContainerHelper4<beans::XPropertiesChangeListener>* pContainer = m_pPropertyListener->getContainer(aGuard, rName); + if (!pContainer) + continue; + listener[rName] = pContainer->getElements(aGuard); + } + + return PropertyChangeNotifier( this, std::move(listener) ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/bc.hxx b/ucb/source/ucp/file/bc.hxx new file mode 100644 index 0000000000..ca1f045fb5 --- /dev/null +++ b/ucb/source/ucp/file/bc.hxx @@ -0,0 +1,257 @@ +/* -*- 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 <mutex> +#include <rtl/ustring.hxx> +#include <cppuhelper/implbase.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/XPropertySetInfoChangeNotifier.hpp> +#include <com/sun/star/beans/XPropertySetInfoChangeListener.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/ucb/XContentCreator.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include "filtask.hxx" + + +namespace fileaccess { + + class PropertyListeners; + class TaskManager; + + class BaseContent: + public cppu::WeakImplHelper< + css::lang::XComponent, + css::lang::XServiceInfo, + css::ucb::XCommandProcessor, + css::beans::XPropertiesChangeNotifier, + css::beans::XPropertyContainer, + css::beans::XPropertySetInfoChangeNotifier, + css::ucb::XContentCreator, + css::container::XChild, + css::ucb::XContent>, + public fileaccess::Notifier // implementation class + { + private: + + // A special creator for inserted contents; Creates an ugly object + BaseContent( TaskManager* pMyShell, + OUString parentName, + bool bFolder ); + + public: + BaseContent( + TaskManager* pMyShell, + const css::uno::Reference< css::ucb::XContentIdentifier >& xContentIdentifier, + OUString aUnqPath ); + + virtual ~BaseContent() override; + + // XComponent + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( + const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + + // 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; + + + // XCommandProcessor + virtual sal_Int32 SAL_CALL + createCommandIdentifier() override; + + virtual css::uno::Any SAL_CALL + execute( + const css::ucb::Command& aCommand, + sal_Int32 CommandId, + const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override; + + virtual void SAL_CALL + abort( sal_Int32 CommandId ) override; + + + // XContent + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL + getIdentifier() override; + + virtual OUString SAL_CALL + getContentType() override; + + virtual void SAL_CALL + addContentEventListener( + const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override; + + virtual void SAL_CALL + removeContentEventListener( + const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override; + + // XPropertiesChangeNotifier + + virtual void SAL_CALL + addPropertiesChangeListener( + const css::uno::Sequence< OUString >& PropertyNames, + const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override; + + virtual void SAL_CALL + removePropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, + const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override; + + // XPropertyContainer + + virtual void SAL_CALL + addProperty( + const OUString& Name, + sal_Int16 Attributes, + const css::uno::Any& DefaultValue ) override; + + virtual void SAL_CALL + removeProperty( const OUString& Name ) override; + + // XPropertySetInfoChangeNotifier + + virtual void SAL_CALL + addPropertySetInfoChangeListener( + const css::uno::Reference< css::beans::XPropertySetInfoChangeListener >& Listener ) override; + + virtual void SAL_CALL + removePropertySetInfoChangeListener( + const css::uno::Reference< css::beans::XPropertySetInfoChangeListener >& Listener ) override; + + + // XContentCreator + + 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; + + + // XChild + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + getParent() override; + + // Not supported + virtual void SAL_CALL + setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + + // Notifier + + std::optional<ContentEventNotifier> cDEL() override; + std::optional<ContentEventNotifier> cEXC( const OUString& aNewName ) override; + std::optional<ContentEventNotifier> cCEL() override; + std::optional<PropertySetInfoChangeNotifier> cPSL() override; + std::optional<PropertyChangeNotifier> cPCL() override; + + private: + // Data members + TaskManager* m_pMyShell; + css::uno::Reference< css::ucb::XContentIdentifier > m_xContentIdentifier; + OUString m_aUncPath; + + enum state { NameForInsertionSet = 1, + JustInserted = 2, + Deleted = 4, + FullFeatured = 8 }; + bool m_bFolder; + sal_uInt16 m_nState; + + std::mutex m_aMutex; + comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aDisposeEventListeners; + comphelper::OInterfaceContainerHelper4<css::ucb::XContentEventListener> m_aContentEventListeners; + comphelper::OInterfaceContainerHelper4<css::beans::XPropertySetInfoChangeListener> m_aPropertySetInfoChangeListeners; + std::unique_ptr<PropertyListeners> m_pPropertyListener; + + + // Private Methods + /// @throws css::uno::RuntimeException + css::uno::Reference< css::ucb::XCommandInfo > + getCommandInfo(); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::beans::XPropertySetInfo > + getPropertySetInfo(); + + /// @throws css::uno::RuntimeException + css::uno::Reference< css::sdbc::XRow > + getPropertyValues( + sal_Int32 nMyCommandIdentifier, + const css::uno::Sequence< css::beans::Property >& PropertySet ); + + css::uno::Sequence< css::uno::Any > + setPropertyValues( + sal_Int32 nMyCommandIdentifier, + const css::uno::Sequence< css::beans::PropertyValue >& Values ); + + css::uno::Reference< css::ucb::XDynamicResultSet > + open( + sal_Int32 nMyCommandIdentifier, + const css::ucb::OpenCommandArgument2& aCommandArgument ); + + void + deleteContent( sal_Int32 nMyCommandIdentifier ); + + + void + transfer( sal_Int32 nMyCommandIdentifier, + const css::ucb::TransferInfo& aTransferInfo ); + + void + insert( sal_Int32 nMyCommandIdentifier, + const css::ucb::InsertCommandArgument& aInsertArgument ); + + void endTask( sal_Int32 CommandId ); + + friend class ContentEventNotifier; + }; + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filcmd.cxx b/ucb/source/ucp/file/filcmd.cxx new file mode 100644 index 0000000000..7bbfca94e0 --- /dev/null +++ b/ucb/source/ucp/file/filcmd.cxx @@ -0,0 +1,123 @@ +/* -*- 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 <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/ucb/UnsupportedCommandException.hpp> + +#include "filcmd.hxx" +#include "filtask.hxx" + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::ucb; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +XCommandInfo_impl::XCommandInfo_impl( TaskManager* pMyShell ) + : m_pMyShell( pMyShell ) +{ +} + +XCommandInfo_impl::~XCommandInfo_impl() +{ +} + + +void SAL_CALL +XCommandInfo_impl::acquire() + noexcept +{ + OWeakObject::acquire(); +} + + +void SAL_CALL +XCommandInfo_impl::release() + noexcept +{ + OWeakObject::release(); +} + + +uno::Any SAL_CALL +XCommandInfo_impl::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet = cppu::queryInterface( rType, + static_cast< XCommandInfo* >(this) ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +uno::Sequence< CommandInfo > SAL_CALL +XCommandInfo_impl::getCommands() +{ + return m_pMyShell->m_sCommandInfo; +} + + +CommandInfo SAL_CALL +XCommandInfo_impl::getCommandInfoByName( + const OUString& aName ) +{ + auto pCommand = std::find_if(std::cbegin(m_pMyShell->m_sCommandInfo), std::cend(m_pMyShell->m_sCommandInfo), + [&aName](const CommandInfo& rCommand) { return rCommand.Name == aName; }); + if (pCommand != std::cend(m_pMyShell->m_sCommandInfo)) + return *pCommand; + + throw UnsupportedCommandException( THROW_WHERE ); +} + + +CommandInfo SAL_CALL +XCommandInfo_impl::getCommandInfoByHandle( + sal_Int32 Handle ) +{ + auto pCommand = std::find_if(std::cbegin(m_pMyShell->m_sCommandInfo), std::cend(m_pMyShell->m_sCommandInfo), + [&Handle](const CommandInfo& rCommand) { return rCommand.Handle == Handle; }); + if (pCommand != std::cend(m_pMyShell->m_sCommandInfo)) + return *pCommand; + + throw UnsupportedCommandException( THROW_WHERE ); +} + + +sal_Bool SAL_CALL +XCommandInfo_impl::hasCommandByName( + const OUString& aName ) +{ + return std::any_of(std::cbegin(m_pMyShell->m_sCommandInfo), std::cend(m_pMyShell->m_sCommandInfo), + [&aName](const CommandInfo& rCommand) { return rCommand.Name == aName; }); +} + + +sal_Bool SAL_CALL +XCommandInfo_impl::hasCommandByHandle( + sal_Int32 Handle ) +{ + return std::any_of(std::cbegin(m_pMyShell->m_sCommandInfo), std::cend(m_pMyShell->m_sCommandInfo), + [&Handle](const CommandInfo& rCommand) { return rCommand.Handle == Handle; }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filcmd.hxx b/ucb/source/ucp/file/filcmd.hxx new file mode 100644 index 0000000000..4a7729e89b --- /dev/null +++ b/ucb/source/ucp/file/filcmd.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/ucb/XCommandInfo.hpp> + + +namespace fileaccess { + + + // forward + class TaskManager; + + + class XCommandInfo_impl + : public cppu::OWeakObject, + public css::ucb::XCommandInfo + { + public: + + explicit XCommandInfo_impl( TaskManager* pMyShell ); + + virtual ~XCommandInfo_impl() override; + + // XInterface + virtual css::uno::Any SAL_CALL + queryInterface( const css::uno::Type& aType ) override; + + virtual void SAL_CALL + acquire() + noexcept override; + + virtual void SAL_CALL + release() + noexcept override; + + // XCommandInfo + + virtual css::uno::Sequence< css::ucb::CommandInfo > SAL_CALL + getCommands() override; + + virtual css::ucb::CommandInfo SAL_CALL + getCommandInfoByName( const OUString& Name ) override; + + virtual css::ucb::CommandInfo SAL_CALL + getCommandInfoByHandle( sal_Int32 Handle ) override; + + virtual sal_Bool SAL_CALL + hasCommandByName( const OUString& Name ) override; + + virtual sal_Bool SAL_CALL + hasCommandByHandle( sal_Int32 Handle ) override; + + + private: + + TaskManager* m_pMyShell; + }; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filerror.hxx b/ucb/source/ucp/file/filerror.hxx new file mode 100644 index 0000000000..c75d11ea19 --- /dev/null +++ b/ucb/source/ucp/file/filerror.hxx @@ -0,0 +1,105 @@ +/* -*- 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 + +namespace fileaccess { + +// Error codes used to deliver the resulting exceptions + +#define TASKHANDLER_NO_ERROR 0 +#define TASKHANDLER_UNSUPPORTED_COMMAND 1 +#define TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT 2 +#define TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT 3 +#define TASKHANDLING_WRONG_OPEN_ARGUMENT 4 +#define TASKHANDLING_WRONG_DELETE_ARGUMENT 5 +#define TASKHANDLING_WRONG_TRANSFER_ARGUMENT 6 +#define TASKHANDLING_WRONG_INSERT_ARGUMENT 7 +#define TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT 8 +#define TASKHANDLING_UNSUPPORTED_OPEN_MODE 9 + +#define TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND 10 +#define TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND 11 + +#define TASKHANDLING_OPEN_FILE_FOR_PAGING 12 +#define TASKHANDLING_NOTCONNECTED_FOR_PAGING 13 +#define TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_PAGING 14 +#define TASKHANDLING_IOEXCEPTION_FOR_PAGING 15 +#define TASKHANDLING_READING_FILE_FOR_PAGING 16 + +#define TASKHANDLING_OPEN_FOR_INPUTSTREAM 17 +#define TASKHANDLING_OPEN_FOR_STREAM 18 +#define TASKHANDLING_OPEN_FOR_DIRECTORYLISTING 19 + +#define TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND 22 +#define TASKHANDLING_NONAMESET_INSERT_COMMAND 23 +#define TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND 24 + +#define TASKHANDLING_NO_OPEN_FILE_FOR_OVERWRITE 26 +#define TASKHANDLING_NO_OPEN_FILE_FOR_WRITE 27 +#define TASKHANDLING_NOTCONNECTED_FOR_WRITE 28 +#define TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_WRITE 29 +#define TASKHANDLING_IOEXCEPTION_FOR_WRITE 30 +#define TASKHANDLING_FILEIOERROR_FOR_WRITE 31 +#define TASKHANDLING_FILEIOERROR_FOR_NO_SPACE 71 +#define TASKHANDLING_FILESIZE_FOR_WRITE 32 +#define TASKHANDLING_INPUTSTREAM_FOR_WRITE 33 +#define TASKHANDLING_NOREPLACE_FOR_WRITE 34 +#define TASKHANDLING_ENSUREDIR_FOR_WRITE 35 + +#define TASKHANDLING_FOLDER_EXISTS_MKDIR 69 +#define TASKHANDLING_INVALID_NAME_MKDIR 70 +#define TASKHANDLING_CREATEDIRECTORY_MKDIR 36 + +#define TASKHANDLING_NOSUCHFILEORDIR_FOR_REMOVE 38 +#define TASKHANDLING_VALIDFILESTATUS_FOR_REMOVE 39 +#define TASKHANDLING_OPENDIRECTORY_FOR_REMOVE 40 +#define TASKHANDLING_DELETEFILE_FOR_REMOVE 41 +#define TASKHANDLING_DELETEDIRECTORY_FOR_REMOVE 42 +#define TASKHANDLING_FILETYPE_FOR_REMOVE 43 +#define TASKHANDLING_VALIDFILESTATUSWHILE_FOR_REMOVE 44 +#define TASKHANDLING_DIRECTORYEXHAUSTED_FOR_REMOVE 45 + +#define TASKHANDLING_TRANSFER_ACCESSINGROOT 46 +#define TASKHANDLING_TRANSFER_INVALIDSCHEME 47 +#define TASKHANDLING_TRANSFER_INVALIDURL 48 +#define TASKHANDLING_TRANSFER_DESTFILETYPE 50 +#define TASKHANDLING_TRANSFER_BY_MOVE_SOURCE 51 +#define TASKHANDLING_TRANSFER_BY_MOVE_SOURCESTAT 52 +#define TASKHANDLING_KEEPERROR_FOR_MOVE 53 +#define TASKHANDLING_NAMECLASH_FOR_MOVE 54 +#define TASKHANDLING_NAMECLASHMOVE_FOR_MOVE 55 +#define TASKHANDLING_NAMECLASHSUPPORT_FOR_MOVE 56 +#define TASKHANDLING_OVERWRITE_FOR_MOVE 57 +#define TASKHANDLING_RENAME_FOR_MOVE 58 +#define TASKHANDLING_RENAMEMOVE_FOR_MOVE 59 + +#define TASKHANDLING_TRANSFER_BY_COPY_SOURCE 60 +#define TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT 61 +#define TASKHANDLING_KEEPERROR_FOR_COPY 62 +#define TASKHANDLING_OVERWRITE_FOR_COPY 63 +#define TASKHANDLING_RENAME_FOR_COPY 64 +#define TASKHANDLING_RENAMEMOVE_FOR_COPY 65 +#define TASKHANDLING_NAMECLASH_FOR_COPY 66 +#define TASKHANDLING_NAMECLASHMOVE_FOR_COPY 67 +#define TASKHANDLING_NAMECLASHSUPPORT_FOR_COPY 68 + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filglob.cxx b/ucb/source/ucp/file/filglob.cxx new file mode 100644 index 0000000000..ef44d7b253 --- /dev/null +++ b/ucb/source/ucp/file/filglob.cxx @@ -0,0 +1,855 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <string_view> + +#include "filglob.hxx" +#include "filerror.hxx" +#include "bc.hxx" +#include <osl/file.hxx> +#include <ucbhelper/cancelcommandexecution.hxx> +#include <com/sun/star/ucb/UnsupportedCommandException.hpp> +#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/ucb/MissingPropertiesException.hpp> +#include <com/sun/star/ucb/MissingInputStreamException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp> +#include <com/sun/star/ucb/UnsupportedNameClashException.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <o3tl/string_view.hxx> +#include <osl/diagnose.h> +#include <rtl/uri.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +using namespace ucbhelper; +using namespace osl; +using namespace ::com::sun::star; +using namespace com::sun::star::task; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; + +namespace { + + Sequence< Any > generateErrorArguments( + OUString const & rPhysicalUrl) + { + OUString aResourceName; + OUString aResourceType; + bool bRemovable = false; + bool bResourceName = false; + bool bResourceType = false; + bool bRemoveProperty = false; + + if (osl::FileBase::getSystemPathFromFileURL( + rPhysicalUrl, + aResourceName) + == osl::FileBase::E_None) + bResourceName = true; + + // The resource types "folder" (i.e., directory) and + // "volume" seem to be + // the most interesting when producing meaningful error messages: + osl::DirectoryItem aItem; + if (osl::DirectoryItem::get(rPhysicalUrl, aItem) == + osl::FileBase::E_None) + { + osl::FileStatus aStatus( osl_FileStatus_Mask_Type ); + if (aItem.getFileStatus(aStatus) == osl::FileBase::E_None) + switch (aStatus.getFileType()) + { + case osl::FileStatus::Directory: + aResourceType = "folder"; + bResourceType = true; + break; + + case osl::FileStatus::Volume: + { + aResourceType = "volume"; + bResourceType = true; + osl::VolumeInfo aVolumeInfo( + osl_VolumeInfo_Mask_Attributes ); + if( osl::Directory::getVolumeInfo( + rPhysicalUrl,aVolumeInfo ) == + osl::FileBase::E_None ) + { + bRemovable = aVolumeInfo.getRemoveableFlag(); + bRemoveProperty = true; + } + } + break; + case osl::FileStatus::Regular: + case osl::FileStatus::Fifo: + case osl::FileStatus::Socket: + case osl::FileStatus::Link: + case osl::FileStatus::Special: + case osl::FileStatus::Unknown: + // do nothing for now + break; + } + } + + Sequence< Any > aArguments( 1 + + (bResourceName ? 1 : 0) + + (bResourceType ? 1 : 0) + + (bRemoveProperty ? 1 : 0) ); + auto pArguments = aArguments.getArray(); + sal_Int32 i = 0; + pArguments[i++] + <<= PropertyValue("Uri", + -1, + Any(rPhysicalUrl), + PropertyState_DIRECT_VALUE); + if (bResourceName) + pArguments[i++] + <<= PropertyValue("ResourceName", + -1, + Any(aResourceName), + PropertyState_DIRECT_VALUE); + if (bResourceType) + pArguments[i++] + <<= PropertyValue("ResourceType", + -1, + Any(aResourceType), + PropertyState_DIRECT_VALUE); + if (bRemoveProperty) + pArguments[i++] + <<= PropertyValue("Removable", + -1, + Any(bRemovable), + PropertyState_DIRECT_VALUE); + + return aArguments; + } +} + + +namespace fileaccess { + + + bool isChild( std::u16string_view srcUnqPath, + std::u16string_view dstUnqPath ) + { + static const sal_Unicode slash = '/'; + // Simple lexical comparison + size_t srcL = srcUnqPath.size(); + size_t dstL = dstUnqPath.size(); + + return ( + ( srcUnqPath == dstUnqPath ) + || + ( ( dstL > srcL ) + && + o3tl::starts_with(dstUnqPath, srcUnqPath) + && + ( dstUnqPath[ srcL ] == slash ) ) + ); + } + + + OUString newName( + std::u16string_view aNewPrefix, + std::u16string_view aOldPrefix, + std::u16string_view old_Name ) + { + size_t srcL = aOldPrefix.size(); + + return OUString::Concat(aNewPrefix) + old_Name.substr( srcL ); + } + + + std::u16string_view getTitle( std::u16string_view aPath ) + { + size_t lastIndex = aPath.rfind( '/' ); + return aPath.substr( lastIndex + 1 ); + } + + + OUString getParentName( std::u16string_view aFileName ) + { + size_t lastIndex = aFileName.rfind( '/' ); + OUString aParent( aFileName.substr( 0,lastIndex ) ); + + if( aParent.endsWith(":") && aParent.getLength() == 6 ) + aParent += "/"; + + if ( aParent == "file://" ) + aParent = "file:///"; + + return aParent; + } + + + osl::FileBase::RC osl_File_copy( const OUString& strPath, + const OUString& strDestPath, + bool test ) + { + if( test ) + { + osl::DirectoryItem aItem; + if( osl::DirectoryItem::get( strDestPath,aItem ) != osl::FileBase:: E_NOENT ) + return osl::FileBase::E_EXIST; + } + + return osl::File::copy( strPath,strDestPath ); + } + + + osl::FileBase::RC osl_File_move( const OUString& strPath, + const OUString& strDestPath, + bool test ) + { + if( test ) + { + osl::DirectoryItem aItem; + if( osl::DirectoryItem::get( strDestPath,aItem ) != osl::FileBase:: E_NOENT ) + return osl::FileBase::E_EXIST; + } + + return osl::File::move( strPath,strDestPath ); + } + + void throw_handler( + sal_Int32 errorCode, + sal_Int32 minorCode, + const Reference< XCommandEnvironment >& xEnv, + const OUString& aUncPath, + BaseContent* pContent, + bool isHandled ) + { + Reference<XCommandProcessor> xComProc(pContent); + Any aAny; + IOErrorCode ioErrorCode; + + if( errorCode == TASKHANDLER_UNSUPPORTED_COMMAND ) + { + aAny <<= UnsupportedCommandException( OSL_LOG_PREFIX ); + cancelCommandExecution( aAny,xEnv ); + } + else if( errorCode == TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT || + errorCode == TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT || + errorCode == TASKHANDLING_WRONG_OPEN_ARGUMENT || + errorCode == TASKHANDLING_WRONG_DELETE_ARGUMENT || + errorCode == TASKHANDLING_WRONG_TRANSFER_ARGUMENT || + errorCode == TASKHANDLING_WRONG_INSERT_ARGUMENT || + errorCode == TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT ) + { + IllegalArgumentException excep; + excep.ArgumentPosition = 0; + cancelCommandExecution(Any(excep), xEnv); + } + else if( errorCode == TASKHANDLING_UNSUPPORTED_OPEN_MODE ) + { + UnsupportedOpenModeException excep; + excep.Mode = sal::static_int_cast< sal_Int16 >(minorCode); + cancelCommandExecution( Any(excep),xEnv ); + } + else if(errorCode == TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND || + errorCode == TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND || + errorCode == TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND ) + { + // What to do here? + } + else if( + // error in opening file + errorCode == TASKHANDLING_NO_OPEN_FILE_FOR_OVERWRITE || + // error in opening file + errorCode == TASKHANDLING_NO_OPEN_FILE_FOR_WRITE || + // error in opening file + errorCode == TASKHANDLING_OPEN_FOR_STREAM || + // error in opening file + errorCode == TASKHANDLING_OPEN_FOR_INPUTSTREAM || + // error in opening file + errorCode == TASKHANDLING_OPEN_FILE_FOR_PAGING ) + { + switch( minorCode ) + { + case FileBase::E_NAMETOOLONG: + // pathname was too long + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + case FileBase::E_NXIO: + // No such device or address + case FileBase::E_NODEV: + // No such device + ioErrorCode = IOErrorCode_INVALID_DEVICE; + break; + case FileBase::E_NOTDIR: + ioErrorCode = IOErrorCode_NOT_EXISTING_PATH; + break; + case FileBase::E_NOENT: + // No such file or directory + ioErrorCode = IOErrorCode_NOT_EXISTING; + break; + case FileBase::E_ROFS: + // #i4735# handle ROFS transparently as ACCESS_DENIED + case FileBase::E_ACCES: + case FileBase::E_PERM: + // permission denied<P> + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_ISDIR: + // Is a directory<p> + ioErrorCode = IOErrorCode_NO_FILE; + break; + case FileBase::E_NOTREADY: + ioErrorCode = IOErrorCode_DEVICE_NOT_READY; + break; + case FileBase::E_MFILE: + // too many open files used by the process + case FileBase::E_NFILE: + // too many open files in the system + ioErrorCode = IOErrorCode_OUT_OF_FILE_HANDLES; + break; + case FileBase::E_INVAL: + // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_NOMEM: + // not enough memory for allocating structures + ioErrorCode = IOErrorCode_OUT_OF_MEMORY; + break; + case FileBase::E_BUSY: + // Text file busy + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_AGAIN: + // Operation would block + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_NOLCK: // No record locks available + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_NOSYS: + ioErrorCode = IOErrorCode_NOT_SUPPORTED; + break; + case FileBase::E_FAULT: // Bad address + case FileBase::E_LOOP: // Too many symbolic links encountered + case FileBase::E_NOSPC: // No space left on device + case FileBase::E_INTR: // function call was interrupted + case FileBase::E_IO: // I/O error + case FileBase::E_MULTIHOP: // Multihop attempted + case FileBase::E_NOLINK: // Link has been severed + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "an error occurred during file opening", + xComProc); + } + else if( errorCode == TASKHANDLING_OPEN_FOR_DIRECTORYLISTING || + errorCode == TASKHANDLING_OPENDIRECTORY_FOR_REMOVE ) + { + switch( minorCode ) + { + case FileBase::E_INVAL: + // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_NOENT: + // the specified path doesn't exist + ioErrorCode = IOErrorCode_NOT_EXISTING; + break; + case FileBase::E_NOTDIR: + // the specified path is not a directory + ioErrorCode = IOErrorCode_NO_DIRECTORY; + break; + case FileBase::E_NOMEM: + // not enough memory for allocating structures + ioErrorCode = IOErrorCode_OUT_OF_MEMORY; + break; + case FileBase::E_ROFS: + // #i4735# handle ROFS transparently as ACCESS_DENIED + case FileBase::E_ACCES: // permission denied + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_NOTREADY: + ioErrorCode = IOErrorCode_DEVICE_NOT_READY; + break; + case FileBase::E_MFILE: + // too many open files used by the process + case FileBase::E_NFILE: + // too many open files in the system + ioErrorCode = IOErrorCode_OUT_OF_FILE_HANDLES; + break; + case FileBase::E_NAMETOOLONG: + // File name too long + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + case FileBase::E_LOOP: + // Too many symbolic links encountered<p> + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "an error occurred during opening a directory", + xComProc); + } + else if( errorCode == TASKHANDLING_NOTCONNECTED_FOR_WRITE || + errorCode == TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_WRITE || + errorCode == TASKHANDLING_IOEXCEPTION_FOR_WRITE || + errorCode == TASKHANDLING_NOTCONNECTED_FOR_PAGING || + errorCode == TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_PAGING || + errorCode == TASKHANDLING_IOEXCEPTION_FOR_PAGING ) + { + ioErrorCode = IOErrorCode_UNKNOWN; + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "an error occurred writing or reading from a file", + xComProc ); + } + else if( errorCode == TASKHANDLING_FILEIOERROR_FOR_NO_SPACE ) + { + ioErrorCode = IOErrorCode_OUT_OF_DISK_SPACE; + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "device full", + xComProc); + } + else if( errorCode == TASKHANDLING_FILEIOERROR_FOR_WRITE || + errorCode == TASKHANDLING_READING_FILE_FOR_PAGING ) + { + switch( minorCode ) + { + case FileBase::E_INVAL: + // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_FBIG: + // File too large + ioErrorCode = IOErrorCode_CANT_WRITE; + break; + case FileBase::E_NOSPC: + // No space left on device + ioErrorCode = IOErrorCode_OUT_OF_DISK_SPACE; + break; + case FileBase::E_NXIO: + // No such device or address + ioErrorCode = IOErrorCode_INVALID_DEVICE; + break; + case FileBase::E_NOLINK: + // Link has been severed + case FileBase::E_ISDIR: + // Is a directory + ioErrorCode = IOErrorCode_NO_FILE; + break; + case FileBase::E_AGAIN: + // Operation would block + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_TIMEDOUT: + ioErrorCode = IOErrorCode_DEVICE_NOT_READY; + break; + case FileBase::E_NOLCK: // No record locks available + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_IO: // I/O error + case FileBase::E_BADF: // Bad file + case FileBase::E_FAULT: // Bad address + case FileBase::E_INTR: // function call was interrupted + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "an error occurred during opening a file", + xComProc); + } + else if( errorCode == TASKHANDLING_NONAMESET_INSERT_COMMAND || + errorCode == TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND ) + { + static constexpr OUString sTitle = u"Title"_ustr; + static constexpr OUString sContentType = u"ContentType"_ustr; + Sequence< OUString > aSeq{ (errorCode == TASKHANDLING_NONAMESET_INSERT_COMMAND) + ? sTitle + : sContentType }; + + aAny <<= MissingPropertiesException( + "a property is missing, necessary to create a content", + xComProc, + aSeq); + cancelCommandExecution(aAny,xEnv); + } + else if( errorCode == TASKHANDLING_FILESIZE_FOR_WRITE ) + { + switch( minorCode ) + { + case FileBase::E_INVAL: + // the format of the parameters was not valid + case FileBase::E_OVERFLOW: + // The resulting file offset would be a value which cannot + // be represented correctly for regular files + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "there were problems with the filesize", + xComProc); + } + else if(errorCode == TASKHANDLING_INPUTSTREAM_FOR_WRITE) + { + aAny <<= + MissingInputStreamException( + "the inputstream is missing, necessary to create a content", + xComProc); + cancelCommandExecution(aAny,xEnv); + } + else if( errorCode == TASKHANDLING_NOREPLACE_FOR_WRITE ) + // Overwrite = false and file exists + { + NameClashException excep("file exists and overwrite forbidden", + Reference<XInterface>(xComProc, UNO_QUERY), + InteractionClassification_ERROR, OUString(getTitle(aUncPath))); + cancelCommandExecution( Any(excep), xEnv ); + } + else if( errorCode == TASKHANDLING_INVALID_NAME_MKDIR ) + { + PropertyValue prop; + prop.Name = "ResourceName"; + prop.Handle = -1; + OUString aClashingName( + rtl::Uri::decode( + OUString(getTitle(aUncPath)), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8)); + prop.Value <<= aClashingName; + InteractiveAugmentedIOException excep( + "the name contained invalid characters", Reference<XInterface>(xComProc, UNO_QUERY), + InteractionClassification_ERROR, IOErrorCode_INVALID_CHARACTER, { Any(prop) }); + if(isHandled) + throw excep; + cancelCommandExecution( Any(excep), xEnv ); +// ioErrorCode = IOErrorCode_INVALID_CHARACTER; +// cancelCommandExecution( +// ioErrorCode, +// generateErrorArguments(aUncPath), +// xEnv, +// OUString( "the name contained invalid characters"), +// xComProc ); + } + else if( errorCode == TASKHANDLING_FOLDER_EXISTS_MKDIR ) + { + NameClashException excep("folder exists and overwrite forbidden", xComProc, + InteractionClassification_ERROR, OUString(getTitle(aUncPath))); + if(isHandled) + throw excep; + cancelCommandExecution( Any(excep), xEnv ); +// ioErrorCode = IOErrorCode_ALREADY_EXISTING; +// cancelCommandExecution( +// ioErrorCode, +// generateErrorArguments(aUncPath), +// xEnv, +// OUString( "the folder exists"), +// xComProc ); + } + else if( errorCode == TASKHANDLING_ENSUREDIR_FOR_WRITE || + errorCode == TASKHANDLING_CREATEDIRECTORY_MKDIR ) + { + switch( minorCode ) + { + case FileBase::E_ACCES: + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_ROFS: + ioErrorCode = IOErrorCode_WRITE_PROTECTED; + break; + case FileBase::E_NAMETOOLONG: + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + default: + ioErrorCode = IOErrorCode_NOT_EXISTING_PATH; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(getParentName(aUncPath)), + //TODO! ok to supply physical URL to getParentName()? + xEnv, + "a folder could not be created", + xComProc ); + } + else if( errorCode == TASKHANDLING_VALIDFILESTATUSWHILE_FOR_REMOVE || + errorCode == TASKHANDLING_VALIDFILESTATUS_FOR_REMOVE || + errorCode == TASKHANDLING_NOSUCHFILEORDIR_FOR_REMOVE ) + { + switch( minorCode ) + { + case FileBase::E_INVAL: // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_NOMEM: // not enough memory for allocating structures + ioErrorCode = IOErrorCode_OUT_OF_MEMORY; + break; + case FileBase::E_ROFS: // #i4735# handle ROFS transparently as ACCESS_DENIED + case FileBase::E_ACCES: // permission denied + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_MFILE: // too many open files used by the process + case FileBase::E_NFILE: // too many open files in the system + ioErrorCode = IOErrorCode_OUT_OF_FILE_HANDLES; + break; + case FileBase::E_NOLINK: // Link has been severed + case FileBase::E_NOENT: // No such file or directory + ioErrorCode = IOErrorCode_NOT_EXISTING; + break; + case FileBase::E_NAMETOOLONG: // File name too long + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + case FileBase::E_NOTDIR: // A component of the path prefix of path is not a directory + ioErrorCode = IOErrorCode_NOT_EXISTING_PATH; + break; + case FileBase::E_LOOP: // Too many symbolic links encountered + case FileBase::E_IO: // I/O error + case FileBase::E_MULTIHOP: // Multihop attempted + case FileBase::E_FAULT: // Bad address + case FileBase::E_INTR: // function call was interrupted + case FileBase::E_NOSYS: // Function not implemented + case FileBase::E_NOSPC: // No space left on device + case FileBase::E_NXIO: // No such device or address + case FileBase::E_OVERFLOW: // Value too large for defined data type + case FileBase::E_BADF: // Invalid oslDirectoryItem parameter + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "a file status object could not be filled", + xComProc ); + } + else if( errorCode == TASKHANDLING_DELETEFILE_FOR_REMOVE || + errorCode == TASKHANDLING_DELETEDIRECTORY_FOR_REMOVE ) + { + switch( minorCode ) + { + case FileBase::E_INVAL: // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_NOMEM: // not enough memory for allocating structures + ioErrorCode = IOErrorCode_OUT_OF_MEMORY; + break; + case FileBase::E_ACCES: // Permission denied + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_PERM: // Operation not permitted + ioErrorCode = IOErrorCode_NOT_SUPPORTED; + break; + case FileBase::E_NAMETOOLONG: // File name too long + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + case FileBase::E_NOLINK: // Link has been severed + case FileBase::E_NOENT: // No such file or directory + ioErrorCode = IOErrorCode_NOT_EXISTING; + break; + case FileBase::E_ISDIR: // Is a directory + case FileBase::E_ROFS: // Read-only file system + ioErrorCode = IOErrorCode_NOT_SUPPORTED; + break; + case FileBase::E_BUSY: // Device or resource busy + ioErrorCode = IOErrorCode_LOCKING_VIOLATION; + break; + case FileBase::E_FAULT: // Bad address + case FileBase::E_LOOP: // Too many symbolic links encountered + case FileBase::E_IO: // I/O error + case FileBase::E_INTR: // function call was interrupted + case FileBase::E_MULTIHOP: // Multihop attempted + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "a file or directory could not be deleted", + xComProc ); + } + else if( errorCode == TASKHANDLING_TRANSFER_BY_COPY_SOURCE || + errorCode == TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT || + errorCode == TASKHANDLING_TRANSFER_BY_MOVE_SOURCE || + errorCode == TASKHANDLING_TRANSFER_BY_MOVE_SOURCESTAT || + errorCode == TASKHANDLING_TRANSFER_DESTFILETYPE || + errorCode == TASKHANDLING_FILETYPE_FOR_REMOVE || + errorCode == TASKHANDLING_DIRECTORYEXHAUSTED_FOR_REMOVE || + errorCode == TASKHANDLING_TRANSFER_INVALIDURL ) + { + OUString aMsg; + switch( minorCode ) + { + case FileBase::E_NOENT: // No such file or directory + if ( errorCode == TASKHANDLING_TRANSFER_BY_COPY_SOURCE || + errorCode == TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT || + errorCode == TASKHANDLING_TRANSFER_BY_MOVE_SOURCE || + errorCode == TASKHANDLING_TRANSFER_BY_MOVE_SOURCESTAT ) + { + ioErrorCode = IOErrorCode_NOT_EXISTING; + aMsg = "source file/folder does not exist"; + break; + } + else + { + ioErrorCode = IOErrorCode_GENERAL; + aMsg = "a general error during transfer command"; + break; + } + default: + ioErrorCode = IOErrorCode_GENERAL; + aMsg = "a general error during transfer command"; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + aMsg, + xComProc ); + } + else if( errorCode == TASKHANDLING_TRANSFER_ACCESSINGROOT ) + { + ioErrorCode = IOErrorCode_WRITE_PROTECTED; + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + "accessing the root during transfer", + xComProc ); + } + else if( errorCode == TASKHANDLING_TRANSFER_INVALIDSCHEME ) + { + aAny <<= InteractiveBadTransferURLException( + "bad transfer url", + xComProc); + cancelCommandExecution( aAny,xEnv ); + } + else if( errorCode == TASKHANDLING_OVERWRITE_FOR_MOVE || + errorCode == TASKHANDLING_OVERWRITE_FOR_COPY || + errorCode == TASKHANDLING_NAMECLASHMOVE_FOR_MOVE || + errorCode == TASKHANDLING_NAMECLASHMOVE_FOR_COPY || + errorCode == TASKHANDLING_KEEPERROR_FOR_MOVE || + errorCode == TASKHANDLING_KEEPERROR_FOR_COPY || + errorCode == TASKHANDLING_RENAME_FOR_MOVE || + errorCode == TASKHANDLING_RENAME_FOR_COPY || + errorCode == TASKHANDLING_RENAMEMOVE_FOR_MOVE || + errorCode == TASKHANDLING_RENAMEMOVE_FOR_COPY ) + { + OUString aMsg( + "general error during transfer"); + + switch( minorCode ) + { + case FileBase::E_EXIST: + ioErrorCode = IOErrorCode_ALREADY_EXISTING; + break; + case FileBase::E_INVAL: // the format of the parameters was not valid + ioErrorCode = IOErrorCode_INVALID_PARAMETER; + break; + case FileBase::E_NOMEM: // not enough memory for allocating structures + ioErrorCode = IOErrorCode_OUT_OF_MEMORY; + break; + case FileBase::E_ACCES: // Permission denied + ioErrorCode = IOErrorCode_ACCESS_DENIED; + break; + case FileBase::E_PERM: // Operation not permitted + ioErrorCode = IOErrorCode_NOT_SUPPORTED; + break; + case FileBase::E_NAMETOOLONG: // File name too long + ioErrorCode = IOErrorCode_NAME_TOO_LONG; + break; + case FileBase::E_NOENT: // No such file or directory + ioErrorCode = IOErrorCode_NOT_EXISTING; + aMsg = "file/folder does not exist"; + break; + case FileBase::E_ROFS: // Read-only file system<p> + ioErrorCode = IOErrorCode_NOT_EXISTING; + break; + default: + ioErrorCode = IOErrorCode_GENERAL; + break; + } + cancelCommandExecution( + ioErrorCode, + generateErrorArguments(aUncPath), + xEnv, + aMsg, + xComProc ); + } + else if( errorCode == TASKHANDLING_NAMECLASH_FOR_COPY || + errorCode == TASKHANDLING_NAMECLASH_FOR_MOVE ) + { + NameClashException excep("name clash during copy or move", + Reference<XInterface>(xComProc, UNO_QUERY), + InteractionClassification_ERROR, OUString(getTitle(aUncPath))); + + cancelCommandExecution(Any(excep), xEnv); + } + else if( errorCode == TASKHANDLING_NAMECLASHSUPPORT_FOR_MOVE || + errorCode == TASKHANDLING_NAMECLASHSUPPORT_FOR_COPY ) + { + UnsupportedNameClashException excep( + "name clash value not supported during copy or move", + Reference<XInterface>(xComProc, UNO_QUERY), minorCode); + + cancelCommandExecution(Any(excep), xEnv); + } + else + { + // case TASKHANDLER_NO_ERROR: + return; + } + } + + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filglob.hxx b/ucb/source/ucp/file/filglob.hxx new file mode 100644 index 0000000000..c113f62ecb --- /dev/null +++ b/ucb/source/ucp/file/filglob.hxx @@ -0,0 +1,95 @@ +/* -*- 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 <string_view> + +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> + + +namespace fileaccess { + + class BaseContent; + + /******************************************************************************/ + /* */ + /* Helper functions */ + /* */ + /******************************************************************************/ + + + // Returns true if dstUnqPath is a child from srcUnqPath or both are equal + + extern bool isChild( std::u16string_view srcUnqPath, + std::u16string_view dstUnqPath ); + + + // Changes the prefix in name + extern OUString newName( std::u16string_view aNewPrefix, + std::u16string_view aOldPrefix, + std::u16string_view old_Name ); + + // returns the last part of the given url as title + extern std::u16string_view getTitle( std::u16string_view aPath ); + + // returns the url without last part as parentname + // In case aFileName is root ( file:/// ) root is returned + + extern OUString getParentName( std::u16string_view aFileName ); + + /** + * special copy: + * On test = true, the implementation determines whether the + * destination exists and returns the appropriate errorcode E_EXIST. + * osl::File::copy copies unchecked. + */ + + extern osl::FileBase::RC osl_File_copy( const OUString& strPath, + const OUString& strDestPath, + bool test ); + + /** + * special move: + * On test = true, the implementation determines whether the + * destination exists and returns the appropriate errorcode E_EXIST. + * osl::File::move moves unchecked + */ + + extern osl::FileBase::RC osl_File_move( const OUString& strPath, + const OUString& strDestPath, + bool test = false ); + + // This function implements the global exception handler of the file_ucp; + // It never returns; + + extern void throw_handler( sal_Int32 errorCode, + sal_Int32 minorCode, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xEnv, + const OUString& aUncPath, + BaseContent* pContent, + bool isHandled); + // the physical URL of the object + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filid.cxx b/ucb/source/ucp/file/filid.cxx new file mode 100644 index 0000000000..d42fd194d6 --- /dev/null +++ b/ucb/source/ucp/file/filid.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "filid.hxx" +#include "filtask.hxx" + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::ucb; + + +FileContentIdentifier::FileContentIdentifier( + const OUString& aUnqPath, + bool IsNormalized ) +{ + if( IsNormalized ) + { + fileaccess::TaskManager::getUrlFromUnq( aUnqPath,m_aContentId ); + } + else + { + m_aContentId = aUnqPath; + } + TaskManager::getScheme( m_aProviderScheme ); +} + +FileContentIdentifier::~FileContentIdentifier() +{ +} + +OUString +SAL_CALL +FileContentIdentifier::getContentIdentifier() +{ + return m_aContentId; +} + + +OUString SAL_CALL +FileContentIdentifier::getContentProviderScheme() +{ + return m_aProviderScheme; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filid.hxx b/ucb/source/ucp/file/filid.hxx new file mode 100644 index 0000000000..dcb5449b0e --- /dev/null +++ b/ucb/source/ucp/file/filid.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/ucb/XContentIdentifier.hpp> + +namespace fileaccess { + + class TaskManager; + + class FileContentIdentifier : + public cppu::WeakImplHelper<css::ucb::XContentIdentifier> + { + + // This implementation has to be reworked + public: + FileContentIdentifier( const OUString& aUnqPath, + bool IsNormalized = true ); + + virtual ~FileContentIdentifier() override; + + // XContentIdentifier + virtual OUString SAL_CALL + getContentIdentifier() override; + + virtual OUString SAL_CALL + getContentProviderScheme() override; + + private: + OUString m_aContentId; // The URL string + OUString m_aProviderScheme; + }; + +} // end namespace fileaccess + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filinl.hxx b/ucb/source/ucp/file/filinl.hxx new file mode 100644 index 0000000000..3ea985ebc6 --- /dev/null +++ b/ucb/source/ucp/file/filinl.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 "filtask.hxx" + +using namespace fileaccess; + +inline const bool& TaskManager::MyProperty::IsNative() const +{ + return isNative; +} +inline const sal_Int32& TaskManager::MyProperty::getHandle() const +{ + return Handle; +} +inline const css::uno::Type& TaskManager::MyProperty::getType() const +{ + return Typ; +} +inline const css::uno::Any& TaskManager::MyProperty::getValue() const +{ + return Value; +} +inline const css::beans::PropertyState& TaskManager::MyProperty::getState() const +{ + return State; +} +inline const sal_Int16& TaskManager::MyProperty::getAttributes() const +{ + return Attributes; +} +inline void TaskManager::MyProperty::setValue( css::uno::Any theValue ) const +{ + const_cast<MyProperty*>(this)->Value = std::move(theValue); +} +inline void TaskManager::MyProperty::setState( const css::beans::PropertyState& theState ) const +{ + const_cast<MyProperty*>(this)->State = theState; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filinpstr.cxx b/ucb/source/ucp/file/filinpstr.cxx new file mode 100644 index 0000000000..5838dcda39 --- /dev/null +++ b/ucb/source/ucp/file/filinpstr.cxx @@ -0,0 +1,165 @@ +/* -*- 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/lang/IllegalArgumentException.hpp> + +#include "filinpstr.hxx" +#include "filerror.hxx" + +using namespace fileaccess; +using namespace com::sun::star; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +XInputStream_impl::XInputStream_impl( const OUString& aUncPath, bool bLock ) + : m_aFile( aUncPath ), + m_nErrorCode( TASKHANDLER_NO_ERROR ), + m_nMinorErrorCode( TASKHANDLER_NO_ERROR ) +{ + sal_uInt32 nFlags = osl_File_OpenFlag_Read; + if ( !bLock ) + nFlags |= osl_File_OpenFlag_NoLock; + + osl::FileBase::RC err = m_aFile.open( nFlags ); + if( err != osl::FileBase::E_None ) + { + m_nIsOpen = false; + m_aFile.close(); + + m_nErrorCode = TASKHANDLING_OPEN_FOR_INPUTSTREAM; + m_nMinorErrorCode = err; + } + else + m_nIsOpen = true; +} + + +XInputStream_impl::~XInputStream_impl() +{ + try + { + closeInput(); + } + catch (io::IOException const &) + { + OSL_FAIL("unexpected situation"); + } + catch (uno::RuntimeException const &) + { + OSL_FAIL("unexpected situation"); + } +} + +sal_Int32 SAL_CALL +XInputStream_impl::readBytes( + uno::Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) +{ + if( ! m_nIsOpen ) throw io::IOException( THROW_WHERE ); + + aData.realloc(nBytesToRead); + //TODO! translate memory exhaustion (if it were detectable...) into + // io::BufferSizeExceededException + + sal_uInt64 nrc(0); + if(m_aFile.read( aData.getArray(),sal_uInt64(nBytesToRead),nrc ) + != osl::FileBase::E_None) + throw io::IOException( THROW_WHERE ); + + // Shrink aData in case we read less than nBytesToRead (XInputStream + // documentation does not tell whether this is required, and I do not know + // if any code relies on this, so be conservative---SB): + if (sal::static_int_cast<sal_Int32>(nrc) != nBytesToRead) + aData.realloc(sal_Int32(nrc)); + return static_cast<sal_Int32>(nrc); +} + +sal_Int32 SAL_CALL +XInputStream_impl::readSomeBytes( + uno::Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead ) +{ + return readBytes( aData,nMaxBytesToRead ); +} + + +void SAL_CALL +XInputStream_impl::skipBytes( sal_Int32 nBytesToSkip ) +{ + m_aFile.setPos( osl_Pos_Current, sal_uInt64( nBytesToSkip ) ); +} + + +sal_Int32 SAL_CALL +XInputStream_impl::available() +{ + sal_Int64 avail = getLength() - getPosition(); + return std::min<sal_Int64>(avail, SAL_MAX_INT32); +} + + +void SAL_CALL +XInputStream_impl::closeInput() +{ + if( m_nIsOpen ) + { + osl::FileBase::RC err = m_aFile.close(); + if( err != osl::FileBase::E_None ) + throw io::IOException( THROW_WHERE ); + m_nIsOpen = false; + } +} + + +void SAL_CALL +XInputStream_impl::seek( sal_Int64 location ) +{ + if( location < 0 ) + throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 ); + if( osl::FileBase::E_None != m_aFile.setPos( osl_Pos_Absolut, sal_uInt64( location ) ) ) + throw io::IOException( THROW_WHERE ); +} + + +sal_Int64 SAL_CALL +XInputStream_impl::getPosition() +{ + sal_uInt64 uPos; + if( osl::FileBase::E_None != m_aFile.getPos( uPos ) ) + throw io::IOException( THROW_WHERE ); + return sal_Int64( uPos ); +} + +sal_Int64 SAL_CALL +XInputStream_impl::getLength() +{ + sal_uInt64 uEndPos; + if ( m_aFile.getSize(uEndPos) != osl::FileBase::E_None ) + throw io::IOException( THROW_WHERE ); + return sal_Int64( uEndPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filinpstr.hxx b/ucb/source/ucp/file/filinpstr.hxx new file mode 100644 index 0000000000..971872fdbb --- /dev/null +++ b/ucb/source/ucp/file/filinpstr.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XInputStream.hpp> + +#include "filrec.hxx" + +namespace fileaccess { + + class TaskManager; + + class XInputStream_impl final + : public cppu::WeakImplHelper<css::io::XInputStream, css::io::XSeekable> + { + public: + + XInputStream_impl( const OUString& aUncPath, bool bLock ); + + virtual ~XInputStream_impl() override; + + /** + * Returns an error code as given by filerror.hxx + */ + + sal_Int32 CtorSuccess() const { return m_nErrorCode;} + sal_Int32 getMinorError() const { return m_nMinorErrorCode;} + + 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; + + virtual void SAL_CALL + seek( sal_Int64 location ) override; + + virtual sal_Int64 SAL_CALL + getPosition() override; + + virtual sal_Int64 SAL_CALL + getLength() override; + + private: + + bool m_nIsOpen; + + ReconnectingFile m_aFile; + + sal_Int32 m_nErrorCode; + sal_Int32 m_nMinorErrorCode; + }; +} // end namespace XInputStream_impl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filinsreq.cxx b/ucb/source/ucp/file/filinsreq.cxx new file mode 100644 index 0000000000..0b8ebfb539 --- /dev/null +++ b/ucb/source/ucp/file/filinsreq.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "filinsreq.hxx" +#include "filtask.hxx" + +#include <comphelper/interaction.hxx> + +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + + +using namespace cppu; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::task; +using namespace com::sun::star::ucb; +using namespace com::sun::star::beans; +using namespace fileaccess; + + +XInteractionRequestImpl::XInteractionRequestImpl( + const OUString& aClashingName, + const Reference<XInterface>& xOrigin, + TaskManager *pShell,sal_Int32 CommandId) + : p1( new XInteractionSupplyNameImpl ), + p2( new XInteractionAbortImpl ), + m_xOrigin(xOrigin) +{ + sal_Int32 nErrorCode(0), nMinorError(0); + if( pShell ) + pShell->retrieveError(CommandId,nErrorCode,nMinorError); + std::vector<uno::Reference<task::XInteractionContinuation>> continuations{ + Reference<XInteractionContinuation>(p1), + Reference<XInteractionContinuation>(p2) }; + Any aAny; + if(nErrorCode == TASKHANDLING_FOLDER_EXISTS_MKDIR) + { + NameClashException excep("folder exists and overwrite forbidden", m_xOrigin, + InteractionClassification_ERROR, aClashingName); + aAny <<= excep; + } + else if(nErrorCode == TASKHANDLING_INVALID_NAME_MKDIR) + { + PropertyValue prop; + prop.Name = "ResourceName"; + prop.Handle = -1; + prop.Value <<= aClashingName; + InteractiveAugmentedIOException excep("the name contained invalid characters", m_xOrigin, + InteractionClassification_ERROR, + IOErrorCode_INVALID_CHARACTER, { Any(prop) }); + aAny <<= excep; + + } + m_xRequest.set(new ::comphelper::OInteractionRequest(aAny, std::move(continuations))); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filinsreq.hxx b/ucb/source/ucp/file/filinsreq.hxx new file mode 100644 index 0000000000..7f2e59a4c9 --- /dev/null +++ b/ucb/source/ucp/file/filinsreq.hxx @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/ucb/XInteractionSupplyName.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <cppuhelper/implbase.hxx> + + +namespace fileaccess { + + + class TaskManager; + + +class XInteractionSupplyNameImpl : public cppu::WeakImplHelper< + css::ucb::XInteractionSupplyName > + { + public: + + XInteractionSupplyNameImpl() + : m_bSelected(false) + { + } + + virtual void SAL_CALL select() override + { + m_bSelected = true; + } + + void SAL_CALL setName(const OUString& Name) override + { + m_aNewName = Name; + } + + const OUString& getName() const + { + return m_aNewName; + } + + bool isSelected() const + { + return m_bSelected; + } + + private: + + bool m_bSelected; + OUString m_aNewName; + }; + + + class XInteractionAbortImpl : public cppu::WeakImplHelper< + css::task::XInteractionAbort > + { + public: + + XInteractionAbortImpl() + : m_bSelected(false) + { + } + + virtual void SAL_CALL select() override + { + m_bSelected = true; + } + + + bool isSelected() const + { + return m_bSelected; + } + + private: + + bool m_bSelected; + }; + + + class XInteractionRequestImpl + { + public: + + XInteractionRequestImpl( + const OUString& aClashingName, + const css::uno::Reference< css::uno::XInterface>& xOrigin, + TaskManager* pShell, + sal_Int32 CommandId); + + bool aborted() const + { + return p2->isSelected(); + } + + OUString newName() const + { + if( p1->isSelected() ) + return p1->getName(); + else + return OUString(); + } + + css::uno::Reference<css::task::XInteractionRequest> const& getRequest() const + { + return m_xRequest; + } + + private: + + XInteractionSupplyNameImpl* p1; + XInteractionAbortImpl* p2; + + css::uno::Reference<css::task::XInteractionRequest> m_xRequest; + + css::uno::Reference< css::uno::XInterface> m_xOrigin; + }; + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filnot.cxx b/ucb/source/ucp/file/filnot.cxx new file mode 100644 index 0000000000..d384dc0ea7 --- /dev/null +++ b/ucb/source/ucp/file/filnot.cxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/ucb/ContentAction.hpp> +#include <com/sun/star/beans/PropertySetInfoChange.hpp> +#include <rtl/ref.hxx> +#include "filnot.hxx" +#include "filid.hxx" +#include "bc.hxx" +#include "prov.hxx" + + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::ucb; + + +ContentEventNotifier::ContentEventNotifier( TaskManager* pMyShell, + const uno::Reference< XContent >& xCreatorContent, + const uno::Reference< XContentIdentifier >& xCreatorId, + std::vector< uno::Reference< ucb::XContentEventListener > >&& sListeners ) + : m_pMyShell( pMyShell ), + m_xCreatorContent( xCreatorContent ), + m_xCreatorId( xCreatorId ), + m_sListeners( std::move(sListeners) ) +{ +} + + +ContentEventNotifier::ContentEventNotifier( TaskManager* pMyShell, + const uno::Reference< XContent >& xCreatorContent, + const uno::Reference< XContentIdentifier >& xCreatorId, + const uno::Reference< XContentIdentifier >& xOldId, + std::vector< uno::Reference< ucb::XContentEventListener > >&& sListeners ) + : m_pMyShell( pMyShell ), + m_xCreatorContent( xCreatorContent ), + m_xCreatorId( xCreatorId ), + m_xOldId( xOldId ), + m_sListeners( std::move(sListeners) ) +{ +} + + +void ContentEventNotifier::notifyChildInserted( const OUString& aChildName ) const +{ + rtl::Reference<FileContentIdentifier> xChildId = new FileContentIdentifier( aChildName ); + + uno::Reference< XContent > xChildContent = m_pMyShell->m_pProvider->queryContent( xChildId ); + + ContentEvent aEvt( m_xCreatorContent, + ContentAction::INSERTED, + xChildContent, + m_xCreatorId ); + + for( const auto& ref : m_sListeners ) + ref->contentEvent( aEvt ); +} + +void ContentEventNotifier::notifyDeleted() const +{ + ContentEvent aEvt( m_xCreatorContent, + ContentAction::DELETED, + m_xCreatorContent, + m_xCreatorId ); + + + for( const auto& ref : m_sListeners ) + ref->contentEvent( aEvt ); +} + + +void ContentEventNotifier::notifyRemoved( const OUString& aChildName ) const +{ + rtl::Reference<FileContentIdentifier> xChildId = new FileContentIdentifier( aChildName ); + + rtl::Reference<BaseContent> pp = new BaseContent( m_pMyShell,xChildId,aChildName ); + { + std::unique_lock aGuard( pp->m_aMutex ); + pp->m_nState |= BaseContent::Deleted; + } + + ContentEvent aEvt( m_xCreatorContent, + ContentAction::REMOVED, + pp, + m_xCreatorId ); + + for( const auto& ref : m_sListeners ) + ref->contentEvent( aEvt ); +} + +void ContentEventNotifier::notifyExchanged() const +{ + ContentEvent aEvt( m_xCreatorContent, + ContentAction::EXCHANGED, + m_xCreatorContent, + m_xOldId ); + + for( const auto& ref : m_sListeners ) + ref->contentEvent( aEvt ); +} + +/*********************************************************************************/ +/* */ +/* PropertySetInfoChangeNotifier */ +/* */ +/*********************************************************************************/ + + +PropertySetInfoChangeNotifier::PropertySetInfoChangeNotifier( + const uno::Reference< XContent >& xCreatorContent, + std::vector< uno::Reference< beans::XPropertySetInfoChangeListener > >&& sListeners ) + : m_xCreatorContent( xCreatorContent ), + m_sListeners( std::move(sListeners) ) +{ + +} + + +void +PropertySetInfoChangeNotifier::notifyPropertyAdded( const OUString & aPropertyName ) const +{ + beans::PropertySetInfoChangeEvent aEvt( m_xCreatorContent, + aPropertyName, + -1, + beans::PropertySetInfoChange::PROPERTY_INSERTED ); + + for( const auto& ref : m_sListeners ) + ref->propertySetInfoChange( aEvt ); +} + + +void +PropertySetInfoChangeNotifier::notifyPropertyRemoved( const OUString & aPropertyName ) const +{ + beans::PropertySetInfoChangeEvent aEvt( m_xCreatorContent, + aPropertyName, + -1, + beans::PropertySetInfoChange::PROPERTY_REMOVED ); + + for( const auto& ref : m_sListeners ) + ref->propertySetInfoChange( aEvt ); +} + + +/*********************************************************************************/ +/* */ +/* PropertySetInfoChangeNotifier */ +/* */ +/*********************************************************************************/ + + +PropertyChangeNotifier::PropertyChangeNotifier( + const css::uno::Reference< XContent >& xCreatorContent, + ListenerMap&& pListeners ) + : m_xCreatorContent( xCreatorContent ), + m_aListeners( std::move(pListeners) ) +{ +} + + +void PropertyChangeNotifier::notifyPropertyChanged( + const uno::Sequence< beans::PropertyChangeEvent >& seqChanged ) const +{ + uno::Sequence< beans::PropertyChangeEvent > Changes = seqChanged; + + for( auto& rChange : asNonConstRange(Changes) ) + rChange.Source = m_xCreatorContent; + + // notify listeners for all Events + + auto it = m_aListeners.find( OUString() ); + if (it != m_aListeners.end()) + { + const std::vector< uno::Reference< beans::XPropertiesChangeListener > >& seqList = it->second; + for( const auto& rListener : seqList ) + rListener->propertiesChange( Changes ); + } + + for( const auto& rChange : std::as_const(Changes) ) + { + uno::Sequence< beans::PropertyChangeEvent > seq{ rChange }; + it = m_aListeners.find( rChange.PropertyName ); + if (it != m_aListeners.end()) + { + const std::vector< uno::Reference< beans::XPropertiesChangeListener > >& seqList = it->second; + for( const auto& rListener : seqList ) + rListener->propertiesChange( seq ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filnot.hxx b/ucb/source/ucp/file/filnot.hxx new file mode 100644 index 0000000000..898a57dd03 --- /dev/null +++ b/ucb/source/ucp/file/filnot.hxx @@ -0,0 +1,116 @@ +/* -*- 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/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/beans/XPropertySetInfoChangeListener.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/ucb/XContentIdentifier.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <optional> +#include <unordered_map> +#include <vector> + +namespace fileaccess { + + class TaskManager; + + class ContentEventNotifier + { + private: + TaskManager* m_pMyShell; + css::uno::Reference< css::ucb::XContent > m_xCreatorContent; + css::uno::Reference< css::ucb::XContentIdentifier > m_xCreatorId; + css::uno::Reference< css::ucb::XContentIdentifier > m_xOldId; + std::vector< css::uno::Reference< css::ucb::XContentEventListener > > m_sListeners; + public: + + ContentEventNotifier( + TaskManager* pMyShell, + const css::uno::Reference< css::ucb::XContent >& xCreatorContent, + const css::uno::Reference< css::ucb::XContentIdentifier >& xCreatorId, + std::vector< css::uno::Reference< css::ucb::XContentEventListener > >&& sListeners ); + + ContentEventNotifier( + TaskManager* pMyShell, + const css::uno::Reference< css::ucb::XContent >& xCreatorContent, + const css::uno::Reference< css::ucb::XContentIdentifier >& xCreatorId, + const css::uno::Reference< css::ucb::XContentIdentifier >& xOldId, + std::vector< css::uno::Reference< css::ucb::XContentEventListener > >&& sListeners ); + + void notifyChildInserted( const OUString& aChildName ) const; + void notifyDeleted() const; + void notifyRemoved( const OUString& aChildName ) const; + void notifyExchanged() const; + }; + + + class PropertySetInfoChangeNotifier + { + private: + css::uno::Reference< css::ucb::XContent > m_xCreatorContent; + std::vector< css::uno::Reference< css::beans::XPropertySetInfoChangeListener > > m_sListeners; + public: + PropertySetInfoChangeNotifier( + const css::uno::Reference< css::ucb::XContent >& xCreatorContent, + std::vector< css::uno::Reference< css::beans::XPropertySetInfoChangeListener > >&& sListeners ); + + void notifyPropertyAdded( const OUString & aPropertyName ) const; + void notifyPropertyRemoved( const OUString & aPropertyName ) const; + }; + + + typedef std::unordered_map< OUString, + std::vector< css::uno::Reference< css::beans::XPropertiesChangeListener > > > ListenerMap; + + class PropertyChangeNotifier + { + private: + css::uno::Reference< css::ucb::XContent > m_xCreatorContent; + ListenerMap m_aListeners; + public: + PropertyChangeNotifier( + const css::uno::Reference< css::ucb::XContent >& xCreatorContent, + ListenerMap&& pListeners ); + + void notifyPropertyChanged( + const css::uno::Sequence< css::beans::PropertyChangeEvent >& seqChanged ) const; + }; + + + class Notifier + { + public: + // Side effect of this function is the change of the name + virtual std::optional<ContentEventNotifier> cEXC( const OUString& aNewName ) = 0; + // Side effect is the change of the state of the object to "deleted". + virtual std::optional<ContentEventNotifier> cDEL() = 0; + virtual std::optional<ContentEventNotifier> cCEL() = 0; + virtual std::optional<PropertySetInfoChangeNotifier> cPSL() = 0; + virtual std::optional<PropertyChangeNotifier> cPCL() = 0; + + protected: + ~Notifier() {} + }; + + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filprp.cxx b/ucb/source/ucp/file/filprp.cxx new file mode 100644 index 0000000000..ed352a9e9a --- /dev/null +++ b/ucb/source/ucp/file/filprp.cxx @@ -0,0 +1,94 @@ +/* -*- 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 "filtask.hxx" +#include "prov.hxx" +#include "filprp.hxx" +#include "filinl.hxx" + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; + +XPropertySetInfo_impl::XPropertySetInfo_impl( TaskManager* pMyShell,const OUString& aUnqPath ) + : m_pMyShell( pMyShell ), + m_seq( 0 ) +{ + m_pMyShell->m_pProvider->acquire(); + + TaskManager::ContentMap::iterator it = m_pMyShell->m_aContent.find( aUnqPath ); + + TaskManager::PropertySet& properties = it->second.properties; + + m_seq.realloc( properties.size() ); + auto p_seq = m_seq.getArray(); + + sal_Int32 count = 0; + for( const auto& rProp : properties ) + { + p_seq[ count++ ] = beans::Property( rProp.getPropertyName(), + rProp.getHandle(), + rProp.getType(), + rProp.getAttributes() ); + } +} + + +XPropertySetInfo_impl::XPropertySetInfo_impl( TaskManager* pMyShell,const Sequence< beans::Property >& seq ) + : m_pMyShell( pMyShell ), + m_seq( seq ) +{ + m_pMyShell->m_pProvider->acquire(); +} + + +XPropertySetInfo_impl::~XPropertySetInfo_impl() +{ + m_pMyShell->m_pProvider->release(); +} + + +beans::Property SAL_CALL +XPropertySetInfo_impl::getPropertyByName( const OUString& aName ) +{ + auto pProp = std::find_if(std::cbegin(m_seq), std::cend(m_seq), + [&aName](const beans::Property& rProp) { return rProp.Name == aName; }); + if (pProp != std::cend(m_seq)) + return *pProp; + + throw beans::UnknownPropertyException( aName ); +} + + +Sequence< beans::Property > SAL_CALL +XPropertySetInfo_impl::getProperties() +{ + return m_seq; +} + + +sal_Bool SAL_CALL +XPropertySetInfo_impl::hasPropertyByName( const OUString& aName ) +{ + return std::any_of(std::cbegin(m_seq), std::cend(m_seq), + [&aName](const beans::Property& rProp) { return rProp.Name == aName; }); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filprp.hxx b/ucb/source/ucp/file/filprp.hxx new file mode 100644 index 0000000000..4fef247d29 --- /dev/null +++ b/ucb/source/ucp/file/filprp.hxx @@ -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 . + */ +#pragma once + +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <cppuhelper/implbase.hxx> + + +namespace fileaccess { + + class TaskManager; + +class XPropertySetInfo_impl : public cppu::WeakImplHelper< + css::beans::XPropertySetInfo > + { + public: + XPropertySetInfo_impl( TaskManager* pMyShell,const OUString& aUnqPath ); + XPropertySetInfo_impl( TaskManager* pMyShell,const css::uno::Sequence< css::beans::Property >& seq ); + + virtual ~XPropertySetInfo_impl() override; + + virtual css::uno::Sequence< css::beans::Property > SAL_CALL + getProperties() override; + + virtual css::beans::Property SAL_CALL + getPropertyByName( const OUString& aName ) override; + + virtual sal_Bool SAL_CALL + hasPropertyByName( const OUString& Name ) override; + + private: + TaskManager* m_pMyShell; + css::uno::Sequence< css::beans::Property > m_seq; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrec.cxx b/ucb/source/ucp/file/filrec.cxx new file mode 100644 index 0000000000..5af520bc35 --- /dev/null +++ b/ucb/source/ucp/file/filrec.cxx @@ -0,0 +1,192 @@ +/* -*- 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 "filrec.hxx" + +namespace fileaccess { + +void ReconnectingFile::disconnect() +{ + m_aFile.close(); + m_bDisconnect = true; +} + +bool ReconnectingFile::reconnect() +{ + bool bResult = false; + if ( m_bFlagsSet ) + { + disconnect(); + if ( m_aFile.open( m_nFlags ) == ::osl::FileBase::E_None + || m_aFile.open( osl_File_OpenFlag_Read ) == ::osl::FileBase::E_None ) + { + m_bDisconnect = false; + bResult = true; + } + } + + return bResult; +} + +::osl::FileBase::RC ReconnectingFile::open( sal_uInt32 uFlags ) +{ + ::osl::FileBase::RC nResult = m_aFile.open( uFlags ); + if ( nResult == ::osl::FileBase::E_None ) + { + if ( uFlags & osl_File_OpenFlag_Create ) + m_nFlags = (uFlags & ( ~osl_File_OpenFlag_Create )) | osl_File_OpenFlag_Write; + else + m_nFlags = uFlags; + + m_bFlagsSet = true; + } + + return nResult; +} + +::osl::FileBase::RC ReconnectingFile::close() +{ + m_nFlags = 0; + m_bFlagsSet = false; + m_bDisconnect = false; + + return m_aFile.close(); +} + +::osl::FileBase::RC ReconnectingFile::setPos( sal_uInt32 uHow, sal_Int64 uPos ) +{ + ::osl::FileBase::RC nRes = ::osl::FileBase::E_NETWORK; + + if ( uHow == osl_Pos_Absolut && uPos > 0 ) + { + if ( m_bDisconnect ) + { + if ( reconnect() ) + nRes = m_aFile.setPos( uHow, uPos ); + } + else + { + // E_INVAL error code means in this case that + // the file handler is invalid + nRes = m_aFile.setPos( uHow, uPos ); + if ( ( nRes == ::osl::FileBase::E_NETWORK + || nRes == ::osl::FileBase::E_INVAL ) + && reconnect() ) + nRes = m_aFile.setPos( uHow, uPos ); + } + } + else + { + if ( !m_bDisconnect ) + nRes = m_aFile.setPos( uHow, uPos ); + } + + return nRes; +} + +::osl::FileBase::RC ReconnectingFile::getPos( sal_uInt64& uPos ) +{ + if ( m_bDisconnect ) + return ::osl::FileBase::E_NETWORK; + + return m_aFile.getPos( uPos ); +} + +::osl::FileBase::RC ReconnectingFile::setSize( sal_uInt64 uSize ) +{ + ::osl::FileBase::RC nRes = ::osl::FileBase::E_NETWORK; + + if ( uSize == 0 ) + { + if ( m_bDisconnect ) + { + if ( reconnect() ) + nRes = m_aFile.setSize( uSize ); + } + else + { + // E_INVAL error code means in this case that + // the file handler is invalid + nRes = m_aFile.setSize( uSize ); + if ( ( nRes == ::osl::FileBase::E_NETWORK + || nRes == ::osl::FileBase::E_INVAL ) + && reconnect() ) + nRes = m_aFile.setSize( uSize ); + } + } + else + { + if ( !m_bDisconnect ) + nRes = m_aFile.setSize( uSize ); + } + + return nRes; +} + +::osl::FileBase::RC ReconnectingFile::getSize( sal_uInt64 &rSize ) +{ + ::osl::FileBase::RC nRes = ::osl::FileBase::E_NETWORK; + + if ( !m_bDisconnect ) + nRes = m_aFile.getSize( rSize ); + + // E_INVAL error code means in this case that + // the file handler is invalid + if ( ( nRes == ::osl::FileBase::E_NETWORK + || nRes == ::osl::FileBase::E_INVAL ) + && reconnect() ) + { + nRes = m_aFile.getSize( rSize ); + + // the repairing should be disconnected, since the position might be wrong + // but the result should be retrieved + disconnect(); + } + + return nRes; +} + +::osl::FileBase::RC ReconnectingFile::read( void *pBuffer, sal_uInt64 uBytesRequested, sal_uInt64& rBytesRead ) +{ + if ( m_bDisconnect ) + return ::osl::FileBase::E_NETWORK; + + return m_aFile.read( pBuffer, uBytesRequested, rBytesRead ); +} + +::osl::FileBase::RC ReconnectingFile::write(const void *pBuffer, sal_uInt64 uBytesToWrite, sal_uInt64& rBytesWritten) +{ + if ( m_bDisconnect ) + return ::osl::FileBase::E_NETWORK; + + return m_aFile.write( pBuffer, uBytesToWrite, rBytesWritten ); +} + +::osl::FileBase::RC ReconnectingFile::sync() const +{ + if ( m_bDisconnect ) + return ::osl::FileBase::E_NETWORK; + + return m_aFile.sync(); +} + +} // namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrec.hxx b/ucb/source/ucp/file/filrec.hxx new file mode 100644 index 0000000000..552aedc7db --- /dev/null +++ b/ucb/source/ucp/file/filrec.hxx @@ -0,0 +1,76 @@ +/* -*- 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 <osl/file.hxx> + +namespace fileaccess { + +class ReconnectingFile +{ + ::osl::File m_aFile; + + sal_uInt32 m_nFlags; + bool m_bFlagsSet; + + bool m_bDisconnect; + + ReconnectingFile( ReconnectingFile const & ) = delete; + ReconnectingFile& operator=( ReconnectingFile const & ) = delete; + +public: + + explicit ReconnectingFile( const OUString& aFileURL ) + : m_aFile( aFileURL ) + , m_nFlags( 0 ) + , m_bFlagsSet( false ) + , m_bDisconnect( false ) + {} + + ~ReconnectingFile() + { + close(); + } + + void disconnect(); + bool reconnect(); + + ::osl::FileBase::RC open( sal_uInt32 uFlags ); + + ::osl::FileBase::RC close(); + + ::osl::FileBase::RC setPos( sal_uInt32 uHow, sal_Int64 uPos ); + + ::osl::FileBase::RC getPos( sal_uInt64& uPos ); + + ::osl::FileBase::RC setSize( sal_uInt64 uSize ); + + ::osl::FileBase::RC getSize( sal_uInt64 &rSize ); + + ::osl::FileBase::RC read( void *pBuffer, sal_uInt64 uBytesRequested, sal_uInt64& rBytesRead ); + + ::osl::FileBase::RC write(const void *pBuffer, sal_uInt64 uBytesToWrite, sal_uInt64& rBytesWritten); + + ::osl::FileBase::RC sync() const; +}; + +} // namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrow.cxx b/ucb/source/ucp/file/filrow.cxx new file mode 100644 index 0000000000..e352e79199 --- /dev/null +++ b/ucb/source/ucp/file/filrow.cxx @@ -0,0 +1,293 @@ +/* -*- 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 "filrow.hxx" +#include "filtask.hxx" +#include <com/sun/star/script/CannotConvertException.hpp> +#include <com/sun/star/script/Converter.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> + +using namespace fileaccess; +using namespace com::sun::star; +using namespace css::uno; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +// Function for TypeConverting + +template< class _type_ > +static bool convert( TaskManager const * pShell, + uno::Reference< script::XTypeConverter >& xConverter, + const uno::Any& rValue, + _type_& aReturn ) +{ + // Try first without converting + bool no_success = ! ( rValue >>= aReturn ); + + if ( no_success ) + { + if( ! xConverter.is() ) + { + xConverter = script::Converter::create(pShell->m_xContext); + } + + try + { + if( rValue.hasValue() ) + { + uno::Any aConvertedValue + = xConverter->convertTo( rValue,cppu::UnoType<_type_>::get() ); + no_success = ! ( aConvertedValue >>= aReturn ); + } + else + no_success = true; + } + catch (const lang::IllegalArgumentException&) + { + no_success = true; + } + catch (const script::CannotConvertException&) + { + no_success = true; + } + } + return no_success; +} + + +XRow_impl::XRow_impl( TaskManager* pMyShell,const uno::Sequence< uno::Any >& seq ) + : m_aValueMap( seq ), + m_nWasNull(false), + m_pMyShell( pMyShell ) +{ +} + +XRow_impl::~XRow_impl() +{ +} + + +sal_Bool SAL_CALL +XRow_impl::wasNull() +{ + return m_nWasNull; +} + + +OUString SAL_CALL +XRow_impl::getString( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<OUString>(columnIndex); +} + +sal_Bool SAL_CALL +XRow_impl::getBoolean( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<bool>(columnIndex); +} + + +sal_Int8 SAL_CALL +XRow_impl::getByte( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<sal_Int8>(columnIndex); +} + +sal_Int16 SAL_CALL +XRow_impl::getShort( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<sal_Int16>(columnIndex); +} + + +sal_Int32 SAL_CALL +XRow_impl::getInt( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<sal_Int32>(columnIndex); +} + +sal_Int64 SAL_CALL +XRow_impl::getLong( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<sal_Int64>(columnIndex); +} + +float SAL_CALL +XRow_impl::getFloat( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<float>(columnIndex); +} + +double SAL_CALL +XRow_impl::getDouble( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<double>(columnIndex); +} + +uno::Sequence< sal_Int8 > SAL_CALL +XRow_impl::getBytes( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Sequence< sal_Int8 >>(columnIndex); +} + +util::Date SAL_CALL +XRow_impl::getDate( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<util::Date>(columnIndex); +} + +util::Time SAL_CALL +XRow_impl::getTime( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<util::Time>(columnIndex); +} + +util::DateTime SAL_CALL +XRow_impl::getTimestamp( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<util::DateTime>(columnIndex); +} + + +uno::Reference< io::XInputStream > SAL_CALL +XRow_impl::getBinaryStream( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< io::XInputStream >>(columnIndex); +} + + +uno::Reference< io::XInputStream > SAL_CALL +XRow_impl::getCharacterStream( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< io::XInputStream >>(columnIndex); +} + + +uno::Any SAL_CALL +XRow_impl::getObject( + sal_Int32 columnIndex, + const uno::Reference< container::XNameAccess >& ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + std::scoped_lock aGuard( m_aMutex ); + uno::Any Value = m_aValueMap[columnIndex - 1]; + m_nWasNull = !Value.hasValue(); + return Value; +} + +uno::Reference< sdbc::XRef > SAL_CALL +XRow_impl::getRef( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< sdbc::XRef >>(columnIndex); +} + +uno::Reference< sdbc::XBlob > SAL_CALL +XRow_impl::getBlob( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< sdbc::XBlob >>(columnIndex); +} + +uno::Reference< sdbc::XClob > SAL_CALL +XRow_impl::getClob( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< sdbc::XClob >>(columnIndex); +} + + +uno::Reference< sdbc::XArray > SAL_CALL +XRow_impl::getArray( + sal_Int32 columnIndex ) +{ + if( isIndexOutOfBounds( columnIndex ) ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + return getValue<uno::Reference< sdbc::XArray >>(columnIndex); +} + +bool +XRow_impl::isIndexOutOfBounds(sal_Int32 nIndex) const +{ + return nIndex < 1 || m_aValueMap.getLength() < nIndex; +} + +template<typename T> +T XRow_impl::getValue(sal_Int32 columnIndex) +{ + T aValue{}; + std::scoped_lock aGuard( m_aMutex ); + m_nWasNull = ::convert<T>( m_pMyShell, m_xTypeConverter, m_aValueMap[ --columnIndex ], aValue ); + return aValue; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrow.hxx b/ucb/source/ucp/file/filrow.hxx new file mode 100644 index 0000000000..1a33565a6a --- /dev/null +++ b/ucb/source/ucp/file/filrow.hxx @@ -0,0 +1,114 @@ +/* -*- 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/sdbc/XRow.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <cppuhelper/implbase.hxx> +#include <mutex> + +namespace fileaccess { + + class TaskManager; + + class XRow_impl: public cppu::WeakImplHelper< + css::sdbc::XRow > + { + public: + XRow_impl( TaskManager* pShell,const css::uno::Sequence< css::uno::Any >& aValueMap ); + virtual ~XRow_impl() override; + + virtual sal_Bool SAL_CALL + wasNull() override; + + virtual OUString SAL_CALL + getString( sal_Int32 columnIndex ) override; + + virtual sal_Bool SAL_CALL + getBoolean( sal_Int32 columnIndex ) override; + + virtual sal_Int8 SAL_CALL + getByte( sal_Int32 columnIndex ) override; + + virtual sal_Int16 SAL_CALL + getShort( sal_Int32 columnIndex ) override; + + virtual sal_Int32 SAL_CALL + getInt( sal_Int32 columnIndex ) override; + + virtual sal_Int64 SAL_CALL + getLong( sal_Int32 columnIndex ) override; + + virtual float SAL_CALL + getFloat( sal_Int32 columnIndex ) override; + + virtual double SAL_CALL + getDouble( + sal_Int32 columnIndex ) override; + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes( sal_Int32 columnIndex ) override; + + virtual css::util::Date SAL_CALL + getDate( sal_Int32 columnIndex ) override; + + virtual css::util::Time SAL_CALL + getTime( sal_Int32 columnIndex ) override; + + virtual css::util::DateTime SAL_CALL + getTimestamp( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream( sal_Int32 columnIndex ) override; + + virtual css::uno::Any SAL_CALL + getObject( + sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL + getRef( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL + getBlob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL + getClob( sal_Int32 columnIndex ) override; + + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL + getArray( sal_Int32 columnIndex ) override; + + private: + std::mutex m_aMutex; + css::uno::Sequence< css::uno::Any > m_aValueMap; + bool m_nWasNull; + TaskManager* m_pMyShell; + css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter; + + bool isIndexOutOfBounds( sal_Int32 nIndex ) const; + template<typename T> + T getValue(sal_Int32 columnIndex); + }; + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrset.cxx b/ucb/source/ucp/file/filrset.cxx new file mode 100644 index 0000000000..2990df183b --- /dev/null +++ b/ucb/source/ucp/file/filrset.cxx @@ -0,0 +1,679 @@ +/* -*- 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 <sal/log.hxx> + +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/ucb/ListenerAlreadySetException.hpp> +#include <com/sun/star/ucb/ServiceNotFoundException.hpp> +#include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp> +#include "filid.hxx" +#include "filtask.hxx" +#include "filprp.hxx" +#include "filrset.hxx" +#include <com/sun/star/ucb/OpenMode.hpp> +#include "prov.hxx" +#include <com/sun/star/uno/Reference.h> + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/ucb/ListActionType.hpp> +#include <com/sun/star/ucb/XSourceInitialization.hpp> +#include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp> +#include <ucbhelper/resultsetmetadata.hxx> + +using namespace fileaccess; +using namespace com::sun::star; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +XResultSet_impl::XResultSet_impl( TaskManager* pMyShell, + const OUString& aUnqPath, + sal_Int32 OpenMode, + const uno::Sequence< beans::Property >& seq, + const uno::Sequence< ucb::NumberedSortingInfo >& seqSort ) + : m_pMyShell( pMyShell ) + , m_nRow( -1 ) + , m_nWasNull ( false ) + , m_nOpenMode( OpenMode ) + , m_bRowCountFinal( false ) + , m_aBaseDirectory( aUnqPath ) + , m_aFolder( aUnqPath ) + , m_sProperty( seq ) + , m_sSortingInfo( seqSort ) + , m_nErrorCode( TASKHANDLER_NO_ERROR ) + , m_nMinorErrorCode( TASKHANDLER_NO_ERROR ) +{ + osl::FileBase::RC err = m_aFolder.open(); + if( err != osl::FileBase::E_None ) + { + m_nIsOpen = false; + m_aFolder.close(); + + m_nErrorCode = TASKHANDLING_OPEN_FOR_DIRECTORYLISTING; + m_nMinorErrorCode = err; + } + else + m_nIsOpen = true; +} + + +XResultSet_impl::~XResultSet_impl() +{ + if( m_nIsOpen ) + m_aFolder.close(); +} + + +void SAL_CALL +XResultSet_impl::disposing( const lang::EventObject& ) +{ + // To do, but what +} + + +void SAL_CALL +XResultSet_impl::addEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.addInterface( aGuard, Listener ); +} + + +void SAL_CALL +XResultSet_impl::removeEventListener( + const uno::Reference< lang::XEventListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + m_aDisposeEventListeners.removeInterface( aGuard, Listener ); +} + + +void SAL_CALL +XResultSet_impl::dispose() +{ + std::unique_lock aGuard( m_aMutex ); + + lang::EventObject aEvt; + aEvt.Source = static_cast< lang::XComponent * >( this ); + + m_aDisposeEventListeners.disposeAndClear( aGuard, aEvt ); + m_aRowCountListeners.disposeAndClear( aGuard, aEvt ); + m_aIsFinalListeners.disposeAndClear( aGuard, aEvt ); +} + + +void XResultSet_impl::rowCountChanged(std::unique_lock<std::mutex>& rGuard) +{ + sal_Int32 aOldValue,aNewValue; + std::vector< uno::Reference< beans::XPropertyChangeListener > > seq = m_aRowCountListeners.getElements(rGuard); + aNewValue = m_aItems.size(); + aOldValue = aNewValue-1; + beans::PropertyChangeEvent aEv; + aEv.PropertyName = "RowCount"; + aEv.Further = false; + aEv.PropertyHandle = -1; + aEv.OldValue <<= aOldValue; + aEv.NewValue <<= aNewValue; + for( const auto& listener : seq ) + listener->propertyChange( aEv ); +} + + +void XResultSet_impl::isFinalChanged() +{ + std::vector< uno::Reference< beans::XPropertyChangeListener > > seq; + { + std::unique_lock aGuard( m_aMutex ); + seq = m_aIsFinalListeners.getElements(aGuard); + m_bRowCountFinal = true; + } + beans::PropertyChangeEvent aEv; + aEv.PropertyName = "IsRowCountFinal"; + aEv.Further = false; + aEv.PropertyHandle = -1; + aEv.OldValue <<= false; + aEv.NewValue <<= true; + for( const auto& listener : seq ) + listener->propertyChange( aEv ); +} + + +bool +XResultSet_impl::OneMore() +{ + if( ! m_nIsOpen ) + return false; + + osl::FileBase::RC err; + bool IsRegular; + OUString aUnqPath; + osl::DirectoryItem aDirIte; + uno::Reference< sdbc::XRow > aRow; + + while( true ) + { + err = m_aFolder.getNextItem( aDirIte ); + + if( err == osl::FileBase::E_NOENT || err == osl::FileBase::E_INVAL ) + { + m_aFolder.close(); + isFinalChanged(); + m_nIsOpen = false; + return m_nIsOpen; + } + else if( err == osl::FileBase::E_None ) + { + if (!m_pMyShell->getv( m_sProperty, aDirIte, aUnqPath, IsRegular, aRow )) + { + SAL_WARN( + "ucb.ucp.file", + "getting dir item in <" << m_aBaseDirectory << "> failed"); + continue; + } + + if( m_nOpenMode == ucb::OpenMode::DOCUMENTS && IsRegular ) + { + std::unique_lock aGuard( m_aMutex ); + m_aItems.push_back( aRow ); + m_aIdents.emplace_back( ); + m_aUnqPath.push_back( aUnqPath ); + rowCountChanged(aGuard); + return true; + + } + else if( m_nOpenMode == ucb::OpenMode::DOCUMENTS && ! IsRegular ) + { + continue; + } + else if( m_nOpenMode == ucb::OpenMode::FOLDERS && ! IsRegular ) + { + std::unique_lock aGuard( m_aMutex ); + m_aItems.push_back( aRow ); + m_aIdents.emplace_back( ); + m_aUnqPath.push_back( aUnqPath ); + rowCountChanged(aGuard); + return true; + } + else if( m_nOpenMode == ucb::OpenMode::FOLDERS && IsRegular ) + { + continue; + } + else + { + std::unique_lock aGuard( m_aMutex ); + m_aItems.push_back( aRow ); + m_aIdents.emplace_back( ); + m_aUnqPath.push_back( aUnqPath ); + rowCountChanged(aGuard); + return true; + } + } + else // error fetching anything + { + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + } + } +} + + +sal_Bool SAL_CALL +XResultSet_impl::next() +{ + bool test; + if( ++m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) test = true; + else + test = OneMore(); + return test; +} + + +sal_Bool SAL_CALL +XResultSet_impl::isBeforeFirst() +{ + return m_nRow == -1; +} + + +sal_Bool SAL_CALL +XResultSet_impl::isAfterLast() +{ + return m_nRow >= sal::static_int_cast<sal_Int32>(m_aItems.size()); // Cannot happen, if m_aFolder.isOpen() +} + + +sal_Bool SAL_CALL +XResultSet_impl::isFirst() +{ + return m_nRow == 0; +} + + +sal_Bool SAL_CALL +XResultSet_impl::isLast() +{ + if( m_nRow == sal::static_int_cast<sal_Int32>(m_aItems.size()) - 1 ) + return ! OneMore(); + else + return false; +} + + +void SAL_CALL +XResultSet_impl::beforeFirst() +{ + m_nRow = -1; +} + + +void SAL_CALL +XResultSet_impl::afterLast() +{ + m_nRow = sal::static_int_cast<sal_Int32>(m_aItems.size()); + while( OneMore() ) + ++m_nRow; +} + + +sal_Bool SAL_CALL +XResultSet_impl::first() +{ + m_nRow = -1; + return next(); +} + + +sal_Bool SAL_CALL +XResultSet_impl::last() +{ + m_nRow = sal::static_int_cast<sal_Int32>(m_aItems.size()) - 1; + while( OneMore() ) + ++m_nRow; + return true; +} + + +sal_Int32 SAL_CALL +XResultSet_impl::getRow() +{ + // Test, whether behind last row + if( -1 == m_nRow || m_nRow >= sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return 0; + else + return m_nRow+1; +} + + +sal_Bool SAL_CALL XResultSet_impl::absolute( sal_Int32 row ) +{ + if( row >= 0 ) + { + m_nRow = row - 1; + if( row >= sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + while( row-- && OneMore() ) + ; + } + else + { + last(); + m_nRow += ( row + 1 ); + if( m_nRow < -1 ) + m_nRow = -1; + } + + return 0<= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +sal_Bool SAL_CALL +XResultSet_impl::relative( sal_Int32 row ) +{ + if( isAfterLast() || isBeforeFirst() ) + throw sdbc::SQLException( THROW_WHERE, uno::Reference< uno::XInterface >(), OUString(), 0, uno::Any() ); + if( row > 0 ) + while( row-- ) next(); + else if( row < 0 ) + while( row++ && m_nRow > - 1 ) previous(); + + return 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +sal_Bool SAL_CALL +XResultSet_impl::previous() +{ + if( m_nRow > sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + m_nRow = sal::static_int_cast<sal_Int32>(m_aItems.size()); // Correct Handling of afterLast + if( 0 <= m_nRow ) -- m_nRow; + + return 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()); +} + + +void SAL_CALL +XResultSet_impl::refreshRow() +{ + // get the row from the filesystem +} + + +sal_Bool SAL_CALL +XResultSet_impl::rowUpdated() +{ + return false; +} + +sal_Bool SAL_CALL +XResultSet_impl::rowInserted() +{ + return false; +} + +sal_Bool SAL_CALL +XResultSet_impl::rowDeleted() +{ + return false; +} + + +uno::Reference< uno::XInterface > SAL_CALL +XResultSet_impl::getStatement() +{ + return uno::Reference< uno::XInterface >(); +} + + +// XCloseable + +void SAL_CALL +XResultSet_impl::close() +{ + if( m_nIsOpen ) + { + m_aFolder.close(); + isFinalChanged(); + std::unique_lock aGuard( m_aMutex ); + m_nIsOpen = false; + } +} + + +OUString SAL_CALL +XResultSet_impl::queryContentIdentifierString() +{ + uno::Reference< ucb::XContentIdentifier > xContentId + = queryContentIdentifier(); + + if( xContentId.is() ) + return xContentId->getContentIdentifier(); + else + return OUString(); +} + + +uno::Reference< ucb::XContentIdentifier > SAL_CALL +XResultSet_impl::queryContentIdentifier() +{ + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + { + if( ! m_aIdents[m_nRow].is() ) + { + m_aIdents[m_nRow].set( new FileContentIdentifier( m_aUnqPath[ m_nRow ] ) ); + } + return m_aIdents[m_nRow]; + } + return uno::Reference< ucb::XContentIdentifier >(); +} + + +uno::Reference< ucb::XContent > SAL_CALL +XResultSet_impl::queryContent() +{ + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_pMyShell->m_pProvider->queryContent( queryContentIdentifier() ); + else + return uno::Reference< ucb::XContent >(); +} + + +// XDynamicResultSet + + +// virtual +uno::Reference< sdbc::XResultSet > SAL_CALL +XResultSet_impl::getStaticResultSet() +{ + std::unique_lock aGuard( m_aMutex ); + + if ( m_xListener.is() ) + throw ucb::ListenerAlreadySetException( THROW_WHERE ); + + return uno::Reference< sdbc::XResultSet >( this ); +} + + +// virtual +void SAL_CALL +XResultSet_impl::setListener( + const uno::Reference< ucb::XDynamicResultSetListener >& Listener ) +{ + std::unique_lock aGuard( m_aMutex ); + + if ( m_xListener.is() ) + throw ucb::ListenerAlreadySetException( THROW_WHERE ); + + m_xListener = Listener; + + + // Create "welcome event" and send it to listener. + + + // Note: We only have the implementation for a static result set at the + // moment (src590). The dynamic result sets passed to the listener + // are a fake. This implementation will never call "notify" at the + // listener to propagate any changes!!! + + uno::Any aInfo; + aInfo <<= ucb::WelcomeDynamicResultSetStruct( this, /* "old" */ + this /* "new" */ ); + + uno::Sequence< ucb::ListAction > aActions( 1 ); + aActions.getArray()[ 0 ] = ucb::ListAction( 0, // Position; not used + 0, // Count; not used + ucb::ListActionType::WELCOME, + aInfo ); + aGuard.unlock(); + + Listener->notify( + ucb::ListEvent( + getXWeak(), aActions ) ); +} + + +// virtual +void SAL_CALL +XResultSet_impl::connectToCache( + const uno::Reference< ucb::XDynamicResultSet > & xCache ) +{ + if( m_xListener.is() ) + throw ucb::ListenerAlreadySetException( THROW_WHERE ); + + uno::Reference< ucb::XSourceInitialization > xTarget( + xCache, uno::UNO_QUERY ); + if( xTarget.is() && m_pMyShell->m_xContext.is() ) + { + uno::Reference< ucb::XCachedDynamicResultSetStubFactory > xStubFactory; + try + { + xStubFactory + = ucb::CachedDynamicResultSetStubFactory::create( + m_pMyShell->m_xContext ); + } + catch ( uno::Exception const & ) + { + } + + if( xStubFactory.is() ) + { + xStubFactory->connectToCache( + this, xCache,m_sSortingInfo, nullptr ); + return; + } + } + throw ucb::ServiceNotFoundException( THROW_WHERE ); +} + + +// virtual +sal_Int16 SAL_CALL +XResultSet_impl::getCapabilities() +{ + // Never set ucb::ContentResultSetCapability::SORTED + // - Underlying content cannot provide sorted data... + return 0; +} + +// XResultSetMetaDataSupplier +uno::Reference< sdbc::XResultSetMetaData > SAL_CALL +XResultSet_impl::getMetaData() +{ + auto pProp = std::find_if(std::cbegin(m_sProperty), std::cend(m_sProperty), + [](const beans::Property& rProp) { return rProp.Name == "Title"; }); + if (pProp != std::cend(m_sProperty)) + { + std::vector< ::ucbhelper::ResultSetColumnData > + aColumnData( m_sProperty.getLength() ); + auto n = std::distance(std::cbegin(m_sProperty), pProp); + // @@@ #82177# - Determine correct value! + aColumnData[ n ].isCaseSensitive = false; + + return new ::ucbhelper::ResultSetMetaData( + m_pMyShell->m_xContext, + m_sProperty, + std::move(aColumnData) ); + } + + return new ::ucbhelper::ResultSetMetaData( m_pMyShell->m_xContext, m_sProperty ); +} + + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +XResultSet_impl::getPropertySetInfo() +{ + + uno::Sequence< beans::Property > seq + { + { "RowCount", -1, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY }, + { "IsRowCountFinal", -1, cppu::UnoType<sal_Bool>::get(), beans::PropertyAttribute::READONLY } + }; + + return new XPropertySetInfo_impl( m_pMyShell, seq ); +} + + +void SAL_CALL XResultSet_impl::setPropertyValue( + const OUString& aPropertyName, const uno::Any& ) +{ + if( aPropertyName == "IsRowCountFinal" || + aPropertyName == "RowCount" ) + return; + throw beans::UnknownPropertyException( aPropertyName ); +} + + +uno::Any SAL_CALL XResultSet_impl::getPropertyValue( + const OUString& PropertyName ) +{ + if( PropertyName == "IsRowCountFinal" ) + { + return uno::Any(m_bRowCountFinal); + } + else if ( PropertyName == "RowCount" ) + { + sal_Int32 count = sal::static_int_cast<sal_Int32>(m_aItems.size()); + return uno::Any(count); + } + else + throw beans::UnknownPropertyException( PropertyName ); +} + + +void SAL_CALL XResultSet_impl::addPropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& xListener ) +{ + if( aPropertyName == "IsRowCountFinal" ) + { + std::unique_lock aGuard( m_aMutex ); + + m_aIsFinalListeners.addInterface( aGuard, xListener ); + } + else if ( aPropertyName == "RowCount" ) + { + std::unique_lock aGuard( m_aMutex ); + + m_aRowCountListeners.addInterface( aGuard, xListener ); + } + else + throw beans::UnknownPropertyException( aPropertyName ); +} + + +void SAL_CALL XResultSet_impl::removePropertyChangeListener( + const OUString& aPropertyName, + const uno::Reference< beans::XPropertyChangeListener >& aListener ) +{ + if( aPropertyName == "IsRowCountFinal" ) + { + std::unique_lock aGuard( m_aMutex ); + + m_aIsFinalListeners.removeInterface( aGuard, aListener ); + } + else if ( aPropertyName == "RowCount" ) + { + std::unique_lock aGuard( m_aMutex ); + + m_aRowCountListeners.removeInterface( aGuard, aListener ); + } + else + throw beans::UnknownPropertyException( aPropertyName ); +} + +void SAL_CALL XResultSet_impl::addVetoableChangeListener( + const OUString&, + const uno::Reference< beans::XVetoableChangeListener >& ) +{ +} + + +void SAL_CALL XResultSet_impl::removeVetoableChangeListener( + const OUString&, + const uno::Reference< beans::XVetoableChangeListener >& ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filrset.hxx b/ucb/source/ucp/file/filrset.hxx new file mode 100644 index 0000000000..3361405dd5 --- /dev/null +++ b/ucb/source/ucp/file/filrset.hxx @@ -0,0 +1,434 @@ +/* -*- 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 <mutex> +#include <vector> +#include <osl/file.hxx> + +#include <comphelper/interfacecontainer4.hxx> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/sdbc/XCloseable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XDynamicResultSetListener.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/XContentIdentifier.hpp> +#include <com/sun/star/beans/Property.hpp> +#include "filrow.hxx" +#include <cppuhelper/implbase.hxx> + +namespace fileaccess { + +class XResultSet_impl : + public cppu::WeakImplHelper< css::lang::XEventListener, + css::sdbc::XRow, + css::sdbc::XResultSet, + css::ucb::XDynamicResultSet, + css::sdbc::XCloseable, + css::sdbc::XResultSetMetaDataSupplier, + css::beans::XPropertySet, + css::ucb::XContentAccess > + { + public: + + XResultSet_impl( TaskManager* pMyShell, + const OUString& aUnqPath, + sal_Int32 OpenMode, + const css::uno::Sequence< css::beans::Property >& seq, + const css::uno::Sequence< css::ucb::NumberedSortingInfo >& seqSort ); + + virtual ~XResultSet_impl() override; + + sal_Int32 CtorSuccess() const { return m_nErrorCode;} + sal_Int32 getMinorError() const { return m_nMinorErrorCode;} + + // XEventListener + virtual void SAL_CALL + disposing( const css::lang::EventObject& Source ) override; + + // XComponent + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( + const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + + // XRow + virtual sal_Bool SAL_CALL + wasNull() override + { + if( 0<= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + m_nWasNull = m_aItems[m_nRow]->wasNull(); + else + m_nWasNull = true; + return m_nWasNull; + } + + virtual OUString SAL_CALL + getString( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getString( columnIndex ); + else + return OUString(); + } + + virtual sal_Bool SAL_CALL + getBoolean( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBoolean( columnIndex ); + else + return false; + } + + virtual sal_Int8 SAL_CALL + getByte( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getByte( columnIndex ); + else + return sal_Int8( 0 ); + } + + virtual sal_Int16 SAL_CALL + getShort( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getShort( columnIndex ); + else + return sal_Int16( 0 ); + } + + virtual sal_Int32 SAL_CALL + getInt( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getInt( columnIndex ); + else + return 0; + } + + virtual sal_Int64 SAL_CALL + getLong( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getLong( columnIndex ); + else + return sal_Int64( 0 ); + } + + virtual float SAL_CALL + getFloat( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getFloat( columnIndex ); + else + return float( 0 ); + } + + virtual double SAL_CALL + getDouble( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getDouble( columnIndex ); + else + return double( 0 ); + } + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getBytes( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBytes( columnIndex ); + else + return css::uno::Sequence< sal_Int8 >(); + } + + virtual css::util::Date SAL_CALL + getDate( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getDate( columnIndex ); + else + return css::util::Date(); + } + + virtual css::util::Time SAL_CALL + getTime( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getTime( columnIndex ); + else + return css::util::Time(); + } + + virtual css::util::DateTime SAL_CALL + getTimestamp( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getTimestamp( columnIndex ); + else + return css::util::DateTime(); + } + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getBinaryStream( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBinaryStream( columnIndex ); + else + return css::uno::Reference< css::io::XInputStream >(); + } + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getCharacterStream( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getCharacterStream( columnIndex ); + else + return css::uno::Reference< css::io::XInputStream >(); + } + + virtual css::uno::Any SAL_CALL + getObject( sal_Int32 columnIndex, + const css::uno::Reference< css::container::XNameAccess >& typeMap ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getObject( columnIndex,typeMap ); + else + return css::uno::Any(); + } + + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL + getRef( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getRef( columnIndex ); + else + return css::uno::Reference< css::sdbc::XRef >(); + } + + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL + getBlob( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getBlob( columnIndex ); + else + return css::uno::Reference< css::sdbc::XBlob >(); + } + + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL + getClob( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getClob( columnIndex ); + else + return css::uno::Reference< css::sdbc::XClob >(); + } + + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL + getArray( sal_Int32 columnIndex ) override + { + if( 0 <= m_nRow && m_nRow < sal::static_int_cast<sal_Int32>(m_aItems.size()) ) + return m_aItems[m_nRow]->getArray( columnIndex ); + else + return css::uno::Reference< css::sdbc::XArray >(); + } + + + // XResultSet + + virtual sal_Bool SAL_CALL + next() override; + + virtual sal_Bool SAL_CALL + isBeforeFirst() override; + + virtual sal_Bool SAL_CALL + isAfterLast() override; + + virtual sal_Bool SAL_CALL + isFirst() override; + + virtual sal_Bool SAL_CALL + isLast() override; + + virtual void SAL_CALL + beforeFirst() override; + + virtual void SAL_CALL + afterLast() override; + + virtual sal_Bool SAL_CALL + first() override; + + virtual sal_Bool SAL_CALL + last() override; + + virtual sal_Int32 SAL_CALL + getRow() override; + + virtual sal_Bool SAL_CALL + absolute( sal_Int32 row ) override; + + virtual sal_Bool SAL_CALL + relative( sal_Int32 rows ) override; + + virtual sal_Bool SAL_CALL + previous() override; + + virtual void SAL_CALL + refreshRow() override; + + virtual sal_Bool SAL_CALL + rowUpdated() override; + + virtual sal_Bool SAL_CALL + rowInserted() override; + + virtual sal_Bool SAL_CALL + rowDeleted() override; + + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + getStatement() override; + + + // XDynamicResultSet + + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL + getStaticResultSet() override; + + virtual void SAL_CALL + setListener( + const css::uno::Reference< + css::ucb::XDynamicResultSetListener >& Listener ) override; + + virtual void SAL_CALL + connectToCache( const css::uno::Reference< css::ucb::XDynamicResultSet > & xCache ) override; + + virtual sal_Int16 SAL_CALL + getCapabilities() override; + + + // XCloseable + + virtual void SAL_CALL + close() override; + + // XContentAccess + + virtual OUString SAL_CALL + queryContentIdentifierString() override; + + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL + queryContentIdentifier() override; + + virtual css::uno::Reference< css::ucb::XContent > SAL_CALL + queryContent() override; + + // XResultSetMetaDataSupplier + virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL + getMetaData() override; + + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + virtual void SAL_CALL setPropertyValue( + const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + + virtual css::uno::Any SAL_CALL + getPropertyValue( + const OUString& PropertyName ) override; + + virtual void SAL_CALL + addPropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + + virtual void SAL_CALL + removePropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual void SAL_CALL + addVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + virtual void SAL_CALL removeVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + private: + + TaskManager* m_pMyShell; + bool m_nIsOpen; + sal_Int32 m_nRow; + bool m_nWasNull; + sal_Int32 m_nOpenMode; + bool m_bRowCountFinal; + + typedef std::vector< css::uno::Reference< css::ucb::XContentIdentifier > > IdentSet; + typedef std::vector< css::uno::Reference< css::sdbc::XRow > > ItemSet; + + IdentSet m_aIdents; + ItemSet m_aItems; + std::vector< OUString > m_aUnqPath; + const OUString m_aBaseDirectory; + + osl::Directory m_aFolder; + css::uno::Sequence< css::beans::Property > m_sProperty; + css::uno::Sequence< css::ucb::NumberedSortingInfo > m_sSortingInfo; + + std::mutex m_aMutex; + comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_aDisposeEventListeners; + comphelper::OInterfaceContainerHelper4<css::beans::XPropertyChangeListener> m_aRowCountListeners; + comphelper::OInterfaceContainerHelper4<css::beans::XPropertyChangeListener> m_aIsFinalListeners; + + css::uno::Reference< css::ucb::XDynamicResultSetListener > m_xListener; + + sal_Int32 m_nErrorCode; + sal_Int32 m_nMinorErrorCode; + + // Methods + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + bool OneMore(); + + void rowCountChanged(std::unique_lock<std::mutex>&); + void isFinalChanged(); + }; + + +} // end namespace fileaccess + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filstr.cxx b/ucb/source/ucp/file/filstr.cxx new file mode 100644 index 0000000000..70c235da7d --- /dev/null +++ b/ucb/source/ucp/file/filstr.cxx @@ -0,0 +1,288 @@ +/* -*- 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/IOException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <osl/diagnose.h> +#include "filstr.hxx" +#include "filerror.hxx" + +using namespace fileaccess; +using namespace com::sun::star; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +/******************************************************************************/ +/* */ +/* XStream_impl implementation */ +/* */ +/******************************************************************************/ + +XStream_impl::XStream_impl( const OUString& aUncPath, bool bLock ) + : m_bInputStreamCalled( false ), + m_bOutputStreamCalled( false ), + m_aFile( aUncPath ), + m_nErrorCode( TASKHANDLER_NO_ERROR ), + m_nMinorErrorCode( TASKHANDLER_NO_ERROR ) +{ + sal_uInt32 nFlags = ( osl_File_OpenFlag_Read | osl_File_OpenFlag_Write ); + if ( !bLock ) + nFlags |= osl_File_OpenFlag_NoLock; + + osl::FileBase::RC err = m_aFile.open( nFlags ); + if( err != osl::FileBase::E_None ) + { + m_nIsOpen = false; + m_aFile.close(); + + m_nErrorCode = TASKHANDLING_OPEN_FOR_STREAM; + m_nMinorErrorCode = err; + } + else + m_nIsOpen = true; +} + + +XStream_impl::~XStream_impl() +{ + try + { + closeStream(); + } + catch (const io::IOException&) + { + OSL_FAIL("unexpected situation"); + } + catch (const uno::RuntimeException&) + { + OSL_FAIL("unexpected situation"); + } +} + + +uno::Reference< io::XInputStream > SAL_CALL +XStream_impl::getInputStream( ) +{ + { + std::scoped_lock aGuard( m_aMutex ); + m_bInputStreamCalled = true; + } + return uno::Reference< io::XInputStream >( this ); +} + + +uno::Reference< io::XOutputStream > SAL_CALL +XStream_impl::getOutputStream( ) +{ + { + std::scoped_lock aGuard( m_aMutex ); + m_bOutputStreamCalled = true; + } + return uno::Reference< io::XOutputStream >( this ); +} + + +void SAL_CALL XStream_impl::truncate() +{ + if (osl::FileBase::E_None != m_aFile.setSize(0)) + throw io::IOException( THROW_WHERE ); + + if (osl::FileBase::E_None != m_aFile.setPos(osl_Pos_Absolut,sal_uInt64(0))) + throw io::IOException( THROW_WHERE ); +} + + +// XStream_impl private non interface methods + + +sal_Int32 SAL_CALL +XStream_impl::readBytes( + uno::Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) +{ + if( ! m_nIsOpen ) + throw io::IOException( THROW_WHERE ); + + try + { + aData.realloc(nBytesToRead); + } + catch (const std::bad_alloc&) + { + if( m_nIsOpen ) m_aFile.close(); + throw io::BufferSizeExceededException( THROW_WHERE ); + } + + sal_uInt64 nrc(0); + if(m_aFile.read( aData.getArray(), sal_uInt64(nBytesToRead), nrc ) + != osl::FileBase::E_None) + { + throw io::IOException( THROW_WHERE ); + } + if (nrc != static_cast<sal_uInt64>(nBytesToRead)) + aData.realloc(nrc); + return static_cast<sal_Int32>(nrc); +} + +sal_Int32 +XStream_impl::readSomeBytes( + sal_Int8* pData, + sal_Int32 nBytesToRead ) +{ + if( ! m_nIsOpen ) + throw io::IOException( THROW_WHERE ); + + sal_uInt64 nrc(0); + if(m_aFile.read( pData, sal_uInt64(nBytesToRead), nrc ) + != osl::FileBase::E_None) + { + throw io::IOException( THROW_WHERE ); + } + return static_cast<sal_Int32>(nrc); +} + +sal_Int32 SAL_CALL +XStream_impl::readSomeBytes( + uno::Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead ) +{ + return readBytes( aData,nMaxBytesToRead ); +} + + +void SAL_CALL +XStream_impl::skipBytes( sal_Int32 nBytesToSkip ) +{ + m_aFile.setPos( osl_Pos_Current, sal_uInt64( nBytesToSkip ) ); +} + + +sal_Int32 SAL_CALL +XStream_impl::available() +{ + sal_Int64 avail = getLength() - getPosition(); + return std::min<sal_Int64>(avail, SAL_MAX_INT32); +} + + +void SAL_CALL +XStream_impl::writeBytes( const uno::Sequence< sal_Int8 >& aData ) +{ + sal_uInt32 length = aData.getLength(); + if(length) + { + sal_uInt64 nWrittenBytes(0); + const sal_Int8* p = aData.getConstArray(); + if(osl::FileBase::E_None != m_aFile.write(static_cast<void const *>(p),sal_uInt64(length),nWrittenBytes) || + nWrittenBytes != length ) + throw io::IOException( THROW_WHERE ); + } +} + + +void +XStream_impl::closeStream() +{ + if( m_nIsOpen ) + { + osl::FileBase::RC err = m_aFile.close(); + + if( err != osl::FileBase::E_None ) { + throw io::IOException("could not close file"); + } + + m_nIsOpen = false; + } +} + +void SAL_CALL +XStream_impl::closeInput() +{ + std::scoped_lock aGuard( m_aMutex ); + m_bInputStreamCalled = false; + + if( ! m_bOutputStreamCalled ) + closeStream(); +} + + +void SAL_CALL +XStream_impl::closeOutput() +{ + std::scoped_lock aGuard( m_aMutex ); + m_bOutputStreamCalled = false; + + if( ! m_bInputStreamCalled ) + closeStream(); +} + + +void SAL_CALL +XStream_impl::seek( sal_Int64 location ) +{ + if( location < 0 ) + throw lang::IllegalArgumentException( THROW_WHERE, uno::Reference< uno::XInterface >(), 0 ); + if( osl::FileBase::E_None != m_aFile.setPos( osl_Pos_Absolut, sal_uInt64( location ) ) ) + throw io::IOException( THROW_WHERE ); +} + + +sal_Int64 SAL_CALL +XStream_impl::getPosition() +{ + sal_uInt64 uPos; + if( osl::FileBase::E_None != m_aFile.getPos( uPos ) ) + throw io::IOException( THROW_WHERE ); + return sal_Int64( uPos ); +} + +sal_Int64 SAL_CALL +XStream_impl::getLength() +{ + sal_uInt64 uEndPos; + if ( m_aFile.getSize(uEndPos) != osl::FileBase::E_None ) + throw io::IOException( THROW_WHERE ); + return sal_Int64( uEndPos ); +} + +void SAL_CALL +XStream_impl::flush() +{} + +void XStream_impl::waitForCompletion() +{ + // At least on UNIX, to reliably learn about any errors encountered by + // asynchronous NFS write operations, without closing the file directly + // afterwards, there appears to be no cheaper way than to call fsync: + if (m_nIsOpen && m_aFile.sync() != osl::FileBase::E_None) { + throw io::IOException( + "could not synchronize file to disc", + getXWeak()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filstr.hxx b/ucb/source/ucp/file/filstr.hxx new file mode 100644 index 0000000000..acef94aa8c --- /dev/null +++ b/ucb/source/ucp/file/filstr.hxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include <rtl/ustring.hxx> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XAsyncOutputMonitor.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <comphelper/bytereader.hxx> +#include <cppuhelper/implbase.hxx> +#include <mutex> + +#include "filrec.hxx" + +namespace fileaccess { + + // forward: + class TaskManager; + +class XStream_impl : public cppu::WeakImplHelper< + css::io::XStream, + css::io::XSeekable, + css::io::XInputStream, + css::io::XOutputStream, + css::io::XTruncate, + css::io::XAsyncOutputMonitor >, + public comphelper::ByteReader + { + + public: + + XStream_impl( const OUString& aUncPath, bool bLock ); + + /** + * Returns an error code as given by filerror.hxx + */ + + sal_Int32 CtorSuccess() const { return m_nErrorCode;} + sal_Int32 getMinorError() const { return m_nMinorErrorCode;} + + virtual ~XStream_impl() override; + + // XStream + + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL + getInputStream() override; + + virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL + getOutputStream() override; + + + // XTruncate + + virtual void SAL_CALL truncate() override; + + + // XInputStream + + sal_Int32 SAL_CALL + readBytes( + css::uno::Sequence< sal_Int8 >& aData, + sal_Int32 nBytesToRead ) override; + + sal_Int32 SAL_CALL + readSomeBytes( + css::uno::Sequence< sal_Int8 >& aData, + sal_Int32 nMaxBytesToRead ) override; + + + void SAL_CALL + skipBytes( sal_Int32 nBytesToSkip ) override; + + sal_Int32 SAL_CALL + available() override; + + void SAL_CALL + closeInput() override; + + // XSeekable + + void SAL_CALL + seek( sal_Int64 location ) override; + + sal_Int64 SAL_CALL + getPosition() override; + + sal_Int64 SAL_CALL + getLength() override; + + + // XOutputStream + + void SAL_CALL + writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override; + + + void SAL_CALL + flush() override; + + + void SAL_CALL + closeOutput() override; + + virtual void SAL_CALL waitForCompletion() override; + + // utl::ByteReader + virtual sal_Int32 + readSomeBytes( + sal_Int8* aData, + sal_Int32 nMaxBytesToRead ) override; + + private: + + std::mutex m_aMutex; + bool m_bInputStreamCalled,m_bOutputStreamCalled; + bool m_nIsOpen; + + ReconnectingFile m_aFile; + + sal_Int32 m_nErrorCode; + sal_Int32 m_nMinorErrorCode; + + // Implementation methods + + /// @throws css::io::NotConnectedException + /// @throws css::io::IOException + /// @throws css::uno::RuntimeException + void + closeStream(); + + }; + +} // end namespace XStream_impl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filtask.cxx b/ucb/source/ucp/file/filtask.cxx new file mode 100644 index 0000000000..930f952d00 --- /dev/null +++ b/ucb/source/ucp/file/filtask.cxx @@ -0,0 +1,2936 @@ +/* -*- 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 <config_features.h> + +#include <sal/config.h> +#include <sal/log.hxx> + +#if HAVE_FEATURE_MACOSX_SANDBOX +#include <sys/stat.h> +#endif + +#include <com/sun/star/beans/IllegalTypeException.hpp> +#include <com/sun/star/beans/NotRemoveableException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyExistException.hpp> +#include <com/sun/star/io/BufferSizeExceededException.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/lang/IllegalAccessException.hpp> +#include <com/sun/star/task/InteractionClassification.hpp> +#include <com/sun/star/ucb/ContentInfoAttribute.hpp> +#include <com/sun/star/ucb/DuplicateCommandIdentifierException.hpp> +#include <com/sun/star/ucb/IOErrorCode.hpp> +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/OpenCommandArgument.hpp> +#include <com/sun/star/ucb/Store.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <comphelper/propertysequence.hxx> +#include <rtl/ref.hxx> +#include <rtl/uri.hxx> + +#include "filtask.hxx" +#include "filcmd.hxx" +#include "filglob.hxx" +#include "filinpstr.hxx" +#include "filprp.hxx" +#include "filrset.hxx" +#include "filstr.hxx" +#include "prov.hxx" + +/******************************************************************************/ +/* */ +/* TaskHandling */ +/* */ +/******************************************************************************/ + + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +TaskManager::UnqPathData::UnqPathData() = default; + +TaskManager::UnqPathData::UnqPathData(TaskManager::UnqPathData&&) = default; + + +TaskManager::UnqPathData::~UnqPathData() +{ +} + +TaskManager::MyProperty::MyProperty( const OUString& thePropertyName ) + : PropertyName( thePropertyName ) + , Handle(-1) + , isNative(false) + , State(beans::PropertyState_AMBIGUOUS_VALUE) + , Attributes(0) +{ + // empty +} + +TaskManager::MyProperty::MyProperty( bool theisNative, + const OUString& thePropertyName, + sal_Int32 theHandle, + const css::uno::Type& theTyp, + const css::uno::Any& theValue, + const css::beans::PropertyState& theState, + sal_Int16 theAttributes ) + : PropertyName( thePropertyName ), + Handle( theHandle ), + isNative( theisNative ), + Typ( theTyp ), + Value( theValue ), + State( theState ), + Attributes( theAttributes ) +{ + // empty +} + +#include "filinl.hxx" + + // Default properties + +constexpr OUString Title( u"Title"_ustr ); +constexpr OUString CasePreservingURL( u"CasePreservingURL"_ustr ); +constexpr OUString IsDocument( u"IsDocument"_ustr ); +constexpr OUString IsFolder( u"IsFolder"_ustr ); +constexpr OUString DateModified( u"DateModified"_ustr ); +constexpr OUString Size( u"Size"_ustr ); +constexpr OUString IsVolume( u"IsVolume"_ustr ); +constexpr OUString IsRemoveable( u"IsRemoveable"_ustr ); +constexpr OUString IsRemote( u"IsRemote"_ustr ); +constexpr OUString IsCompactDisc( u"IsCompactDisc"_ustr ); +constexpr OUString IsFloppy( u"IsFloppy"_ustr ); +constexpr OUString IsHidden( u"IsHidden"_ustr ); +constexpr OUString ContentType( u"ContentType"_ustr ); +constexpr OUString IsReadOnly( u"IsReadOnly"_ustr ); +constexpr OUString CreatableContentsInfo( u"CreatableContentsInfo"_ustr ); + +TaskManager::TaskManager( const uno::Reference< uno::XComponentContext >& rxContext, + FileProvider* pProvider, bool bWithConfig ) + : m_nCommandId( 0 ), + m_pProvider( pProvider ), + m_xContext( rxContext ), + // Commands + m_sCommandInfo{ + { /* Name */ "getCommandInfo", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<void>::get() }, + + { /* Name */ "getPropertySetInfo", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<void>::get() }, + + { /* Name */ "getPropertyValues", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<uno::Sequence< beans::Property >>::get() }, + + { /* Name */ "setPropertyValues", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get() }, + + { /* Name */ "open", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<OpenCommandArgument>::get() }, + + { /* Name */ "transfer", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<TransferInfo>::get() }, + + { /* Name */ "delete", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<sal_Bool>::get() }, + + { /* Name */ "insert", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<InsertCommandArgument>::get() }, + + { /* Name */ "createNewContent", + /* Handle */ -1, + /* ArgType */ cppu::UnoType<ucb::ContentInfo>::get() } } +{ + // Title + m_aDefaultProperties.insert( MyProperty( true, + Title, + -1 , + cppu::UnoType<OUString>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND ) ); + + // CasePreservingURL + m_aDefaultProperties.insert( + MyProperty( true, + CasePreservingURL, + -1 , + cppu::UnoType<OUString>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + + // IsFolder + m_aDefaultProperties.insert( MyProperty( true, + IsFolder, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + + // IsDocument + m_aDefaultProperties.insert( MyProperty( true, + IsDocument, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // Removable + m_aDefaultProperties.insert( MyProperty( true, + IsVolume, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + + // Removable + m_aDefaultProperties.insert( MyProperty( true, + IsRemoveable, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // Remote + m_aDefaultProperties.insert( MyProperty( true, + IsRemote, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // CompactDisc + m_aDefaultProperties.insert( MyProperty( true, + IsCompactDisc, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // Floppy + m_aDefaultProperties.insert( MyProperty( true, + IsFloppy, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + // Hidden + m_aDefaultProperties.insert( + MyProperty( + true, + IsHidden, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND +#if defined(_WIN32) + )); +#else + | beans::PropertyAttribute::READONLY)); // under unix/linux only readable +#endif + + + // ContentType + m_aDefaultProperties.insert( MyProperty( false, + ContentType, + -1 , + cppu::UnoType<OUString>::get(), + uno::Any(OUString()), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + + // DateModified + m_aDefaultProperties.insert( MyProperty( true, + DateModified, + -1 , + cppu::UnoType<util::DateTime>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND ) ); + + // Size + m_aDefaultProperties.insert( MyProperty( true, + Size, + -1, + cppu::UnoType<sal_Int64>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND ) ); + + // IsReadOnly + m_aDefaultProperties.insert( MyProperty( true, + IsReadOnly, + -1 , + cppu::UnoType<sal_Bool>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND ) ); + + + // CreatableContentsInfo + m_aDefaultProperties.insert( MyProperty( true, + CreatableContentsInfo, + -1 , + cppu::UnoType<uno::Sequence< ucb::ContentInfo >>::get(), + uno::Any(), + beans::PropertyState_DEFAULT_VALUE, + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY ) ); + + if(bWithConfig) + { + uno::Reference< XPropertySetRegistryFactory > xRegFac = ucb::Store::create( m_xContext ); + // Open/create a registry + m_xFileRegistry = xRegFac->createPropertySetRegistry( OUString() ); + } +} + + +TaskManager::~TaskManager() +{ +} + + +void +TaskManager::startTask( + sal_Int32 CommandId, + const uno::Reference< XCommandEnvironment >& xCommandEnv ) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + if( it != m_aTaskMap.end() ) + { + throw DuplicateCommandIdentifierException( OSL_LOG_PREFIX ); + } + m_aTaskMap.emplace( CommandId, TaskHandling( xCommandEnv )); +} + + +void +TaskManager::endTask( sal_Int32 CommandId, + const OUString& aUncPath, + BaseContent* pContent) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + if( it == m_aTaskMap.end() ) + return; + + sal_Int32 ErrorCode = it->second.getInstalledError(); + sal_Int32 MinorCode = it->second.getMinorErrorCode(); + bool isHandled = it->second.isHandled(); + + Reference< XCommandEnvironment > xComEnv + = it->second.getCommandEnvironment(); + + m_aTaskMap.erase( it ); + + aGuard.unlock(); + + if( ErrorCode != TASKHANDLER_NO_ERROR ) + throw_handler( + ErrorCode, + MinorCode, + xComEnv, + aUncPath, + pContent, + isHandled); +} + + +void TaskManager::clearError( sal_Int32 CommandId ) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + if( it != m_aTaskMap.end() ) + it->second.clearError(); +} + + +void TaskManager::retrieveError( sal_Int32 CommandId, + sal_Int32 &ErrorCode, + sal_Int32 &minorCode) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + if( it != m_aTaskMap.end() ) + { + ErrorCode = it->second.getInstalledError(); + minorCode = it->second. getMinorErrorCode(); + } +} + + +void TaskManager::installError( sal_Int32 CommandId, + sal_Int32 ErrorCode, + sal_Int32 MinorCode ) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + if( it != m_aTaskMap.end() ) + it->second.installError( ErrorCode,MinorCode ); +} + + +sal_Int32 +TaskManager::getCommandId() +{ + std::unique_lock aGuard( m_aMutex ); + return ++m_nCommandId; +} + + +void TaskManager::handleTask( + sal_Int32 CommandId, + const uno::Reference< task::XInteractionRequest >& request ) +{ + std::unique_lock aGuard( m_aMutex ); + TaskMap::iterator it = m_aTaskMap.find( CommandId ); + uno::Reference< task::XInteractionHandler > xInt; + if( it != m_aTaskMap.end() ) + { + xInt = it->second.getInteractionHandler(); + if( xInt.is() ) + xInt->handle( request ); + it->second.setHandled(); + } +} + +/*********************************************************************************/ +/* */ +/* de/registerNotifier-Implementation */ +/* */ +/*********************************************************************************/ + + +// This two methods register and deregister a change listener for the content belonging +// to URL aUnqPath + + +void +TaskManager::registerNotifier( const OUString& aUnqPath, Notifier* pNotifier ) +{ + std::unique_lock aGuard( m_aMutex ); + + ContentMap::iterator it = + m_aContent.emplace( aUnqPath, UnqPathData() ).first; + + std::vector< Notifier* >& nlist = it->second.notifier; + + std::vector<Notifier*>::iterator it1 = std::find(nlist.begin(), nlist.end(), pNotifier); + if( it1 != nlist.end() ) // Every "Notifier" only once + { + return; + } + nlist.push_back( pNotifier ); +} + + +void +TaskManager::deregisterNotifier( const OUString& aUnqPath,Notifier* pNotifier ) +{ + std::unique_lock aGuard( m_aMutex ); + + ContentMap::iterator it = m_aContent.find( aUnqPath ); + if( it == m_aContent.end() ) + return; + + std::erase(it->second.notifier, pNotifier); + + if( it->second.notifier.empty() ) + m_aContent.erase( it ); +} + + +/*********************************************************************************/ +/* */ +/* de/associate-Implementation */ +/* */ +/*********************************************************************************/ + +// Used to associate and deassociate a new property with +// the content belonging to URL UnqPath. +// The default value and the attributes are input + + +void +TaskManager::associate( const OUString& aUnqPath, + const OUString& PropertyName, + const uno::Any& DefaultValue, + const sal_Int16 Attributes ) +{ + MyProperty newProperty( false, + PropertyName, + -1, + DefaultValue.getValueType(), + DefaultValue, + beans::PropertyState_DEFAULT_VALUE, + Attributes ); + + auto it1 = m_aDefaultProperties.find( newProperty ); + if( it1 != m_aDefaultProperties.end() ) + throw beans::PropertyExistException( THROW_WHERE ); + + { + std::unique_lock aGuard( m_aMutex ); + + ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first; + + // Load the XPersistentPropertySetInfo and create it, if it does not exist + load( it,true ); + + PropertySet& properties = it->second.properties; + it1 = properties.find( newProperty ); + if( it1 != properties.end() ) + throw beans::PropertyExistException(THROW_WHERE ); + + // Property does not exist + properties.insert( newProperty ); + it->second.xC->addProperty( PropertyName,Attributes,DefaultValue ); + } + notifyPropertyAdded( getPropertySetListeners( aUnqPath ), PropertyName ); +} + + +void +TaskManager::deassociate( const OUString& aUnqPath, + const OUString& PropertyName ) +{ + MyProperty oldProperty( PropertyName ); + + auto it1 = m_aDefaultProperties.find( oldProperty ); + if( it1 != m_aDefaultProperties.end() ) + throw beans::NotRemoveableException( THROW_WHERE ); + + std::unique_lock aGuard( m_aMutex ); + + ContentMap::iterator it = m_aContent.emplace( aUnqPath,UnqPathData() ).first; + + load( it, false ); + + PropertySet& properties = it->second.properties; + + it1 = properties.find( oldProperty ); + if( it1 == properties.end() ) + throw beans::UnknownPropertyException( PropertyName ); + + properties.erase( it1 ); + + if( it->second.xC.is() ) + it->second.xC->removeProperty( PropertyName ); + + if( properties.size() == 9 ) + { + MyProperty ContentTProperty( ContentType ); + + if( properties.find( ContentTProperty )->getState() == beans::PropertyState_DEFAULT_VALUE ) + { + it->second.xS = nullptr; + it->second.xC = nullptr; + it->second.xA = nullptr; + if(m_xFileRegistry.is()) + m_xFileRegistry->removePropertySet( aUnqPath ); + } + } + aGuard.unlock(); + notifyPropertyRemoved( getPropertySetListeners( aUnqPath ), PropertyName ); +} + + +/*********************************************************************************/ +/* */ +/* page-Implementation */ +/* */ +/*********************************************************************************/ + +// Given an xOutputStream, this method writes the content of the file belonging to +// URL aUnqPath into the XOutputStream + + +void TaskManager::page( sal_Int32 CommandId, + const OUString& aUnqPath, + const uno::Reference< io::XOutputStream >& xOutputStream ) +{ + osl::File aFile( aUnqPath ); + osl::FileBase::RC err = aFile.open( osl_File_OpenFlag_Read ); + + if( err != osl::FileBase::E_None ) + { + aFile.close(); + installError( CommandId, + TASKHANDLING_OPEN_FILE_FOR_PAGING, + err ); + return; + } + + const sal_uInt64 bfz = 4*1024; + sal_Int8 BFF[bfz]; + sal_uInt64 nrc; // Retrieved number of Bytes; + + do + { + err = aFile.read( static_cast<void*>(BFF),bfz,nrc ); + if( err == osl::FileBase::E_None ) + { + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + uno::Sequence< sal_Int8 > seq( BFF, static_cast<sal_uInt32>(nrc) ); + try + { + xOutputStream->writeBytes( seq ); + } + catch (const io::NotConnectedException&) + { + installError( CommandId, + TASKHANDLING_NOTCONNECTED_FOR_PAGING ); + break; + } + catch (const io::BufferSizeExceededException&) + { + installError( CommandId, + TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_PAGING ); + break; + } + catch (const io::IOException&) + { + installError( CommandId, + TASKHANDLING_IOEXCEPTION_FOR_PAGING ); + break; + } + } + else + { + installError( CommandId, + TASKHANDLING_READING_FILE_FOR_PAGING, + err ); + break; + } + } while( nrc == bfz ); + + + aFile.close(); + + + try + { + xOutputStream->closeOutput(); + } + catch (const io::NotConnectedException&) + { + } + catch (const io::BufferSizeExceededException&) + { + } + catch (const io::IOException&) + { + } +} + + +/*********************************************************************************/ +/* */ +/* open-Implementation */ +/* */ +/*********************************************************************************/ + +// Given a file URL aUnqPath, this methods returns a XInputStream which reads from the open file. + + +uno::Reference< io::XInputStream > +TaskManager::open( sal_Int32 CommandId, + const OUString& aUnqPath, + bool bLock ) +{ + rtl::Reference<XInputStream_impl> pInputStream(new XInputStream_impl( aUnqPath, bLock )); // from filinpstr.hxx + + sal_Int32 ErrorCode = pInputStream->CtorSuccess(); + + if( ErrorCode != TASKHANDLER_NO_ERROR ) + { + installError( CommandId, + ErrorCode, + pInputStream->getMinorError() ); + + pInputStream.clear(); + } + + return pInputStream; +} + + +/*********************************************************************************/ +/* */ +/* open for read/write access-Implementation */ +/* */ +/*********************************************************************************/ + +// Given a file URL aUnqPath, this methods returns a XStream which can be used +// to read and write from/to the file. + + +uno::Reference< io::XStream > +TaskManager::open_rw( sal_Int32 CommandId, + const OUString& aUnqPath, + bool bLock ) +{ + rtl::Reference<XStream_impl> pStream(new XStream_impl( aUnqPath, bLock )); // from filstr.hxx + + sal_Int32 ErrorCode = pStream->CtorSuccess(); + + if( ErrorCode != TASKHANDLER_NO_ERROR ) + { + installError( CommandId, + ErrorCode, + pStream->getMinorError() ); + + pStream.clear(); + } + return pStream; +} + + +/*********************************************************************************/ +/* */ +/* ls-Implementation */ +/* */ +/*********************************************************************************/ + +// This method returns the result set containing the children of the directory belonging +// to file URL aUnqPath + + +uno::Reference< XDynamicResultSet > +TaskManager::ls( sal_Int32 CommandId, + const OUString& aUnqPath, + const sal_Int32 OpenMode, + const uno::Sequence< beans::Property >& seq, + const uno::Sequence< NumberedSortingInfo >& seqSort ) +{ + rtl::Reference<XResultSet_impl> p(new XResultSet_impl( this,aUnqPath,OpenMode,seq,seqSort )); + + sal_Int32 ErrorCode = p->CtorSuccess(); + + if( ErrorCode != TASKHANDLER_NO_ERROR ) + { + installError( CommandId, + ErrorCode, + p->getMinorError() ); + + p.clear(); + } + + return p; +} + + +/*********************************************************************************/ +/* */ +/* info_c implementation */ +/* */ +/*********************************************************************************/ +// Info for commands + +uno::Reference< XCommandInfo > +TaskManager::info_c() +{ + return new XCommandInfo_impl( this ); +} + + +/*********************************************************************************/ +/* */ +/* info_p-Implementation */ +/* */ +/*********************************************************************************/ +// Info for the properties + +uno::Reference< beans::XPropertySetInfo > +TaskManager::info_p( const OUString& aUnqPath ) +{ + std::unique_lock aGuard( m_aMutex ); + return new XPropertySetInfo_impl( this,aUnqPath ); +} + + +/*********************************************************************************/ +/* */ +/* setv-Implementation */ +/* */ +/*********************************************************************************/ + +// Sets the values of the properties belonging to fileURL aUnqPath + + +uno::Sequence< uno::Any > +TaskManager::setv( const OUString& aUnqPath, + const uno::Sequence< beans::PropertyValue >& values ) +{ + std::unique_lock aGuard( m_aMutex ); + + sal_Int32 propChanged = 0; + uno::Sequence< uno::Any > ret( values.getLength() ); + auto retRange = asNonConstRange(ret); + uno::Sequence< beans::PropertyChangeEvent > seqChanged( values.getLength() ); + auto seqChangedRange = asNonConstRange(seqChanged); + + TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath ); + PropertySet& properties = it->second.properties; + TaskManager::PropertySet::const_iterator it1; + uno::Any aAny; + + for( sal_Int32 i = 0; i < values.getLength(); ++i ) + { + MyProperty toset( values[i].Name ); + it1 = properties.find( toset ); + if( it1 == properties.end() ) + { + retRange[i] <<= beans::UnknownPropertyException( THROW_WHERE ); + continue; + } + + aAny = it1->getValue(); + if( aAny == values[i].Value ) + continue; // nothing needs to be changed + + if( it1->getAttributes() & beans::PropertyAttribute::READONLY ) + { + retRange[i] <<= lang::IllegalAccessException( THROW_WHERE ); + continue; + } + + seqChangedRange[ propChanged ].PropertyName = values[i].Name; + seqChangedRange[ propChanged ].PropertyHandle = -1; + seqChangedRange[ propChanged ].Further = false; + seqChangedRange[ propChanged ].OldValue = aAny; + seqChangedRange[ propChanged++ ].NewValue = values[i].Value; + + it1->setValue( values[i].Value ); // Put the new value into the local cash + + if( ! it1->IsNative() ) + { + // Also put logical properties into storage + if( !it->second.xS.is() ) + load( it, true ); + + if( ( values[i].Name == ContentType ) && + it1->getState() == beans::PropertyState_DEFAULT_VALUE ) + { // Special logic for ContentType + // 09.07.01: Not reached anymore, because ContentType is readonly + it1->setState( beans::PropertyState_DIRECT_VALUE ); + it->second.xC->addProperty( values[i].Name, + beans::PropertyAttribute::MAYBEVOID, + values[i].Value ); + } + + try + { + it->second.xS->setPropertyValue( values[i].Name,values[i].Value ); + } + catch (const uno::Exception&e) + { + --propChanged; // unsuccessful setting + retRange[i] <<= e; + } + } + else + { + // native properties + // Setting of physical file properties + if( values[i].Name == Size ) + { + sal_Int64 newSize = 0; + if( values[i].Value >>= newSize ) + { // valid value for the size + osl::File aFile(aUnqPath); + bool err = + aFile.open(osl_File_OpenFlag_Write) != osl::FileBase::E_None || + aFile.setSize(sal_uInt64(newSize)) != osl::FileBase::E_None || + aFile.close() != osl::FileBase::E_None; + + if( err ) + { + --propChanged; // unsuccessful setting + uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence( + { + {"Uri", uno::Any(aUnqPath)} + })); + retRange[i] <<= InteractiveAugmentedIOException( + OUString(), + nullptr, + task::InteractionClassification_ERROR, + IOErrorCode_GENERAL, + names ); + } + } + else + retRange[i] <<= beans::IllegalTypeException( THROW_WHERE ); + } + else if(values[i].Name == IsReadOnly || + values[i].Name == IsHidden) + { + bool value = false; + if( values[i].Value >>= value ) + { + osl::DirectoryItem aDirItem; + osl::FileBase::RC err = + osl::DirectoryItem::get(aUnqPath,aDirItem); + sal_uInt64 nAttributes(0); + if(err == osl::FileBase::E_None) + { + osl::FileStatus aFileStatus(osl_FileStatus_Mask_Attributes); + err = aDirItem.getFileStatus(aFileStatus); + if(err == osl::FileBase::E_None && + aFileStatus.isValid(osl_FileStatus_Mask_Attributes)) + nAttributes = aFileStatus.getAttributes(); + } + // now we have the attributes provided all went well. + if(err == osl::FileBase::E_None) { + if(values[i].Name == IsReadOnly) + { + nAttributes &= ~(osl_File_Attribute_OwnWrite | + osl_File_Attribute_GrpWrite | + osl_File_Attribute_OthWrite | + osl_File_Attribute_ReadOnly); + if(value) + nAttributes |= osl_File_Attribute_ReadOnly; + else + nAttributes |= ( + osl_File_Attribute_OwnWrite | + osl_File_Attribute_GrpWrite | + osl_File_Attribute_OthWrite); + } + else if(values[i].Name == IsHidden) + { + nAttributes &= ~(osl_File_Attribute_Hidden); + if(value) + nAttributes |= osl_File_Attribute_Hidden; + } + err = osl::File::setAttributes( + aUnqPath,nAttributes); + } + + if( err != osl::FileBase::E_None ) + { + --propChanged; // unsuccessful setting + uno::Sequence<uno::Any> names(comphelper::InitAnyPropertySequence( + { + {"Uri", uno::Any(aUnqPath)} + })); + IOErrorCode ioError; + switch( err ) + { + case osl::FileBase::E_NOMEM: + // not enough memory for allocating structures <br> + ioError = IOErrorCode_OUT_OF_MEMORY; + break; + case osl::FileBase::E_INVAL: + // the format of the parameters was not valid<p> + ioError = IOErrorCode_INVALID_PARAMETER; + break; + case osl::FileBase::E_NAMETOOLONG: + // File name too long<br> + ioError = IOErrorCode_NAME_TOO_LONG; + break; + case osl::FileBase::E_NOENT: + // No such file or directory<br> + case osl::FileBase::E_NOLINK: + // Link has been severed<br> + ioError = IOErrorCode_NOT_EXISTING; + break; + case osl::FileBase::E_ROFS: + // #i4735# handle ROFS transparently + // as ACCESS_DENIED + case osl::FileBase::E_PERM: + case osl::FileBase::E_ACCES: + // permission denied<br> + ioError = IOErrorCode_ACCESS_DENIED; + break; + case osl::FileBase::E_LOOP: + // Too many symbolic links encountered<br> + case osl::FileBase::E_FAULT: + // Bad address<br> + case osl::FileBase::E_IO: + // I/O error<br> + case osl::FileBase::E_NOSYS: + // Function not implemented<br> + case osl::FileBase::E_MULTIHOP: + // Multihop attempted<br> + case osl::FileBase::E_INTR: + // function call was interrupted<p> + default: + ioError = IOErrorCode_GENERAL; + break; + } + retRange[i] <<= InteractiveAugmentedIOException( + OUString(), + nullptr, + task::InteractionClassification_ERROR, + ioError, + names ); + } + } + else + retRange[i] <<= beans::IllegalTypeException( THROW_WHERE ); + } + } + } // end for + + aGuard.unlock(); + if( propChanged ) + { + seqChanged.realloc( propChanged ); + notifyPropertyChanges( getPropertyChangeNotifier( aUnqPath ), seqChanged ); + } + + return ret; +} + +/*********************************************************************************/ +/* */ +/* getv-Implementation */ +/* */ +/*********************************************************************************/ + +// Reads the values of the properties belonging to fileURL aUnqPath; +// Returns an XRow object containing the values in the requested order. + + +uno::Reference< sdbc::XRow > +TaskManager::getv( sal_Int32 CommandId, + const OUString& aUnqPath, + const uno::Sequence< beans::Property >& properties ) +{ + uno::Sequence< uno::Any > seq( properties.getLength() ); + + sal_Int32 n_Mask; + getMaskFromProperties( n_Mask,properties ); + osl::FileStatus aFileStatus( n_Mask ); + + osl::DirectoryItem aDirItem; + osl::FileBase::RC nError1 = osl::DirectoryItem::get( aUnqPath,aDirItem ); + if( nError1 != osl::FileBase::E_None ) + installError(CommandId, + TASKHANDLING_OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED + nError1); + + osl::FileBase::RC nError2 = aDirItem.getFileStatus( aFileStatus ); + if( nError1 == osl::FileBase::E_None && + nError2 != osl::FileBase::E_None ) + installError(CommandId, + TASKHANDLING_OPEN_FILE_FOR_PAGING, // BEAWARE, REUSED + nError2); + + { + std::unique_lock aGuard( m_aMutex ); + + TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath ); + commit( aGuard, it, aFileStatus ); + + PropertySet& propset = it->second.properties; + + std::transform(properties.begin(), properties.end(), seq.getArray(), + [&propset](const beans::Property& rProp) -> uno::Any { + MyProperty readProp( rProp.Name ); + auto it1 = propset.find( readProp ); + if( it1 == propset.end() ) + return uno::Any(); + return it1->getValue(); + }); + } + + return new XRow_impl( this,seq ); +} + + +/********************************************************************************/ +/* */ +/* transfer-commandos */ +/* */ +/********************************************************************************/ + + +/********************************************************************************/ +/* */ +/* move-implementation */ +/* */ +/********************************************************************************/ + +// Moves the content belonging to fileURL srcUnqPath to fileURL dstUnqPath. + + +void +TaskManager::move( sal_Int32 CommandId, + const OUString& srcUnqPath, + const OUString& dstUnqPathIn, + const sal_Int32 NameClash ) +{ + // --> #i88446# Method notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) ); crashes if + // srcUnqPath and dstUnqPathIn are equal + if( srcUnqPath == dstUnqPathIn ) + return; + + osl::FileBase::RC nError; + OUString dstUnqPath( dstUnqPathIn ); + + switch( NameClash ) + { + case NameClash::KEEP: + { + nError = osl_File_move( srcUnqPath,dstUnqPath,true ); + if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_KEEPERROR_FOR_MOVE, + nError ); + return; + } + break; + } + case NameClash::OVERWRITE: + { + // stat to determine whether we have a symlink + OUString targetPath(dstUnqPath); + + osl::FileStatus aStatus(osl_FileStatus_Mask_Type|osl_FileStatus_Mask_LinkTargetURL); + osl::DirectoryItem aItem; + (void)osl::DirectoryItem::get(dstUnqPath,aItem); + (void)aItem.getFileStatus(aStatus); + + if( aStatus.isValid(osl_FileStatus_Mask_Type) && + aStatus.isValid(osl_FileStatus_Mask_LinkTargetURL) && + aStatus.getFileType() == osl::FileStatus::Link ) + targetPath = aStatus.getLinkTargetURL(); + + // Will do nothing if file does not exist. + osl::File::remove( targetPath ); + + nError = osl_File_move( srcUnqPath,targetPath ); + if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_OVERWRITE_FOR_MOVE, + nError ); + return; + } + break; + } + case NameClash::RENAME: + { + OUString newDstUnqPath; + nError = osl_File_move( srcUnqPath,dstUnqPath,true ); + if( nError == osl::FileBase::E_EXIST ) + { + // "invent" a new valid title. + + sal_Int32 nPos = -1; + sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' ); + sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' ); + if( ( nLastSlash < nLastDot ) // dot is part of last(!) path segment + && ( nLastSlash != ( nLastDot - 1 ) ) ) // file name does not start with a dot + nPos = nLastDot; + else + nPos = dstUnqPath.getLength(); + + sal_Int32 nTry = 0; + + do + { + newDstUnqPath = dstUnqPath; + + OUString aPostfix = "_" + OUString::number( ++nTry ); + + newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix ); + + nError = osl_File_move( srcUnqPath,newDstUnqPath,true ); + } + while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) ); + } + + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_RENAME_FOR_MOVE ); + return; + } + else if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_RENAMEMOVE_FOR_MOVE, + nError ); + return; + } + else + dstUnqPath = newDstUnqPath; + + break; + } + case NameClash::ERROR: + { + nError = osl_File_move( srcUnqPath,dstUnqPath,true ); + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_NAMECLASH_FOR_MOVE ); + return; + } + else if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_NAMECLASHMOVE_FOR_MOVE, + nError ); + return; + } + break; + } + case NameClash::ASK: + default: + { + nError = osl_File_move( srcUnqPath,dstUnqPath,true ); + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_NAMECLASHSUPPORT_FOR_MOVE, + NameClash::ASK); + return; + } + } + break; + } + + // Determine, whether we have moved a file or a folder + osl::DirectoryItem aItem; + nError = osl::DirectoryItem::get( dstUnqPath,aItem ); + if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_TRANSFER_BY_MOVE_SOURCE, + nError ); + return; + } + osl::FileStatus aStatus( osl_FileStatus_Mask_Type ); + nError = aItem.getFileStatus( aStatus ); + if( nError != osl::FileBase::E_None || ! aStatus.isValid( osl_FileStatus_Mask_Type ) ) + { + installError( CommandId, + TASKHANDLING_TRANSFER_BY_MOVE_SOURCESTAT, + nError ); + return; + } + bool isDocument = ( aStatus.getFileType() == osl::FileStatus::Regular ); + + + copyPersistentSet( srcUnqPath,dstUnqPath,!isDocument ); + + OUString aDstParent = getParentName( dstUnqPath ); + OUString aSrcParent = getParentName( srcUnqPath ); + + notifyInsert( getContentEventListeners( aDstParent ),dstUnqPath ); + if( aDstParent != aSrcParent ) + notifyContentRemoved( getContentEventListeners( aSrcParent ),srcUnqPath ); + + notifyContentExchanged( getContentExchangedEventListeners( srcUnqPath,dstUnqPath,!isDocument ) ); + erasePersistentSet( srcUnqPath,!isDocument ); +} + + +/********************************************************************************/ +/* */ +/* copy-implementation */ +/* */ +/********************************************************************************/ + +// Copies the content belonging to fileURL srcUnqPath to fileURL dstUnqPath ( files and directories ) + + +namespace { + +bool getType( + TaskManager & task, sal_Int32 id, OUString const & fileUrl, + osl::DirectoryItem * item, osl::FileStatus::Type * type) +{ + OSL_ASSERT(item != nullptr && type != nullptr); + osl::FileBase::RC err = osl::DirectoryItem::get(fileUrl, *item); + if (err != osl::FileBase::E_None) { + task.installError(id, TASKHANDLING_TRANSFER_BY_COPY_SOURCE, err); + return false; + } + osl::FileStatus stat(osl_FileStatus_Mask_Type); + err = item->getFileStatus(stat); + if (err != osl::FileBase::E_None) { + task.installError(id, TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT, err); + return false; + } + *type = stat.getFileType(); + return true; +} + +} + +void +TaskManager::copy( + sal_Int32 CommandId, + const OUString& srcUnqPath, + const OUString& dstUnqPathIn, + sal_Int32 NameClash ) +{ + osl::FileBase::RC nError; + OUString dstUnqPath( dstUnqPathIn ); + + // Resolve symbolic links within the source path. If srcUnqPath denotes a + // symbolic link (targeting either a file or a folder), the contents of the + // target is copied (recursively, in the case of a folder). However, if + // recursively copying the contents of a folder causes a symbolic link to be + // copied, the symbolic link itself is copied. + osl::DirectoryItem item; + osl::FileStatus::Type type; + if (!getType(*this, CommandId, srcUnqPath, &item, &type)) { + return; + } + OUString rslvdSrcUnqPath; + if (type == osl::FileStatus::Link) { + osl::FileStatus stat(osl_FileStatus_Mask_LinkTargetURL); + nError = item.getFileStatus(stat); + if (nError != osl::FileBase::E_None) { + installError( + CommandId, TASKHANDLING_TRANSFER_BY_COPY_SOURCESTAT, nError); + return; + } + rslvdSrcUnqPath = stat.getLinkTargetURL(); + if (!getType(*this, CommandId, srcUnqPath, &item, &type)) { + return; + } + } else { + rslvdSrcUnqPath = srcUnqPath; + } + + bool isDocument + = type != osl::FileStatus::Directory && type != osl::FileStatus::Volume; + FileUrlType IsWhat = isDocument ? FileUrlType::File : FileUrlType::Folder; + + switch( NameClash ) + { + case NameClash::KEEP: + { + nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true ); + if( nError != osl::FileBase::E_None && nError != osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_KEEPERROR_FOR_COPY, + nError ); + return; + } + break; + } + case NameClash::OVERWRITE: + { + // remove (..., MustExist = sal_False). + remove( CommandId, dstUnqPath, IsWhat, false ); + + // copy. + nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,false ); + if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_OVERWRITE_FOR_COPY, + nError ); + return; + } + break; + } + case NameClash::RENAME: + { + OUString newDstUnqPath = dstUnqPath; + nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true ); + + if( nError == osl::FileBase::E_EXIST ) + { + // "invent" a new valid title. + + sal_Int32 nPos = -1; + sal_Int32 nLastDot = dstUnqPath.lastIndexOf( '.' ); + sal_Int32 nLastSlash = dstUnqPath.lastIndexOf( '/' ); + if ( ( nLastSlash < nLastDot ) // dot is part of last(!) path segment + && ( nLastSlash != ( nLastDot - 1 ) ) ) // file name does not start with a dot + nPos = nLastDot; + else + nPos = dstUnqPath.getLength(); + + sal_Int32 nTry = 0; + + do + { + newDstUnqPath = dstUnqPath; + + OUString aPostfix = "_" + OUString::number( ++nTry ); + + newDstUnqPath = newDstUnqPath.replaceAt( nPos, 0, aPostfix ); + + nError = copy_recursive( rslvdSrcUnqPath,newDstUnqPath,IsWhat,true ); + } + while( ( nError == osl::FileBase::E_EXIST ) && ( nTry < 10000 ) ); + } + + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_RENAME_FOR_COPY ); + return; + } + else if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_RENAMEMOVE_FOR_COPY, + nError ); + return; + } + else + dstUnqPath = newDstUnqPath; + + break; + } + case NameClash::ERROR: + { + nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true ); + + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_NAMECLASH_FOR_COPY ); + return; + } + else if( nError != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_NAMECLASHMOVE_FOR_COPY, + nError ); + return; + } + break; + } + case NameClash::ASK: + default: + { + nError = copy_recursive( rslvdSrcUnqPath,dstUnqPath,IsWhat,true ); + + if( nError == osl::FileBase::E_EXIST ) + { + installError( CommandId, + TASKHANDLING_NAMECLASHSUPPORT_FOR_COPY, + NameClash); + return; + } + break; + } + } + + copyPersistentSet( srcUnqPath,dstUnqPath, !isDocument ); + notifyInsert( getContentEventListeners( getParentName( dstUnqPath ) ),dstUnqPath ); +} + + +/********************************************************************************/ +/* */ +/* remove-implementation */ +/* */ +/********************************************************************************/ + +// Deletes the content belonging to fileURL aUnqPath( recursively in case of directory ) +// Return: success of operation + + +bool +TaskManager::remove( sal_Int32 CommandId, + const OUString& aUnqPath, + FileUrlType IsWhat, + bool MustExist ) +{ + sal_Int32 nMask = osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL; + + osl::DirectoryItem aItem; + osl::FileStatus aStatus( nMask ); + osl::FileBase::RC nError; + + if( IsWhat == FileUrlType::Unknown ) // Determine whether we are removing a directory or a file + { + nError = osl::DirectoryItem::get( aUnqPath, aItem ); + if( nError != osl::FileBase::E_None ) + { + if (MustExist) + { + installError( CommandId, + TASKHANDLING_NOSUCHFILEORDIR_FOR_REMOVE, + nError ); + } + return (!MustExist); + } + + nError = aItem.getFileStatus( aStatus ); + if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) ) + { + installError( CommandId, + TASKHANDLING_VALIDFILESTATUS_FOR_REMOVE, + nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR ); + return false; + } + + if( aStatus.getFileType() == osl::FileStatus::Regular || + aStatus.getFileType() == osl::FileStatus::Link ) + IsWhat = FileUrlType::File; + else if( aStatus.getFileType() == osl::FileStatus::Directory || + aStatus.getFileType() == osl::FileStatus::Volume ) + IsWhat = FileUrlType::Folder; + } + + + if( IsWhat == FileUrlType::File ) + { + nError = osl::File::remove( aUnqPath ); + if( nError != osl::FileBase::E_None ) + { + if (MustExist) + { + installError( CommandId, + TASKHANDLING_DELETEFILE_FOR_REMOVE, + nError ); + } + return (!MustExist); + } + else + { + notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) ); + erasePersistentSet( aUnqPath ); // Removes from XPersistentPropertySet + } + } + else if( IsWhat == FileUrlType::Folder ) + { + osl::Directory aDirectory( aUnqPath ); + + nError = aDirectory.open(); + if( nError != osl::FileBase::E_None ) + { + if (MustExist) + { + installError( CommandId, + TASKHANDLING_OPENDIRECTORY_FOR_REMOVE, + nError ); + } + return (!MustExist); + } + + bool whileSuccess = true; + FileUrlType recurse = FileUrlType::Unknown; + OUString name; + + nError = aDirectory.getNextItem( aItem ); + while( nError == osl::FileBase::E_None ) + { + nError = aItem.getFileStatus( aStatus ); + if( nError != osl::FileBase::E_None || ! aStatus.isValid( nMask ) ) + { + installError( CommandId, + TASKHANDLING_VALIDFILESTATUSWHILE_FOR_REMOVE, + nError != osl::FileBase::E_None ? nError : TASKHANDLER_NO_ERROR ); + whileSuccess = false; + break; + } + + if( aStatus.getFileType() == osl::FileStatus::Regular || + aStatus.getFileType() == osl::FileStatus::Link ) + recurse = FileUrlType::File; + else if( aStatus.getFileType() == osl::FileStatus::Directory || + aStatus.getFileType() == osl::FileStatus::Volume ) + recurse = FileUrlType::Folder; + + name = aStatus.getFileURL(); + whileSuccess = remove( CommandId, name, recurse, MustExist ); + if( !whileSuccess ) + break; + + nError = aDirectory.getNextItem( aItem ); + } + + aDirectory.close(); + + if( ! whileSuccess ) + return false; // error code is installed + + if( nError != osl::FileBase::E_NOENT ) + { + installError( CommandId, + TASKHANDLING_DIRECTORYEXHAUSTED_FOR_REMOVE, + nError ); + return false; + } + + nError = osl::Directory::remove( aUnqPath ); + if( nError != osl::FileBase::E_None ) + { + if (MustExist) + { + installError( CommandId, + TASKHANDLING_DELETEDIRECTORY_FOR_REMOVE, + nError ); + } + return (!MustExist); + } + else + { + notifyContentDeleted( getContentDeletedEventListeners(aUnqPath) ); + erasePersistentSet( aUnqPath ); + } + } + else // Don't know what to remove + { + installError( CommandId, + TASKHANDLING_FILETYPE_FOR_REMOVE ); + return false; + } + + return true; +} + + +/********************************************************************************/ +/* */ +/* mkdir-implementation */ +/* */ +/********************************************************************************/ + +// Creates new directory with given URL, recursively if necessary +// Return:: success of operation + + +bool +TaskManager::mkdir( sal_Int32 CommandId, + const OUString& rUnqPath, + bool OverWrite ) +{ + OUString aUnqPath; + + // remove trailing slash + if ( rUnqPath.endsWith("/") ) + aUnqPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 ); + else + aUnqPath = rUnqPath; + + osl::FileBase::RC nError = osl::Directory::create( aUnqPath ); + + switch ( nError ) + { + case osl::FileBase::E_EXIST: // Directory cannot be overwritten + { + if( !OverWrite ) + { + installError( CommandId, + TASKHANDLING_FOLDER_EXISTS_MKDIR ); + return false; + } + else + return true; + } + case osl::FileBase::E_INVAL: + { + installError(CommandId, + TASKHANDLING_INVALID_NAME_MKDIR); + return false; + } + case osl::FileBase::E_None: + { + OUString aPrtPath = getParentName( aUnqPath ); + notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath ); + return true; + } + default: + return ensuredir( + CommandId, + aUnqPath, + TASKHANDLING_CREATEDIRECTORY_MKDIR ); + } +} + + +/********************************************************************************/ +/* */ +/* mkfil-implementation */ +/* */ +/********************************************************************************/ + +// Creates new file with given URL. +// The content of aInputStream becomes the content of the file +// Return:: success of operation + + +bool +TaskManager::mkfil( sal_Int32 CommandId, + const OUString& aUnqPath, + bool Overwrite, + const uno::Reference< io::XInputStream >& aInputStream ) +{ + // return value unimportant + bool bSuccess = write( CommandId, + aUnqPath, + Overwrite, + aInputStream ); + if ( bSuccess ) + { + OUString aPrtPath = getParentName( aUnqPath ); + notifyInsert( getContentEventListeners( aPrtPath ),aUnqPath ); + } + return bSuccess; +} + + +/********************************************************************************/ +/* */ +/* write-implementation */ +/* */ +/********************************************************************************/ + +// writes to the file with given URL. +// The content of aInputStream becomes the content of the file +// Return:: success of operation + + +bool +TaskManager::write( sal_Int32 CommandId, + const OUString& aUnqPath, + bool OverWrite, + const uno::Reference< io::XInputStream >& aInputStream ) +{ + if( ! aInputStream.is() ) + { + installError( CommandId, + TASKHANDLING_INPUTSTREAM_FOR_WRITE ); + return false; + } + + // Create parent path, if necessary. + if ( ! ensuredir( CommandId, + getParentName( aUnqPath ), + TASKHANDLING_ENSUREDIR_FOR_WRITE ) ) + return false; + + osl::FileBase::RC err; + osl::File aFile( aUnqPath ); + + if( OverWrite ) + { + err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); + + if( err != osl::FileBase::E_None ) + { + aFile.close(); + err = aFile.open( osl_File_OpenFlag_Write ); + + if( err != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_NO_OPEN_FILE_FOR_OVERWRITE, + err ); + return false; + } + + // the existing file was just opened and should be overwritten now, + // truncate it first + + err = aFile.setSize( 0 ); + if( err != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_FILESIZE_FOR_WRITE, + err ); + return false; + } + } + } + else + { + err = aFile.open( osl_File_OpenFlag_Read | osl_File_OpenFlag_NoLock ); + if( err == osl::FileBase::E_None ) // The file exists and shall not be overwritten + { + installError( CommandId, + TASKHANDLING_NOREPLACE_FOR_WRITE, // Now an exception + err ); + + aFile.close(); + return false; + } + + // as a temporary solution the creation does not lock the file at all + // in future it should be possible to create the file without lock explicitly + err = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create | osl_File_OpenFlag_NoLock ); + + if( err != osl::FileBase::E_None ) + { + aFile.close(); + installError( CommandId, + TASKHANDLING_NO_OPEN_FILE_FOR_WRITE, + err ); + return false; + } + } + + bool bSuccess = true; + + sal_uInt64 nWrittenBytes; + sal_Int32 nReadBytes = 0, nRequestedBytes = 32768 /*32k*/; + uno::Sequence< sal_Int8 > seq( nRequestedBytes ); + + do + { + try + { + nReadBytes = aInputStream->readBytes( seq, + nRequestedBytes ); + } + catch( const io::NotConnectedException& ) + { + installError( CommandId, + TASKHANDLING_NOTCONNECTED_FOR_WRITE ); + bSuccess = false; + break; + } + catch( const io::BufferSizeExceededException& ) + { + installError( CommandId, + TASKHANDLING_BUFFERSIZEEXCEEDED_FOR_WRITE ); + bSuccess = false; + break; + } + catch( const io::IOException& ) + { + installError( CommandId, + TASKHANDLING_IOEXCEPTION_FOR_WRITE ); + bSuccess = false; + break; + } + + if( nReadBytes ) + { + const sal_Int8* p = seq.getConstArray(); + + err = aFile.write( static_cast<void const *>(p), + sal_uInt64( nReadBytes ), + nWrittenBytes ); + + if( err != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_FILEIOERROR_FOR_WRITE, + err ); + bSuccess = false; + break; + } + else if( nWrittenBytes != sal_uInt64( nReadBytes ) ) + { + installError( CommandId, + TASKHANDLING_FILEIOERROR_FOR_NO_SPACE ); + bSuccess = false; + break; + } + } + } while( nReadBytes == nRequestedBytes ); + + err = aFile.close(); + if( err != osl::FileBase::E_None ) + { + installError( CommandId, + TASKHANDLING_FILEIOERROR_FOR_WRITE, + err ); + bSuccess = false; + } + + return bSuccess; +} + + +/*********************************************************************************/ +/* */ +/* insertDefaultProperties-Implementation */ +/* */ +/*********************************************************************************/ + + +void TaskManager::insertDefaultProperties( const OUString& aUnqPath ) +{ + std::unique_lock aGuard(m_aMutex); + insertDefaultProperties(aGuard, aUnqPath); +} + +void TaskManager::insertDefaultProperties( std::unique_lock<std::mutex>& /*rGuard*/, const OUString& aUnqPath ) +{ + ContentMap::iterator it = + m_aContent.emplace( aUnqPath,UnqPathData() ).first; + + load( it, false ); + + MyProperty ContentTProperty( ContentType ); + + PropertySet& properties = it->second.properties; + bool ContentNotDefau = properties.find( ContentTProperty ) != properties.end(); + + properties.reserve(properties.size() + m_aDefaultProperties.size()); + for (auto const& defaultprop : m_aDefaultProperties) + { + if( !ContentNotDefau || defaultprop.getPropertyName() != ContentType ) + properties.insert( defaultprop ); + } +} + + +/******************************************************************************/ +/* */ +/* mapping of file urls */ +/* to uncpath and vice versa */ +/* */ +/******************************************************************************/ + + +bool TaskManager::getUnqFromUrl( const OUString& Url, OUString& Unq ) +{ + if ( Url == "file:///" || Url == "file://localhost/" || Url == "file://127.0.0.1/" ) + { + Unq = "file:///"; + return false; + } + + bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Url,Unq ); + + Unq = Url; + + sal_Int32 l = Unq.getLength()-1; + if( ! err && Unq.endsWith("/") && + Unq.indexOf( '/', RTL_CONSTASCII_LENGTH("//") ) != -1 ) + Unq = Unq.copy(0, l); + + return err; +} + + +bool TaskManager::getUrlFromUnq( const OUString& Unq,OUString& Url ) +{ + bool err = osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL( Unq,Url ); + + Url = Unq; + + return err; +} + + +// Helper function for public copy + +osl::FileBase::RC +TaskManager::copy_recursive( const OUString& srcUnqPath, + const OUString& dstUnqPath, + FileUrlType TypeToCopy, + bool testExistBeforeCopy ) +{ + osl::FileBase::RC err = osl::FileBase::E_None; + + if( TypeToCopy == FileUrlType::File ) // Document + { + err = osl_File_copy( srcUnqPath,dstUnqPath,testExistBeforeCopy ); + } + else if( TypeToCopy == FileUrlType::Folder ) + { + osl::Directory aDir( srcUnqPath ); + (void)aDir.open(); + + err = osl::Directory::create( dstUnqPath ); + osl::FileBase::RC next = err; + if( err == osl::FileBase::E_None ) + { + sal_Int32 const n_Mask = osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName | osl_FileStatus_Mask_Type; + + osl::DirectoryItem aDirItem; + + while( err == osl::FileBase::E_None ) + { + next = aDir.getNextItem( aDirItem ); + if (next != osl::FileBase::E_None ) + break; + bool IsDoc = false; + osl::FileStatus aFileStatus( n_Mask ); + aDirItem.getFileStatus( aFileStatus ); + if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) ) + IsDoc = aFileStatus.getFileType() == osl::FileStatus::Regular; + + // Getting the information for the next recursive copy + FileUrlType newTypeToCopy = IsDoc ? FileUrlType::File : FileUrlType::Folder; + + OUString newSrcUnqPath; + if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) ) + newSrcUnqPath = aFileStatus.getFileURL(); + + OUString newDstUnqPath = dstUnqPath; + OUString tit; + if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) ) + tit = rtl::Uri::encode( aFileStatus.getFileName(), + rtl_UriCharClassPchar, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ); + + if( !newDstUnqPath.endsWith( "/" ) ) + newDstUnqPath += "/"; + + newDstUnqPath += tit; + + if ( newSrcUnqPath != dstUnqPath ) + err = copy_recursive( newSrcUnqPath,newDstUnqPath,newTypeToCopy,false ); + } + + if( err == osl::FileBase::E_None && next != osl::FileBase::E_NOENT ) + err = next; + } + aDir.close(); + } + + return err; +} + + +// Helper function for mkfil,mkdir and write +// Creates whole path +// returns success of the operation + + +bool TaskManager::ensuredir( sal_Int32 CommandId, + const OUString& rUnqPath, + sal_Int32 errorCode ) +{ + OUString aPath; + + if ( rUnqPath.isEmpty() ) + return false; + + if ( rUnqPath.endsWith("/") ) + aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 ); + else + aPath = rUnqPath; + +#if HAVE_FEATURE_MACOSX_SANDBOX + + // Avoid annoying sandbox messages in the system.log from the + // below aDirectory.open(), which ends up calling opendir(). + // Surely it is easier to just call stat()? Calling stat() on an + // arbitrary (?) directory does not seem to cause any sandbox + // violation, while opendir() does. (Sorry I could not be bothered + // to use some complex cross-platform abstraction over stat() here + // in this macOS specific code block.) + + OUString aDirName; + struct stat s; + if( osl::FileBase::getSystemPathFromFileURL( aPath, aDirName ) == osl::FileBase::E_None && + stat(OUStringToOString( aDirName, RTL_TEXTENCODING_UTF8).getStr(), &s ) == 0 && + S_ISDIR( s.st_mode ) ) + return sal_True; +#endif + + // HACK: create directory on a mount point with nobrowse option + // returns ENOSYS in any case !! + osl::Directory aDirectory( aPath ); + osl::FileBase::RC nError = aDirectory.open(); + aDirectory.close(); + + if( nError == osl::File::E_None ) + return true; + + nError = osl::Directory::create( aPath ); + + if( nError == osl::File::E_None ) + notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath ); + + bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + + if( ! bSuccess ) + { + OUString aParentDir = getParentName( aPath ); + + if ( aParentDir != aPath ) + { // Create first the parent directory + bSuccess = ensuredir( CommandId, + getParentName( aPath ), + errorCode ); + + // After parent directory structure exists try it one's more + + if ( bSuccess ) + { // Parent directory exists, retry creation of directory + nError = osl::Directory::create( aPath ); + + if( nError == osl::File::E_None ) + notifyInsert( getContentEventListeners( getParentName( aPath ) ),aPath ); + + bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + } + } + } + + if( ! bSuccess ) + installError( CommandId, + errorCode, + nError ); + + return bSuccess; +} + + +// Given a sequence of properties seq, this method determines the mask +// used to instantiate an osl::FileStatus, so that a call to +// osl::DirectoryItem::getFileStatus fills the required fields. + + +void +TaskManager::getMaskFromProperties( + sal_Int32& n_Mask, + const uno::Sequence< beans::Property >& seq ) +{ + n_Mask = 0; + for(const auto& rProp : seq) { + if(rProp.Name == Title) + n_Mask |= osl_FileStatus_Mask_FileName; + else if(rProp.Name == CasePreservingURL) + n_Mask |= osl_FileStatus_Mask_FileURL; + else if(rProp.Name == IsDocument || + rProp.Name == IsFolder || + rProp.Name == IsVolume || + rProp.Name == IsRemoveable || + rProp.Name == IsRemote || + rProp.Name == IsCompactDisc || + rProp.Name == IsFloppy || + rProp.Name == ContentType) + n_Mask |= (osl_FileStatus_Mask_Type | osl_FileStatus_Mask_LinkTargetURL); + else if(rProp.Name == Size) + n_Mask |= (osl_FileStatus_Mask_FileSize | + osl_FileStatus_Mask_Type | + osl_FileStatus_Mask_LinkTargetURL); + else if(rProp.Name == IsHidden || + rProp.Name == IsReadOnly) + n_Mask |= osl_FileStatus_Mask_Attributes; + else if(rProp.Name == DateModified) + n_Mask |= osl_FileStatus_Mask_ModifyTime; + } +} + + +/*********************************************************************************/ +/* */ +/* load-Implementation */ +/* */ +/*********************************************************************************/ + +// Load the properties from configuration, if create == true create them. +// The Properties are stored under the url belonging to it->first. + + +void +TaskManager::load( const ContentMap::iterator& it, bool create ) +{ + if( ( it->second.xS.is() && it->second.xC.is() && it->second.xA.is() ) + || !m_xFileRegistry.is() ) + return; + + + uno::Reference< ucb::XPersistentPropertySet > xS = m_xFileRegistry->openPropertySet( it->first,create ); + if( xS.is() ) + { + it->second.xS = xS; + it->second.xC.set(xS, uno::UNO_QUERY); + it->second.xA.set(xS, uno::UNO_QUERY); + + // Now put in all values in the storage in the local hash; + + PropertySet& properties = it->second.properties; + const uno::Sequence< beans::Property > seq = xS->getPropertySetInfo()->getProperties(); + + for( const auto& rProp : seq ) + { + MyProperty readProp( false, + rProp.Name, + rProp.Handle, + rProp.Type, + xS->getPropertyValue( rProp.Name ), + beans::PropertyState_DIRECT_VALUE, + rProp.Attributes ); + properties.insert( readProp ); + } + } + else if( create ) + { + // Catastrophic error + } +} + + +/*********************************************************************************/ +/* */ +/* commit-Implementation */ +/* */ +/*********************************************************************************/ +// Commit inserts the determined properties in the filestatus object into +// the internal map, so that is possible to determine on a subsequent +// setting of file properties which properties have changed without filestat + + +void +TaskManager::commit( std::unique_lock<std::mutex>& rGuard, + const TaskManager::ContentMap::iterator& it, + const osl::FileStatus& aFileStatus ) +{ + TaskManager::PropertySet::const_iterator it1; + + if( it->second.properties.empty() ) + { + OUString aPath = it->first; + insertDefaultProperties( rGuard, aPath ); + } + + PropertySet& properties = it->second.properties; + + it1 = properties.find( MyProperty( Title ) ); + if( it1 != properties.end() ) + { + if( aFileStatus.isValid( osl_FileStatus_Mask_FileName ) ) + { + it1->setValue( uno::Any(aFileStatus.getFileName()) ); + } + } + + it1 = properties.find( MyProperty( CasePreservingURL ) ); + if( it1 != properties.end() ) + { + if( aFileStatus.isValid( osl_FileStatus_Mask_FileURL ) ) + { + it1->setValue( uno::Any(aFileStatus.getFileURL()) ); + } + } + + + bool isDirectory; + + sal_Int64 dirSize = 0; + + if( aFileStatus.isValid( osl_FileStatus_Mask_FileSize ) ) + dirSize = aFileStatus.getFileSize(); + + if( aFileStatus.isValid( osl_FileStatus_Mask_Type ) ) + { + bool isFile,isVolume; + if( osl::FileStatus::Link == aFileStatus.getFileType() && + aFileStatus.isValid( osl_FileStatus_Mask_LinkTargetURL ) ) + { + osl::DirectoryItem aDirItem; + osl::FileStatus aFileStatus2( osl_FileStatus_Mask_Type ); + if( osl::FileBase::E_None == osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(),aDirItem ) && + osl::FileBase::E_None == aDirItem.getFileStatus( aFileStatus2 ) && + aFileStatus2.isValid( osl_FileStatus_Mask_Type ) ) + { + isVolume = osl::FileStatus::Volume == aFileStatus2.getFileType(); + isDirectory = + osl::FileStatus::Volume == aFileStatus2.getFileType() || + osl::FileStatus::Directory == aFileStatus2.getFileType(); + isFile = + osl::FileStatus::Regular == aFileStatus2.getFileType(); + + if( aFileStatus2.isValid( osl_FileStatus_Mask_FileSize ) ) + dirSize = aFileStatus2.getFileSize(); + } + else + { + // extremely ugly, but otherwise default construction + // of aDirItem and aFileStatus2 + // before the preceding if + isVolume = osl::FileStatus::Volume == aFileStatus.getFileType(); + isDirectory = + osl::FileStatus::Volume == aFileStatus.getFileType() || + osl::FileStatus::Directory == aFileStatus.getFileType(); + isFile = + osl::FileStatus::Regular == aFileStatus.getFileType(); + } + } + else + { + isVolume = osl::FileStatus::Volume == aFileStatus.getFileType(); + isDirectory = + osl::FileStatus::Volume == aFileStatus.getFileType() || + osl::FileStatus::Directory == aFileStatus.getFileType(); + isFile = + osl::FileStatus::Regular == aFileStatus.getFileType(); + } + + it1 = properties.find( MyProperty( IsVolume ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isVolume ) ); + + it1 = properties.find( MyProperty( IsFolder ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isDirectory ) ); + + it1 = properties.find( MyProperty( IsDocument ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isFile ) ); + + osl::VolumeInfo aVolumeInfo( osl_VolumeInfo_Mask_Attributes ); + if( isVolume && + osl::FileBase::E_None == osl::Directory::getVolumeInfo( it->first,aVolumeInfo ) && + aVolumeInfo.isValid( osl_VolumeInfo_Mask_Attributes ) ) + { + // Retrieve the flags; + bool isRemote = aVolumeInfo.getRemoteFlag(); + bool isRemoveable = aVolumeInfo.getRemoveableFlag(); + bool isCompactDisc = aVolumeInfo.getCompactDiscFlag(); + bool isFloppy = aVolumeInfo.getFloppyDiskFlag(); + + it1 = properties.find( MyProperty( IsRemote ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isRemote ) ); + + it1 = properties.find( MyProperty( IsRemoveable ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isRemoveable ) ); + + it1 = properties.find( MyProperty( IsCompactDisc ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isCompactDisc ) ); + + it1 = properties.find( MyProperty( IsFloppy ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( isFloppy ) ); + } + else + { + uno::Any aAny(false); + it1 = properties.find( MyProperty( IsRemote ) ); + if( it1 != properties.end() ) + it1->setValue( aAny ); + + it1 = properties.find( MyProperty( IsRemoveable ) ); + if( it1 != properties.end() ) + it1->setValue( aAny ); + + it1 = properties.find( MyProperty( IsCompactDisc ) ); + if( it1 != properties.end() ) + it1->setValue( aAny ); + + it1 = properties.find( MyProperty( IsFloppy ) ); + if( it1 != properties.end() ) + it1->setValue( aAny ); + } + } + else + { + isDirectory = false; + } + + it1 = properties.find( MyProperty( Size ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( dirSize ) ); + + it1 = properties.find( MyProperty( IsReadOnly ) ); + if( it1 != properties.end() ) + { + if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) ) + { + sal_uInt64 Attr = aFileStatus.getAttributes(); + bool readonly = ( Attr & osl_File_Attribute_ReadOnly ) != 0; + it1->setValue( uno::Any( readonly ) ); + } + } + + it1 = properties.find( MyProperty( IsHidden ) ); + if( it1 != properties.end() ) + { + if( aFileStatus.isValid( osl_FileStatus_Mask_Attributes ) ) + { + sal_uInt64 Attr = aFileStatus.getAttributes(); + bool ishidden = ( Attr & osl_File_Attribute_Hidden ) != 0; + it1->setValue( uno::Any( ishidden ) ); + } + } + + it1 = properties.find( MyProperty( DateModified ) ); + if( it1 != properties.end() ) + { + if( aFileStatus.isValid( osl_FileStatus_Mask_ModifyTime ) ) + { + TimeValue temp = aFileStatus.getModifyTime(); + + // Convert system time to local time (for EA) + TimeValue myLocalTime; + if (!osl_getLocalTimeFromSystemTime( &temp, &myLocalTime )) + { + SAL_WARN( + "ucb.ucp.file", + "cannot convert (" << temp.Seconds << ", " << temp.Nanosec + << ") to local time"); + myLocalTime = temp; + } + + oslDateTime myDateTime; + osl_getDateTimeFromTimeValue( &myLocalTime, &myDateTime ); + util::DateTime aDateTime; + + aDateTime.NanoSeconds = myDateTime.NanoSeconds; + aDateTime.Seconds = myDateTime.Seconds; + aDateTime.Minutes = myDateTime.Minutes; + aDateTime.Hours = myDateTime.Hours; + aDateTime.Day = myDateTime.Day; + aDateTime.Month = myDateTime.Month; + aDateTime.Year = myDateTime.Year; + it1->setValue( uno::Any( aDateTime ) ); + } + } + + it1 = properties.find( MyProperty( CreatableContentsInfo ) ); + if( it1 != properties.end() ) + it1->setValue( uno::Any( + isDirectory || !aFileStatus.isValid( osl_FileStatus_Mask_Type ) + ? queryCreatableContentsInfo() + : uno::Sequence< ucb::ContentInfo >() ) ); +} + + +// Special optimized method for getting the properties of a +// directoryitem, which is returned by osl::DirectoryItem::getNextItem() + + +bool +TaskManager::getv( + const uno::Sequence< beans::Property >& properties, + osl::DirectoryItem& aDirItem, + OUString& aUnqPath, + bool& aIsRegular, + uno::Reference< sdbc::XRow > & row ) +{ + uno::Sequence< uno::Any > seq( properties.getLength() ); + + sal_Int32 n_Mask; + getMaskFromProperties( n_Mask,properties ); + + // Always retrieve the type and the target URL because item might be a link + osl::FileStatus aFileStatus( n_Mask | + osl_FileStatus_Mask_FileURL | + osl_FileStatus_Mask_Type | + osl_FileStatus_Mask_LinkTargetURL ); + + osl::FileBase::RC aRes = aDirItem.getFileStatus( aFileStatus ); + if ( aRes != osl::FileBase::E_None ) + { + SAL_WARN( + "ucb.ucp.file", + "osl::DirectoryItem::getFileStatus failed with " << +aRes); + return false; + } + + aUnqPath = aFileStatus.getFileURL(); + + // If the directory item type is a link retrieve the type of the target + + if ( aFileStatus.getFileType() == osl::FileStatus::Link ) + { + // Assume failure + aIsRegular = false; + osl::DirectoryItem aTargetItem; + (void)osl::DirectoryItem::get( aFileStatus.getLinkTargetURL(), aTargetItem ); + if ( aTargetItem.is() ) + { + osl::FileStatus aTargetStatus( osl_FileStatus_Mask_Type ); + + if ( osl::FileBase::E_None == aTargetItem.getFileStatus( aTargetStatus ) ) + aIsRegular = + aTargetStatus.getFileType() == osl::FileStatus::Regular; + } + } + else + aIsRegular = aFileStatus.getFileType() == osl::FileStatus::Regular; + + { + std::unique_lock aGuard( m_aMutex ); + + insertDefaultProperties( aGuard, aUnqPath ); + + TaskManager::ContentMap::iterator it = m_aContent.find( aUnqPath ); + commit( aGuard, it, aFileStatus ); + + PropertySet& propset = it->second.properties; + + std::transform(properties.begin(), properties.end(), seq.getArray(), + [&propset](const beans::Property& rProp) -> uno::Any { + MyProperty readProp( rProp.Name ); + auto it1 = propset.find( readProp ); + if( it1 == propset.end() ) + return uno::Any(); + return it1->getValue(); + }); + } + + row = new XRow_impl( this,seq ); + return true; +} + + +// EventListener + + +std::vector< ContentEventNotifier > +TaskManager::getContentEventListeners( const OUString& aName ) +{ + std::vector< ContentEventNotifier > listeners; + { + std::unique_lock aGuard( m_aMutex ); + TaskManager::ContentMap::iterator it = m_aContent.find( aName ); + if( it != m_aContent.end() && !it->second.notifier.empty() ) + { + std::vector<Notifier*>& listOfNotifiers = it->second.notifier; + for (auto const& pointer : listOfNotifiers) + { + std::optional<ContentEventNotifier> notifier = pointer->cCEL(); + if( notifier ) + listeners.push_back( std::move(*notifier) ); + } + } + } + return listeners; +} + + +std::vector< ContentEventNotifier > +TaskManager::getContentDeletedEventListeners( const OUString& aName ) +{ + std::vector< ContentEventNotifier > listeners; + { + std::unique_lock aGuard( m_aMutex ); + TaskManager::ContentMap::iterator it = m_aContent.find( aName ); + if( it != m_aContent.end() && !it->second.notifier.empty() ) + { + std::vector<Notifier*>& listOfNotifiers = it->second.notifier; + for (auto const& pointer : listOfNotifiers) + { + std::optional<ContentEventNotifier> notifier = pointer->cDEL(); + if( notifier ) + listeners.push_back( std::move(*notifier) ); + } + } + } + return listeners; +} + +void TaskManager::notifyInsert(const std::vector<ContentEventNotifier>& listeners, + const OUString& aChildName) +{ + for (const auto & l : listeners ) + { + l.notifyChildInserted( aChildName ); + } +} + +void TaskManager::notifyContentDeleted( + const std::vector<ContentEventNotifier>& listeners) +{ + for( auto const & l : listeners ) + { + l.notifyDeleted(); + } +} + +void TaskManager::notifyContentRemoved( + const std::vector<ContentEventNotifier>& listeners, const OUString& aChildName) +{ + for( auto const & l : listeners ) + { + l.notifyRemoved( aChildName ); + } +} + + +std::vector< PropertySetInfoChangeNotifier > +TaskManager::getPropertySetListeners( const OUString& aName ) +{ + std::vector< PropertySetInfoChangeNotifier > listeners; + { + std::unique_lock aGuard( m_aMutex ); + TaskManager::ContentMap::iterator it = m_aContent.find( aName ); + if( it != m_aContent.end() && !it->second.notifier.empty() ) + { + std::vector<Notifier*>& listOfNotifiers = it->second.notifier; + for (auto const& pointer : listOfNotifiers) + { + std::optional<PropertySetInfoChangeNotifier> notifier = pointer->cPSL(); + if( notifier ) + listeners.push_back( std::move(*notifier) ); + } + } + } + return listeners; +} + +void TaskManager::notifyPropertyAdded( + const std::vector<PropertySetInfoChangeNotifier>& listeners, + const OUString& aPropertyName) +{ + for( auto const & l : listeners ) + { + l.notifyPropertyAdded( aPropertyName ); + } +} + +void TaskManager::notifyPropertyRemoved( + const std::vector<PropertySetInfoChangeNotifier>& listeners, + const OUString& aPropertyName) +{ + for( auto const & l : listeners ) + { + l.notifyPropertyRemoved( aPropertyName ); + } +} + + +std::vector< ContentEventNotifier > +TaskManager::getContentExchangedEventListeners( const OUString& aOldPrefix, + const OUString& aNewPrefix, + bool withChildren ) +{ + std::vector< ContentEventNotifier > aVector; + + sal_Int32 count; + OUString aOldName; + OUString aNewName; + std::vector< OUString > oldChildList; + + { + std::unique_lock aGuard( m_aMutex ); + + if( ! withChildren ) + { + aOldName = aOldPrefix; + aNewName = aNewPrefix; + count = 1; + } + else + { + for (auto const& content : m_aContent) + { + if( isChild( aOldPrefix, content.first ) ) + { + oldChildList.push_back( content.first ); + } + } + count = oldChildList.size(); + } + + + for( sal_Int32 j = 0; j < count; ++j ) + { + if( withChildren ) + { + aOldName = oldChildList[j]; + aNewName = newName( aNewPrefix,aOldPrefix,aOldName ); + } + + TaskManager::ContentMap::iterator itold = m_aContent.find( aOldName ); + if( itold != m_aContent.end() ) + { + TaskManager::ContentMap::iterator itnew = m_aContent.emplace( + aNewName,UnqPathData() ).first; + + // copy Ownership also + itnew->second.properties = std::move(itold->second.properties); + + // copy existing list + std::vector< Notifier* > copyList; + std::swap(copyList, itnew->second.notifier); + itnew->second.notifier = std::move(itold->second.notifier); + + m_aContent.erase( itold ); + + if (itnew != m_aContent.end()) + { + if (!itnew->second.notifier.empty()) + { + std::vector<Notifier*>& listOfNotifiers = itnew->second.notifier; + for (auto const& pointer : listOfNotifiers) + { + std::optional<ContentEventNotifier> notifier = pointer->cEXC( aNewName ); + if( notifier ) + aVector.push_back( std::move(*notifier) ); + } + } + + // Merge with preexisting notifiers + // However, these may be in status BaseContent::Deleted + itnew->second.notifier.insert(itnew->second.notifier.end(), + copyList.begin(), copyList.end() ); + } + } + } + } + + return aVector; +} + +void TaskManager::notifyContentExchanged( + const std::vector<ContentEventNotifier>& listeners_vec) +{ + for( auto & l : listeners_vec) + { + l.notifyExchanged(); + } +} + + +std::vector< PropertyChangeNotifier > +TaskManager::getPropertyChangeNotifier( const OUString& aName ) +{ + std::vector< PropertyChangeNotifier > listeners; + { + std::unique_lock aGuard( m_aMutex ); + TaskManager::ContentMap::iterator it = m_aContent.find( aName ); + if( it != m_aContent.end() && !it->second.notifier.empty() ) + { + std::vector<Notifier*>& listOfNotifiers = it->second.notifier; + for (auto const& pointer : listOfNotifiers) + { + std::optional<PropertyChangeNotifier> notifier = pointer->cPCL(); + if( notifier ) + listeners.push_back( std::move(*notifier) ); + } + } + } + return listeners; +} + +void TaskManager::notifyPropertyChanges( + const std::vector<PropertyChangeNotifier>& listeners, + const uno::Sequence<beans::PropertyChangeEvent>& seqChanged) +{ + for( auto const & l : listeners ) + { + l.notifyPropertyChanged( seqChanged ); + } +} + + +/********************************************************************************/ +/* remove persistent propertyset */ +/********************************************************************************/ + +void +TaskManager::erasePersistentSetWithoutChildren( const OUString& aUnqPath ) +{ + { + // Release possible references + std::unique_lock aGuard( m_aMutex ); + ContentMap::iterator it = m_aContent.find( aUnqPath ); + if( it != m_aContent.end() ) + { + it->second.xS = nullptr; + it->second.xC = nullptr; + it->second.xA = nullptr; + + it->second.properties.clear(); + } + } + + m_xFileRegistry->removePropertySet( aUnqPath ); +} + +void +TaskManager::erasePersistentSet( const OUString& aUnqPath, + bool withChildren ) +{ + if( ! m_xFileRegistry.is() ) + { + OSL_ASSERT( m_xFileRegistry.is() ); + return; + } + + if( ! withChildren ) + { + erasePersistentSetWithoutChildren(aUnqPath); + return; + } + + uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY ); + const uno::Sequence< OUString > seqNames = xName->getElementNames(); + + OUString old_Name = aUnqPath; + + for( const auto& rName : seqNames ) + { + if( ! ( isChild( old_Name,rName ) ) ) + continue; + + old_Name = rName; + + erasePersistentSetWithoutChildren(old_Name); + } +} + + +/********************************************************************************/ +/* copy persistent propertyset */ +/* from srcUnqPath to dstUnqPath */ +/********************************************************************************/ + +void +TaskManager::copyPersistentSetWithoutChildren( const OUString& srcUnqPath, + const OUString& dstUnqPath ) +{ + uno::Reference< XPersistentPropertySet > x_src = + m_xFileRegistry->openPropertySet( srcUnqPath,false ); + m_xFileRegistry->removePropertySet( dstUnqPath ); + + if( ! x_src.is() ) + return; + + const uno::Sequence< beans::Property > seqProperty = + x_src->getPropertySetInfo()->getProperties(); + + if( ! seqProperty.hasElements() ) + return; + + uno::Reference< XPersistentPropertySet > + x_dstS = m_xFileRegistry->openPropertySet( dstUnqPath,true ); + uno::Reference< beans::XPropertyContainer > + x_dstC( x_dstS,uno::UNO_QUERY ); + + for( const auto& rProperty : seqProperty ) + { + x_dstC->addProperty( rProperty.Name, + rProperty.Attributes, + x_src->getPropertyValue( rProperty.Name ) ); + } +} + +void +TaskManager::copyPersistentSet( const OUString& srcUnqPath, + const OUString& dstUnqPath, + bool withChildren ) +{ + if( ! m_xFileRegistry.is() ) + { + OSL_ASSERT( m_xFileRegistry.is() ); + return; + } + + if( ! withChildren ) + { + copyPersistentSetWithoutChildren(srcUnqPath, dstUnqPath); + return; + } + + uno::Reference< container::XNameAccess > xName( m_xFileRegistry,uno::UNO_QUERY ); + const uno::Sequence< OUString > seqNames = xName->getElementNames(); + + OUString new_Name; + + for( const auto& rName : seqNames ) + { + if( ! ( isChild( srcUnqPath,rName ) ) ) + continue; + + new_Name = newName( dstUnqPath,srcUnqPath,rName ); + + copyPersistentSetWithoutChildren(rName, new_Name); + } +} + +uno::Sequence< ucb::ContentInfo > TaskManager::queryCreatableContentsInfo() +{ + + + uno::Sequence< beans::Property > props + { + { "Title", -1, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND } + }; + return + { + { FileContentType, ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | ucb::ContentInfoAttribute::KIND_DOCUMENT, props }, + { FolderContentType, ucb::ContentInfoAttribute::KIND_FOLDER, props } + }; +} + +/*******************************************************************************/ +/* */ +/* some miscellaneous static functions */ +/* */ +/*******************************************************************************/ + +void +TaskManager::getScheme( OUString& Scheme ) +{ + Scheme = "file"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/filtask.hxx b/ucb/source/ucp/file/filtask.hxx new file mode 100644 index 0000000000..9d41692554 --- /dev/null +++ b/ucb/source/ucp/file/filtask.hxx @@ -0,0 +1,647 @@ +/* -*- 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 <o3tl/sorted_vector.hxx> +#include <osl/file.hxx> +#include <rtl/ustring.hxx> + +#include <osl/mutex.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/ucb/ContentInfo.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/XPersistentPropertySet.hpp> +#include <com/sun/star/ucb/XPropertySetRegistry.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include "filerror.hxx" +#include "filnot.hxx" +#include <mutex> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +namespace fileaccess +{ + class BaseContent; + class FileProvider; + class XPropertySetInfo_impl; + class XCommandInfo_impl; + class XResultSet_impl; + + /* + * The relevant methods in this class all have as first argument the CommandId, + * so if necessary, every method has access to its relevant XInteractionHandler and + * XProgressHandler. + */ + + + class TaskManager + { + friend class XPropertySetInfo_impl; + friend class XResultSet_impl; + friend class XCommandInfo_impl; + + private: + + class TaskHandling + { + private: + + bool m_bHandled; + sal_Int32 m_nErrorCode,m_nMinorCode; + css::uno::Reference< css::task::XInteractionHandler > m_xInteractionHandler; + css::uno::Reference< css::ucb::XCommandEnvironment > m_xCommandEnvironment; + + + public: + + explicit TaskHandling( + css::uno::Reference< css::ucb::XCommandEnvironment > xCommandEnv ) + : m_bHandled( false ), + m_nErrorCode( TASKHANDLER_NO_ERROR ), + m_nMinorCode( TASKHANDLER_NO_ERROR ), + m_xCommandEnvironment( std::move(xCommandEnv) ) + { + } + + void setHandled() + { + m_bHandled = true; + } + + bool isHandled() const + { + return m_bHandled; + } + + void clearError() + { + m_nErrorCode = TASKHANDLER_NO_ERROR; + m_nMinorCode = TASKHANDLER_NO_ERROR; + } + + void installError( sal_Int32 nErrorCode, + sal_Int32 nMinorCode ) + { + m_nErrorCode = nErrorCode; + m_nMinorCode = nMinorCode; + } + + sal_Int32 getInstalledError() const + { + return m_nErrorCode; + } + + sal_Int32 getMinorErrorCode() const + { + return m_nMinorCode; + } + + css::uno::Reference< css::task::XInteractionHandler > const & + getInteractionHandler() + { + if( ! m_xInteractionHandler.is() && m_xCommandEnvironment.is() ) + m_xInteractionHandler = m_xCommandEnvironment->getInteractionHandler(); + + return m_xInteractionHandler; + } + + const css::uno::Reference< css::ucb::XCommandEnvironment >& + getCommandEnvironment() const + { + return m_xCommandEnvironment; + } + + }; // end class TaskHandling + + + typedef std::unordered_map< sal_Int32,TaskHandling > TaskMap; + private: + + std::mutex m_aMutex; + sal_Int32 m_nCommandId; + TaskMap m_aTaskMap; + + + public: + class MyProperty + { + private: + OUString PropertyName; + sal_Int32 Handle; + bool isNative; + css::uno::Type Typ; // Duplicates information in Value + css::uno::Any Value; + css::beans::PropertyState State; + sal_Int16 Attributes; + public: + explicit MyProperty( const OUString& thePropertyName ); + MyProperty( bool theIsNative, + const OUString& thePropertyName, + sal_Int32 theHandle, + const css::uno::Type& theTyp, + const css::uno::Any& theValue, + const css::beans::PropertyState& theState, + sal_Int16 theAttributes ); + + inline const bool& IsNative() const; + const OUString& getPropertyName() const { return PropertyName; } + inline const sal_Int32& getHandle() const; + inline const css::uno::Type& getType() const; + inline const css::uno::Any& getValue() const; + inline const css::beans::PropertyState& getState() const; + inline const sal_Int16& getAttributes() const; + + // The set* functions are declared const, because the key of "this" stays intact + inline void setValue( css::uno::Any theValue ) const; + inline void setState( const css::beans::PropertyState& theState ) const; + }; + + struct MyPropertyLess + { + bool operator()( const MyProperty& rKey1, const MyProperty& rKey2 ) const + { + return rKey1.getPropertyName() < rKey2.getPropertyName(); + } + }; + + typedef o3tl::sorted_vector< MyProperty, MyPropertyLess > PropertySet; + + class UnqPathData + { + public: + UnqPathData(); + UnqPathData(UnqPathData&&); + ~UnqPathData(); + + PropertySet properties; + std::vector< Notifier* > notifier; + + // Three views on the PersistentPropertySet + css::uno::Reference< css::ucb::XPersistentPropertySet > xS; + css::uno::Reference< css::beans::XPropertyContainer > xC; + css::uno::Reference< css::beans::XPropertyAccess > xA; + }; + + typedef std::unordered_map< OUString,UnqPathData > ContentMap; + + TaskManager( const css::uno::Reference< css::uno::XComponentContext >& rxContext, + FileProvider* pProvider, bool bWithConfig ); + ~TaskManager(); + + /// @throws css::ucb::DuplicateCommandIdentifierException + void startTask( + sal_Int32 CommandId, + const css::uno::Reference< css::ucb::XCommandEnvironment >& xCommandEnv ); + + sal_Int32 getCommandId(); + + + /** + * The error code may be one of the error codes defined in + * filerror.hxx. + * The minor code refines the information given in ErrorCode. + */ + + void installError( sal_Int32 CommandId, + sal_Int32 ErrorCode, + sal_Int32 minorCode = TASKHANDLER_NO_ERROR ); + + void retrieveError( sal_Int32 CommandId, + sal_Int32 &ErrorCode, + sal_Int32 &minorCode); + + /** + * Deinstalls the task and evaluates a possibly set error code. + * "endTask" throws in case an error code is set the corresponding exception. + */ + + void endTask( sal_Int32 CommandId, + // the physical URL of the object + const OUString& aUnqPath, + BaseContent* pContent); + + + /** + * Handles an interactionrequest + */ + + void handleTask( sal_Int32 CommandId, + const css::uno::Reference< css::task::XInteractionRequest >& request ); + + /** + * Clears any error which are set on the commandid + */ + + void clearError( sal_Int32 ); + + /** + * This two methods register and deregister a change listener for the content belonging + * to URL aUnqPath + */ + + void registerNotifier( const OUString& aUnqPath,Notifier* pNotifier ); + + void deregisterNotifier( const OUString& aUnqPath,Notifier* pNotifier ); + + + /** + * Used to associate and deassociate a new property with + * the content belonging to URL UnqPath. + * The default value and the attributes are input + * + * @throws css::beans::PropertyExistException + * @throws css::beans::IllegalTypeException + * @throws css::uno::RuntimeException + */ + + void associate( const OUString& UnqPath, + const OUString& PropertyName, + const css::uno::Any& DefaultValue, + const sal_Int16 Attributes ); + + /// @throws css::beans::UnknownPropertyException + /// @throws css::beans::NotRemoveableException + /// @throws css::uno::RuntimeException + void deassociate( const OUString& UnqPath, + const OUString& PropertyName ); + + + // Every method having a command id is not allowed to throw anything, + // but instead must install every error code in the task handler + + + /** + * Given an xOutputStream, this method writes the content of the file belonging to + * URL aUnqPath into the XOutputStream + */ + + void page( sal_Int32 CommandId, + const OUString& aUnqPath, + const css::uno::Reference< css::io::XOutputStream >& xOutputStream ); + + + /** + * Given a file URL aUnqPath, this methods returns a XInputStream which reads from the open file. + */ + + css::uno::Reference< css::io::XInputStream > + open( sal_Int32 CommandId, + const OUString& aUnqPath, + bool bLock ); + + + /** + * Given a file URL aUnqPath, this methods returns a XStream which can be used + * to read and write from/to the file. + */ + + css::uno::Reference< css::io::XStream > + open_rw( sal_Int32 CommandId, + const OUString& aUnqPath, + bool bLock ); + + + /** + * This method returns the result set containing the children of the directory belonging + * to file URL aUnqPath + */ + + css::uno::Reference< css::ucb::XDynamicResultSet > + ls( sal_Int32 CommandId, + const OUString& aUnqPath, + const sal_Int32 OpenMode, + const css::uno::Sequence< css::beans::Property >& sProperty, + const css::uno::Sequence< css::ucb::NumberedSortingInfo > & sSortingInfo ); + + + /** + * Info methods + */ + + // Info for commands + css::uno::Reference< css::ucb::XCommandInfo > + info_c(); + + // Info for the properties + css::uno::Reference< css::beans::XPropertySetInfo > + info_p( const OUString& aUnqPath ); + + + /** + * Sets the values of the properties belonging to fileURL aUnqPath + */ + + css::uno::Sequence< css::uno::Any > + setv( const OUString& aUnqPath, + const css::uno::Sequence< css::beans::PropertyValue >& values ); + + + /** + * Reads the values of the properties belonging to fileURL aUnqPath; + * Returns an XRow object containing the values in the requested order. + */ + + css::uno::Reference< css::sdbc::XRow > + getv( sal_Int32 CommandId, + const OUString& aUnqPath, + const css::uno::Sequence< css::beans::Property >& properties ); + + + /********************************************************************************/ + /* transfer-commands */ + /********************************************************************************/ + + /** + * Moves the content belonging to fileURL srcUnqPath to fileURL dstUnqPath( files and directories ) + */ + + void + move( sal_Int32 CommandId, + const OUString& srcUnqPath, // Full file(folder)-path + const OUString& dstUnqPath, // Path to the destination-directory + const sal_Int32 NameClash ); + + /** + * Copies the content belonging to fileURL srcUnqPath to fileURL dstUnqPath ( files and directories ) + */ + + void + copy( sal_Int32 CommandId, // See "move" + const OUString& srcUnqPath, + const OUString& dstUnqPath, + sal_Int32 NameClash ); + + enum class FileUrlType { Folder = 1, File = -1, Unknown = 0 }; + + /** + * Deletes the content belonging to fileURL aUnqPath( recursively in case of directory ) + */ + + bool + remove( sal_Int32 CommandId, + const OUString& aUnqPath, + FileUrlType eTypeToMove = FileUrlType::Unknown, + bool MustExist = true ); + + + /********************************************************************************/ + /* write and create - commandos */ + /********************************************************************************/ + + /** + * Creates new directory with given URL, recursively if necessary + * Return:: success of operation + */ + + bool + mkdir( sal_Int32 CommandId, + const OUString& aDirectoryName, + bool OverWrite ); + + + /** + * Creates new file with given URL. + * The content of aInputStream becomes the content of the file + * Return:: success of operation + */ + + bool + mkfil( sal_Int32 CommandId, + const OUString& aFileName, + bool OverWrite, + const css::uno::Reference< css::io::XInputStream >& aInputStream ); + + + /** + * writes to the file with given URL. + * The content of aInputStream becomes the content of the file + * Return:: success of operation + */ + bool + write( sal_Int32 CommandId, + const OUString& aUnqPath, + bool OverWrite, + const css::uno::Reference< css::io::XInputStream >& aInputStream ); + + + void insertDefaultProperties( const OUString& aUnqPath ); + + static css::uno::Sequence< css::ucb::ContentInfo > + queryCreatableContentsInfo(); + + + /******************************************************************************/ + /* */ + /* mapping of file urls */ + /* to uncpath and vice versa */ + /* */ + /******************************************************************************/ + + static bool getUnqFromUrl( const OUString& Url, OUString& Unq ); + + static bool getUrlFromUnq( const OUString& Unq, OUString& Url ); + + + FileProvider* m_pProvider; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::ucb::XPropertySetRegistry > m_xFileRegistry; + + private: + + void insertDefaultProperties( std::unique_lock<std::mutex>& rGuard, const OUString& aUnqPath ); + + /********************************************************************************/ + /* get eventListeners */ + /********************************************************************************/ + + std::vector< ContentEventNotifier > + getContentEventListeners( const OUString& aName ); + + std::vector< ContentEventNotifier > + getContentDeletedEventListeners( const OUString& aName ); + + std::vector< ContentEventNotifier > + getContentExchangedEventListeners( const OUString& aOldPrefix, + const OUString& aNewPrefix, + bool withChildren ); + + std::vector< PropertyChangeNotifier > + getPropertyChangeNotifier( const OUString& aName ); + + std::vector< PropertySetInfoChangeNotifier > + getPropertySetListeners( const OUString& aName ); + + + /********************************************************************************/ + /* notify eventListeners */ + /********************************************************************************/ + + static void notifyPropertyChanges( + const std::vector<PropertyChangeNotifier>& listeners, + const css::uno::Sequence<css::beans::PropertyChangeEvent>& seqChanged); + + static void notifyContentExchanged( + const std::vector<ContentEventNotifier>& listeners_vec); + + static void + notifyInsert(const std::vector<ContentEventNotifier>& listeners, + const OUString& aChildName); + + static void + notifyContentDeleted(const std::vector<ContentEventNotifier>& listeners); + + static void + notifyContentRemoved(const std::vector<ContentEventNotifier>& listeners, + const OUString& aChildName); + + static void notifyPropertyAdded( + const std::vector<PropertySetInfoChangeNotifier>& listeners, + const OUString& aPropertyName); + + static void notifyPropertyRemoved( + const std::vector<PropertySetInfoChangeNotifier>& listeners, + const OUString& aPropertyName); + + /********************************************************************************/ + /* remove persistent propertyset */ + /********************************************************************************/ + + void erasePersistentSetWithoutChildren( const OUString& aUnqPath ); + void erasePersistentSet( const OUString& aUnqPath, + bool withChildren = false ); + + /********************************************************************************/ + /* copy persistent propertyset */ + /* from srcUnqPath to dstUnqPath */ + /********************************************************************************/ + + void copyPersistentSetWithoutChildren( const OUString& srcUnqPath, + const OUString& dstUnqPath ); + void copyPersistentSet( const OUString& srcUnqPath, + const OUString& dstUnqPath, + bool withChildren ); + + + // Special optimized method for getting the properties of a directoryitem, which + // is returned by osl::DirectoryItem::getNextItem() + + bool + getv( const css::uno::Sequence< css::beans::Property >& properties, + osl::DirectoryItem& DirItem, + OUString& aUnqPath, + bool& bIsRegular, + css::uno::Reference< css::sdbc::XRow > & row ); + + + /** + * Load the properties from configuration, if create == true create them. + * The Properties are stored under the url belonging to it->first. + */ + + void load( const TaskManager::ContentMap::iterator& it, + bool create ); + + /** + * Commit inserts the determined properties in the filestatus object into + * the internal map, so that is possible to determine on a subsequent + * setting of file properties which properties have changed without filestat + */ + + void + commit( + std::unique_lock<std::mutex>& rGuard, + const TaskManager::ContentMap::iterator& it, + const osl::FileStatus& aFileStatus ); + + /** + * Given a Sequence of properties seq, this method determines the mask + * used to instantiate an osl::FileStatus, so that a call to + * osl::DirectoryItem::getFileStatus fills the required fields. + */ + + static void + getMaskFromProperties( + sal_Int32& n_Mask, + const css::uno::Sequence< css::beans::Property >& seq ); + + + // Helper function for public copy + + osl::FileBase::RC + copy_recursive( + const OUString& srcUnqPath, + const OUString& dstUnqPath, + FileUrlType TypeToCopy, + bool testExistence ); + + + // Helper function for mkfil,mkdir and write + // Creates whole path + // returns success of the operation + // The call determines the errorCode, which should be used to install + // any error + + bool + ensuredir( sal_Int32 CommandId, + const OUString& aDirectoryName, + sal_Int32 errorCode ); + + // General + ContentMap m_aContent; + + + public: + + static constexpr OUString FolderContentType = + u"application/vnd.sun.staroffice.fsys-folder"_ustr; + static constexpr OUString FileContentType = + u"application/vnd.sun.staroffice.fsys-file"_ustr; + + + private: + + PropertySet m_aDefaultProperties; + css::uno::Sequence< css::ucb::CommandInfo > m_sCommandInfo; + + public: + // Miscellaneous: + // Methods for "writeComponentInfo" and "createComponentFactory" + + static void getScheme( OUString& Scheme ); + }; + +} // end namespace TaskHandling + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/prov.cxx b/ucb/source/ucp/file/prov.cxx new file mode 100644 index 0000000000..eab4ec5300 --- /dev/null +++ b/ucb/source/ucp/file/prov.cxx @@ -0,0 +1,447 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <osl/security.hxx> +#include <osl/file.hxx> +#include <osl/socket.h> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/ucb/FileSystemNotation.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <cppuhelper/supportsservice.hxx> +#include "filglob.hxx" +#include "filid.hxx" +#include "filtask.hxx" +#include "bc.hxx" +#include "prov.hxx" + +using namespace fileaccess; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::ucb; +using namespace com::sun::star::container; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + + +/****************************************************************************/ +/* */ +/* */ +/* FileProvider */ +/* */ +/* */ +/****************************************************************************/ +FileProvider::FileProvider( const Reference< XComponentContext >& rxContext ) + : m_xContext(rxContext) + , m_FileSystemNotation(FileSystemNotation::UNKNOWN_NOTATION) +{ +} + +FileProvider::~FileProvider() +{ +} + +// XInitialization +void FileProvider::init() +{ + if( ! m_pMyShell ) + m_pMyShell.reset( new TaskManager( m_xContext, this, true ) ); +} + + +void SAL_CALL +FileProvider::initialize( + const Sequence< Any >& aArguments ) +{ + if( ! m_pMyShell ) { + OUString config; + if( aArguments.hasElements() && + (aArguments[0] >>= config) && + config == "NoConfig" ) + m_pMyShell.reset( new TaskManager( m_xContext, this, false ) ); + else + m_pMyShell.reset( new TaskManager( m_xContext, this, true ) ); + } +} + +// XServiceInfo methods. +OUString SAL_CALL +FileProvider::getImplementationName() +{ + return "com.sun.star.comp.ucb.FileProvider"; +} + +sal_Bool SAL_CALL FileProvider::supportsService(const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL +FileProvider::getSupportedServiceNames() +{ + return { "com.sun.star.ucb.FileContentProvider" }; +} + +// XContent + + +Reference< XContent > SAL_CALL +FileProvider::queryContent( + const Reference< XContentIdentifier >& xIdentifier ) +{ + init(); + OUString aUnc; + bool err = fileaccess::TaskManager::getUnqFromUrl( xIdentifier->getContentIdentifier(), + aUnc ); + + if( err ) + { + throw IllegalIdentifierException( THROW_WHERE ); + } + + return Reference< XContent >( new BaseContent( m_pMyShell.get(), xIdentifier, aUnc ) ); +} + + +sal_Int32 SAL_CALL +FileProvider::compareContentIds( + const Reference< XContentIdentifier >& Id1, + const Reference< XContentIdentifier >& Id2 ) +{ + init(); + OUString aUrl1 = Id1->getContentIdentifier(); + OUString aUrl2 = Id2->getContentIdentifier(); + + sal_Int32 iComp = aUrl1.compareTo( aUrl2 ); + + if ( 0 != iComp ) + { + OUString aPath1, aPath2; + + fileaccess::TaskManager::getUnqFromUrl( aUrl1, aPath1 ); + fileaccess::TaskManager::getUnqFromUrl( aUrl2, aPath2 ); + + osl::FileBase::RC error; + osl::DirectoryItem aItem1, aItem2; + + error = osl::DirectoryItem::get( aPath1, aItem1 ); + if ( error == osl::FileBase::E_None ) + error = osl::DirectoryItem::get( aPath2, aItem2 ); + + if ( error != osl::FileBase::E_None ) + return iComp; + + osl::FileStatus aStatus1( osl_FileStatus_Mask_FileURL ); + osl::FileStatus aStatus2( osl_FileStatus_Mask_FileURL ); + error = aItem1.getFileStatus( aStatus1 ); + if ( error == osl::FileBase::E_None ) + error = aItem2.getFileStatus( aStatus2 ); + + if ( error == osl::FileBase::E_None ) + { + iComp = aStatus1.getFileURL().compareTo( aStatus2.getFileURL() ); + +// Quick hack for Windows to threat all file systems as case insensitive +#ifdef _WIN32 + if ( 0 != iComp ) + { + error = osl::FileBase::getSystemPathFromFileURL( aStatus1.getFileURL(), aPath1 ); + if ( error == osl::FileBase::E_None ) + error = osl::FileBase::getSystemPathFromFileURL( aStatus2.getFileURL(), aPath2 ); + + if ( error == osl::FileBase::E_None ) + iComp = aPath1.compareToIgnoreAsciiCase( aPath2 ); + } +#endif + } + } + + return iComp; +} + + +Reference< XContentIdentifier > SAL_CALL +FileProvider::createContentIdentifier( + const OUString& ContentId ) +{ + init(); + return new FileContentIdentifier( ContentId,false ); +} + + +//XPropertySetInfoImpl + +namespace { + +class XPropertySetInfoImpl2 + : public cppu::OWeakObject, + public XPropertySetInfo +{ +public: + XPropertySetInfoImpl2(); + + // XInterface + virtual Any SAL_CALL + queryInterface( const Type& aType ) override; + + virtual void SAL_CALL + acquire() + noexcept override; + + virtual void SAL_CALL + release() + noexcept override; + + + virtual Sequence< Property > SAL_CALL + getProperties() override; + + virtual Property SAL_CALL + getPropertyByName( const OUString& aName ) override; + + virtual sal_Bool SAL_CALL + hasPropertyByName( const OUString& Name ) override; + + +private: + Sequence< Property > m_seq; +}; + +} + +XPropertySetInfoImpl2::XPropertySetInfoImpl2() + : m_seq{ Property( "HostName", + -1, + cppu::UnoType<OUString>::get(), + PropertyAttribute::READONLY ), + Property( "HomeDirectory", + -1, + cppu::UnoType<OUString>::get(), + PropertyAttribute::READONLY ), + Property( "FileSystemNotation", + -1, + cppu::UnoType<sal_Int32>::get(), + PropertyAttribute::READONLY )} +{ +} + +void SAL_CALL +XPropertySetInfoImpl2::acquire() + noexcept +{ + OWeakObject::acquire(); +} + + +void SAL_CALL +XPropertySetInfoImpl2::release() + noexcept +{ + OWeakObject::release(); +} + + +Any SAL_CALL +XPropertySetInfoImpl2::queryInterface( const Type& rType ) +{ + Any aRet = cppu::queryInterface( rType, + static_cast< XPropertySetInfo* >(this) ); + return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType ); +} + + +Property SAL_CALL +XPropertySetInfoImpl2::getPropertyByName( const OUString& aName ) +{ + auto pProp = std::find_if(std::cbegin(m_seq), std::cend(m_seq), + [&aName](const Property& rProp) { return rProp.Name == aName; }); + if (pProp != std::cend(m_seq)) + return *pProp; + + throw UnknownPropertyException( aName ); +} + + +Sequence< Property > SAL_CALL +XPropertySetInfoImpl2::getProperties() +{ + return m_seq; +} + + +sal_Bool SAL_CALL +XPropertySetInfoImpl2::hasPropertyByName( + const OUString& aName ) +{ + return std::any_of(std::cbegin(m_seq), std::cend(m_seq), + [&aName](const Property& rProp) { return rProp.Name == aName; }); +} + + +void FileProvider::initProperties() +{ + std::scoped_lock aGuard( m_aMutex ); + if( m_xPropertySetInfo.is() ) + return; + + osl_getLocalHostname( &m_HostName.pData ); + +#if defined ( UNX ) + m_FileSystemNotation = FileSystemNotation::UNIX_NOTATION; +#elif defined( _WIN32 ) + m_FileSystemNotation = FileSystemNotation::DOS_NOTATION; +#else + m_FileSystemNotation = FileSystemNotation::UNKNOWN_NOTATION; +#endif + osl::Security aSecurity; + aSecurity.getHomeDir( m_HomeDirectory ); + + // static const sal_Int32 UNKNOWN_NOTATION = (sal_Int32)0; + // static const sal_Int32 UNIX_NOTATION = (sal_Int32)1; + // static const sal_Int32 DOS_NOTATION = (sal_Int32)2; + // static const sal_Int32 MAC_NOTATION = (sal_Int32)3; + + m_xPropertySetInfo = new XPropertySetInfoImpl2(); +} + + +// XPropertySet + +Reference< XPropertySetInfo > SAL_CALL +FileProvider::getPropertySetInfo( ) +{ + initProperties(); + return m_xPropertySetInfo; +} + + +void SAL_CALL +FileProvider::setPropertyValue( const OUString& aPropertyName, + const Any& ) +{ + if( !(aPropertyName == "FileSystemNotation" || + aPropertyName == "HomeDirectory" || + aPropertyName == "HostName") ) + throw UnknownPropertyException( aPropertyName ); +} + + +Any SAL_CALL +FileProvider::getPropertyValue( + const OUString& aPropertyName ) +{ + initProperties(); + if( aPropertyName == "FileSystemNotation" ) + { + return Any(m_FileSystemNotation); + } + else if( aPropertyName == "HomeDirectory" ) + { + return Any(m_HomeDirectory); + } + else if( aPropertyName == "HostName" ) + { + return Any(m_HostName); + } + else + throw UnknownPropertyException( aPropertyName ); +} + + +void SAL_CALL +FileProvider::addPropertyChangeListener( + const OUString&, + const Reference< XPropertyChangeListener >& ) +{ +} + + +void SAL_CALL +FileProvider::removePropertyChangeListener( + const OUString&, + const Reference< XPropertyChangeListener >& ) +{ +} + +void SAL_CALL +FileProvider::addVetoableChangeListener( + const OUString&, + const Reference< XVetoableChangeListener >& ) +{ +} + + +void SAL_CALL +FileProvider::removeVetoableChangeListener( + const OUString&, + const Reference< XVetoableChangeListener >& ) +{ +} + + +// XFileIdentifierConverter + +sal_Int32 SAL_CALL +FileProvider::getFileProviderLocality( const OUString& BaseURL ) +{ + // If the base URL is a 'file' URL, return 10 (very 'local'), otherwise + // return -1 (mismatch). What is missing is a fast comparison to ASCII, + // ignoring case: + return BaseURL.getLength() >= 5 + && (BaseURL[0] == 'F' || BaseURL[0] == 'f') + && (BaseURL[1] == 'I' || BaseURL[1] == 'i') + && (BaseURL[2] == 'L' || BaseURL[2] == 'l') + && (BaseURL[3] == 'E' || BaseURL[3] == 'e') + && BaseURL[4] == ':' ? + 10 : -1; +} + +OUString SAL_CALL FileProvider::getFileURLFromSystemPath( const OUString&, + const OUString& SystemPath ) +{ + OUString aNormalizedPath; + if ( osl::FileBase::getFileURLFromSystemPath( SystemPath,aNormalizedPath ) != osl::FileBase::E_None ) + return OUString(); + + return aNormalizedPath; +} + +OUString SAL_CALL FileProvider::getSystemPathFromFileURL( const OUString& URL ) +{ + OUString aSystemPath; + if (osl::FileBase::getSystemPathFromFileURL( URL,aSystemPath ) != osl::FileBase::E_None ) + return OUString(); + + return aSystemPath; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +ucb_file_FileProvider_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new FileProvider(context)); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/prov.hxx b/ucb/source/ucp/file/prov.hxx new file mode 100644 index 0000000000..530010be1f --- /dev/null +++ b/ucb/source/ucp/file/prov.hxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/ucb/XContentProvider.hpp> +#include <com/sun/star/ucb/XContentIdentifierFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/ucb/XFileIdentifierConverter.hpp> +#include <cppuhelper/implbase.hxx> +#include <memory> +#include <mutex> + +// FileProvider + + +namespace fileaccess { + + // Forward declaration + + class BaseContent; + class TaskManager; + + class FileProvider: public cppu::WeakImplHelper < + css::lang::XServiceInfo, + css::lang::XInitialization, + css::ucb::XContentProvider, + css::ucb::XContentIdentifierFactory, + css::beans::XPropertySet, + css::ucb::XFileIdentifierConverter > + { + friend class BaseContent; + public: + + explicit FileProvider( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~FileProvider() 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; + + + // XInitialization + virtual void SAL_CALL + initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + + // XContentProvider + virtual css::uno::Reference< css::ucb::XContent > SAL_CALL + queryContent( + const css::uno::Reference< css::ucb::XContentIdentifier >& Identifier ) override; + + // XContentIdentifierFactory + + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL + createContentIdentifier( + const OUString& ContentId ) override; + + + virtual sal_Int32 SAL_CALL + compareContentIds( + const css::uno::Reference< css::ucb::XContentIdentifier >& Id1, + const css::uno::Reference< css::ucb::XContentIdentifier >& Id2 ) override; + + // XPropertySet + + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo( ) override; + + virtual void SAL_CALL + setPropertyValue( + const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + + virtual css::uno::Any SAL_CALL + getPropertyValue( + const OUString& PropertyName ) override; + + virtual void SAL_CALL + addPropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + + virtual void SAL_CALL + removePropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual void SAL_CALL + addVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + virtual void SAL_CALL + removeVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + + // XFileIdentifierConverter + + virtual sal_Int32 SAL_CALL + getFileProviderLocality( const OUString& BaseURL ) override; + + virtual OUString SAL_CALL getFileURLFromSystemPath( const OUString& BaseURL, + const OUString& SystemPath ) override; + + virtual OUString SAL_CALL getSystemPathFromFileURL( const OUString& URL ) override; + + + private: + // methods + void init(); + + // Members + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + void initProperties(); + std::mutex m_aMutex; + OUString m_HostName; + OUString m_HomeDirectory; + sal_Int32 m_FileSystemNotation; + + css::uno::Reference< css::beans::XPropertySetInfo > m_xPropertySetInfo; + + std::unique_ptr<TaskManager> m_pMyShell; + }; + +} // end namespace fileaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/ucb/source/ucp/file/ucpfile1.component b/ucb/source/ucp/file/ucpfile1.component new file mode 100644 index 0000000000..5a2efaf330 --- /dev/null +++ b/ucb/source/ucp/file/ucpfile1.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.ucb.FileProvider" + constructor="ucb_file_FileProvider_get_implementation"> + <service name="com.sun.star.ucb.FileContentProvider"/> + </implementation> +</component> |