diff options
Diffstat (limited to 'unotools/source/ucbhelper')
-rw-r--r-- | unotools/source/ucbhelper/XTempFile.hxx | 153 | ||||
-rw-r--r-- | unotools/source/ucbhelper/localfilehelper.cxx | 242 | ||||
-rw-r--r-- | unotools/source/ucbhelper/makefile.mk | 54 | ||||
-rw-r--r-- | unotools/source/ucbhelper/progresshandlerwrap.cxx | 98 | ||||
-rw-r--r-- | unotools/source/ucbhelper/tempfile.cxx | 493 | ||||
-rw-r--r-- | unotools/source/ucbhelper/ucbhelper.cxx | 925 | ||||
-rw-r--r-- | unotools/source/ucbhelper/ucblockbytes.cxx | 1746 | ||||
-rw-r--r-- | unotools/source/ucbhelper/ucbstreamhelper.cxx | 248 | ||||
-rw-r--r-- | unotools/source/ucbhelper/xtempfile.cxx | 576 |
9 files changed, 4535 insertions, 0 deletions
diff --git a/unotools/source/ucbhelper/XTempFile.hxx b/unotools/source/ucbhelper/XTempFile.hxx new file mode 100644 index 000000000000..115f6cf823a7 --- /dev/null +++ b/unotools/source/ucbhelper/XTempFile.hxx @@ -0,0 +1,153 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _XTEMPFILE_HXX_ +#define _XTEMPFILE_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XTempFile.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase5.hxx> +#ifndef _CPPUHELPER_PROPERTYSETMIXIN_HXX_ +#include <cppuhelper/propertysetmixin.hxx> +#endif +#include <osl/mutex.hxx> + +class SvStream; +namespace utl { class TempFile; } + +typedef ::cppu::WeakImplHelper5< ::com::sun::star::io::XTempFile + , ::com::sun::star::io::XInputStream + , ::com::sun::star::io::XOutputStream + , ::com::sun::star::io::XTruncate + , ::com::sun::star::lang::XServiceInfo + > + OTempFileBase; + +class OTempFileService : + public OTempFileBase, + public ::cppu::PropertySetMixin< ::com::sun::star::io::XTempFile > +{ +protected: + ::utl::TempFile* mpTempFile; + ::osl::Mutex maMutex; + SvStream* mpStream; + sal_Bool mbRemoveFile; + sal_Bool mbInClosed; + sal_Bool mbOutClosed; + + sal_Int64 mnCachedPos; + sal_Bool mbHasCachedPos; + + void checkError () const; + void checkConnected (); + +public: + OTempFileService (::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & context); + + //Methods + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& aType ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire( ) + throw (); + virtual void SAL_CALL release( ) + throw (); + // XTypeProvider + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL getImplementationId( ) + throw (::com::sun::star::uno::RuntimeException); + + // XTempFile + virtual ::sal_Bool SAL_CALL getRemoveFile() + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setRemoveFile( ::sal_Bool _removefile ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getUri() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getResourceName() + throw (::com::sun::star::uno::RuntimeException); + + // XInputStream + virtual ::sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL available( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XOutputStream + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aData ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL flush( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeOutput( ) + throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition( ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength( ) + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XStream + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream( ) + throw (::com::sun::star::uno::RuntimeException); + // XTruncate + virtual void SAL_CALL truncate() + throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName() + throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames() + throw (::com::sun::star::uno::RuntimeException); + + //::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface > SAL_CALL XTempFile_createInstance( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & context); + static ::rtl::OUString getImplementationName_Static (); + static ::com::sun::star::uno::Sequence < ::rtl::OUString > getSupportedServiceNames_Static(); + + static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleComponentFactory > createServiceFactory_Static( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory ); + +private: + OTempFileService( OTempFileService & ); + virtual ~OTempFileService (); + +}; +#endif diff --git a/unotools/source/ucbhelper/localfilehelper.cxx b/unotools/source/ucbhelper/localfilehelper.cxx new file mode 100644 index 000000000000..5ddd1f811923 --- /dev/null +++ b/unotools/source/ucbhelper/localfilehelper.cxx @@ -0,0 +1,242 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> + +#include <unotools/localfilehelper.hxx> +#include <ucbhelper/fileidentifierconverter.hxx> +#include <ucbhelper/contentbroker.hxx> +#include <rtl/ustring.hxx> +#include <osl/file.hxx> +#include <tools/debug.hxx> +#include <tools/list.hxx> +#include <tools/urlobj.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; + +namespace utl +{ + +sal_Bool LocalFileHelper::ConvertSystemPathToURL( const String& rName, const String& rBaseURL, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if ( FileBase::getFileURLFromSystemPath( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + rReturn = ::ucbhelper::getFileURLFromSystemPath( xManager, rBaseURL, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + return sal_False; + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertURLToSystemPath( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if( FileBase::getSystemPathFromFileURL( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + rReturn = ::ucbhelper::getSystemPathFromFileURL( xManager, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertPhysicalNameToURL( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + rtl::OUString aRet; + if ( FileBase::getFileURLFromSystemPath( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + + try + { + rtl::OUString aBase( ::ucbhelper::getLocalFileURL( xManager ) ); + rReturn = ::ucbhelper::getFileURLFromSystemPath( xManager, aBase, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::ConvertURLToPhysicalName( const String& rName, String& rReturn ) +{ + rReturn = ::rtl::OUString(); + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + { + ::rtl::OUString aRet; + if ( FileBase::getSystemPathFromFileURL( rName, aRet ) == FileBase::E_None ) + rReturn = aRet; + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + try + { + INetURLObject aObj( rName ); + INetURLObject aLocal( ::ucbhelper::getLocalFileURL( xManager ) ); + if ( aObj.GetProtocol() == aLocal.GetProtocol() ) + rReturn = ::ucbhelper::getSystemPathFromFileURL( xManager, rName ); + } + catch ( ::com::sun::star::uno::RuntimeException& ) + { + } + } + + return ( rReturn.Len() != 0 ); +} + +sal_Bool LocalFileHelper::IsLocalFile( const String& rName ) +{ + String aTmp; + return ConvertURLToPhysicalName( rName, aTmp ); +} + +sal_Bool LocalFileHelper::IsFileContent( const String& rName ) +{ + String aTmp; + return ConvertURLToSystemPath( rName, aTmp ); +} + +DECLARE_LIST( StringList_Impl, ::rtl::OUString* ) + +::com::sun::star::uno::Sequence < ::rtl::OUString > LocalFileHelper::GetFolderContents( const ::rtl::OUString& rFolder, sal_Bool bFolder ) +{ + StringList_Impl* pFiles = NULL; + try + { + ::ucbhelper::Content aCnt( rFolder, Reference< XCommandEnvironment > () ); + Reference< ::com::sun::star::sdbc::XResultSet > xResultSet; + ::com::sun::star::uno::Sequence< ::rtl::OUString > aProps(1); + ::rtl::OUString* pProps = aProps.getArray(); + pProps[0] = ::rtl::OUString::createFromAscii( "Url" ); + + try + { + ::ucbhelper::ResultSetInclude eInclude = bFolder ? ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS : ::ucbhelper::INCLUDE_DOCUMENTS_ONLY; + xResultSet = aCnt.createCursor( aProps, eInclude ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( Exception& ) + { + } + + if ( xResultSet.is() ) + { + pFiles = new StringList_Impl; + Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + try + { + while ( xResultSet->next() ) + { + ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); + ::rtl::OUString* pFile = new ::rtl::OUString( aId ); + pFiles->Insert( pFile, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( Exception& ) + { + } + } + } + catch( Exception& ) + { + } + + if ( pFiles ) + { + ULONG nCount = pFiles->Count(); + Sequence < ::rtl::OUString > aRet( nCount ); + ::rtl::OUString* pRet = aRet.getArray(); + for ( USHORT i = 0; i < nCount; ++i ) + { + ::rtl::OUString* pFile = pFiles->GetObject(i); + pRet[i] = *( pFile ); + delete pFile; + } + delete pFiles; + return aRet; + } + else + return Sequence < ::rtl::OUString > (); +} + +} diff --git a/unotools/source/ucbhelper/makefile.mk b/unotools/source/ucbhelper/makefile.mk new file mode 100644 index 000000000000..57088c69ca5c --- /dev/null +++ b/unotools/source/ucbhelper/makefile.mk @@ -0,0 +1,54 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJINC=..$/..$/inc +PRJNAME=unotools +TARGET=ucbhelp + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ---------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files ------------------------------------- + +SLOFILES=\ + $(SLO)$/ucblockbytes.obj \ + $(SLO)$/localfilehelper.obj \ + $(SLO)$/ucbhelper.obj \ + $(SLO)$/ucbstreamhelper.obj \ + $(SLO)$/tempfile.obj \ + $(SLO)$/xtempfile.obj \ + $(SLO)$/progresshandlerwrap.obj + +# --- Targets ---------------------------------- + +.INCLUDE : target.mk + diff --git a/unotools/source/ucbhelper/progresshandlerwrap.cxx b/unotools/source/ucbhelper/progresshandlerwrap.cxx new file mode 100644 index 000000000000..7fdbdacabc4b --- /dev/null +++ b/unotools/source/ucbhelper/progresshandlerwrap.cxx @@ -0,0 +1,98 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" +#include <unotools/progresshandlerwrap.hxx> + +namespace utl +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; + +ProgressHandlerWrap::ProgressHandlerWrap( ::com::sun::star::uno::Reference< ::com::sun::star::task::XStatusIndicator > xSI ) +: m_xStatusIndicator( xSI ) +{ +} + +sal_Bool getStatusFromAny_Impl( const Any& aAny, ::rtl::OUString& aText, sal_Int32& nNum ) +{ + sal_Bool bNumIsSet = sal_False; + + Sequence< Any > aSetList; + if( ( aAny >>= aSetList ) && aSetList.getLength() ) + for( int ind = 0; ind < aSetList.getLength(); ind++ ) + { + if( !bNumIsSet && ( aSetList[ind] >>= nNum ) ) + bNumIsSet = sal_True; + else + !aText.getLength() && ( aSetList[ind] >>= aText ); + } + + return bNumIsSet; +} + +void SAL_CALL ProgressHandlerWrap::push( const Any& Status ) + throw( RuntimeException ) +{ + if( !m_xStatusIndicator.is() ) + return; + + ::rtl::OUString aText; + sal_Int32 nRange; + + if( getStatusFromAny_Impl( Status, aText, nRange ) ) + m_xStatusIndicator->start( aText, nRange ); +} + +void SAL_CALL ProgressHandlerWrap::update( const Any& Status ) + throw( RuntimeException ) +{ + if( !m_xStatusIndicator.is() ) + return; + + ::rtl::OUString aText; + sal_Int32 nValue; + + if( getStatusFromAny_Impl( Status, aText, nValue ) ) + { + if( aText.getLength() ) m_xStatusIndicator->setText( aText ); + m_xStatusIndicator->setValue( nValue ); + } +} + +void SAL_CALL ProgressHandlerWrap::pop() + throw( RuntimeException ) +{ + if( m_xStatusIndicator.is() ) + m_xStatusIndicator->end(); +} + +} // namespace utl + diff --git a/unotools/source/ucbhelper/tempfile.cxx b/unotools/source/ucbhelper/tempfile.cxx new file mode 100644 index 000000000000..e77dc529e410 --- /dev/null +++ b/unotools/source/ucbhelper/tempfile.cxx @@ -0,0 +1,493 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" + +#include <unotools/tempfile.hxx> +#include <tools/tempfile.hxx> +#include <unotools/localfilehelper.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <ucbhelper/fileidentifierconverter.hxx> +#include <ucbhelper/contentbroker.hxx> +#include <rtl/ustring.hxx> +#include <rtl/instance.hxx> +#include <osl/file.hxx> +#include <tools/time.hxx> +#include <tools/debug.hxx> +#include <stdio.h> + +#ifdef UNX +#include <sys/stat.h> +#endif + +using namespace osl; + +namespace +{ + struct TempNameBase_Impl + : public rtl::Static< ::rtl::OUString, TempNameBase_Impl > {}; +} + +namespace utl +{ + +struct TempFile_Impl +{ + String aName; + String aURL; + SvStream* pStream; + sal_Bool bIsDirectory; + + TempFile_Impl() + : pStream(0) + {} +}; + +rtl::OUString getParentName( const rtl::OUString& aFileName ) +{ + sal_Int32 lastIndex = aFileName.lastIndexOf( sal_Unicode('/') ); + rtl::OUString aParent = aFileName.copy( 0,lastIndex ); + + if( aParent[ aParent.getLength()-1] == sal_Unicode(':') && aParent.getLength() == 6 ) + aParent += rtl::OUString::createFromAscii( "/" ); + + if( 0 == aParent.compareToAscii( "file://" ) ) + aParent = rtl::OUString::createFromAscii( "file:///" ); + + return aParent; +} + +sal_Bool ensuredir( const rtl::OUString& rUnqPath ) +{ + rtl::OUString aPath; + if ( rUnqPath.getLength() < 1 ) + return sal_False; + + // remove trailing slash + if ( rUnqPath[ rUnqPath.getLength() - 1 ] == sal_Unicode( '/' ) ) + aPath = rUnqPath.copy( 0, rUnqPath.getLength() - 1 ); + else + aPath = rUnqPath; + + // HACK: create directory on a mount point with nobrowse option + // returns ENOSYS in any case !! + osl::Directory aDirectory( aPath ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + osl::FileBase::RC nError = aDirectory.open(); +#ifdef UNX +umask(old_mode); +#endif + aDirectory.close(); + if( nError == osl::File::E_None ) + return sal_True; + + // try to create the directory + nError = osl::Directory::create( aPath ); + sal_Bool bSuccess = ( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + if( !bSuccess ) + { + // perhaps parent(s) don't exist + rtl::OUString aParentDir = getParentName( aPath ); + if ( aParentDir != aPath ) + { + bSuccess = ensuredir( getParentName( aPath ) ); + + // After parent directory structure exists try it one's more + if ( bSuccess ) + { + // Parent directory exists, retry creation of directory + nError = osl::Directory::create( aPath ); + bSuccess =( nError == osl::File::E_None || nError == osl::FileBase::E_EXIST ); + } + } + } + + return bSuccess; +} + +#define TMPNAME_SIZE ( 1 + 5 + 5 + 4 + 1 ) +String ConstructTempDir_Impl( const String* pParent ) +{ + String aName; + if ( pParent && pParent->Len() ) + { + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProviderManager > xManager = + pBroker->getContentProviderManagerInterface(); + + // if parent given try to use it + rtl::OUString aTmp( *pParent ); + + // test for valid filename + rtl::OUString aRet; + ::osl::FileBase::getFileURLFromSystemPath( + ::ucbhelper::getSystemPathFromFileURL( xManager, aTmp ), + aRet ); + if ( aRet.getLength() ) + { + ::osl::DirectoryItem aItem; + sal_Int32 i = aRet.getLength(); + if ( aRet[i-1] == '/' ) + i--; + + if ( DirectoryItem::get( ::rtl::OUString( aRet, i ), aItem ) == FileBase::E_None ) + aName = aRet; + } + } + else + { + DBG_WARNING( "::unotools::TempFile : UCB not present or not initialized!" ); + } + } + + if ( !aName.Len() ) + { + ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + if (rTempNameBase_Impl.getLength() == 0) + { + ::rtl::OUString ustrTempDirURL; + ::osl::FileBase::RC rc = ::osl::File::getTempDirURL( + ustrTempDirURL ); + if (rc == ::osl::FileBase::E_None) + rTempNameBase_Impl = ustrTempDirURL; + } + // if no parent or invalid parent : use default directory + DBG_ASSERT( rTempNameBase_Impl.getLength(), "No TempDir!" ); + aName = rTempNameBase_Impl; + ensuredir( aName ); + } + + // Make sure that directory ends with a separator + xub_StrLen i = aName.Len(); + if( i>0 && aName.GetChar(i-1) != '/' ) + aName += '/'; + + return aName; +} + +void CreateTempName_Impl( String& rName, sal_Bool bKeep, sal_Bool bDir = sal_True ) +{ + // add a suitable tempname + // Prefix can have 5 chars, leaving 3 for numbers. 26 ** 3 == 17576 + // ER 13.07.00 why not radix 36 [0-9A-Z] ?!? + const unsigned nRadix = 26; + String aName( rName ); + aName += String::CreateFromAscii( "sv" ); + + rName.Erase(); + static unsigned long u = Time::GetSystemTicks(); + for ( unsigned long nOld = u; ++u != nOld; ) + { + u %= (nRadix*nRadix*nRadix); + String aTmp( aName ); + aTmp += String::CreateFromInt32( (sal_Int32) (unsigned) u, nRadix ); + aTmp += String::CreateFromAscii( ".tmp" ); + + if ( bDir ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + // !bKeep: only for creating a name, not a file or directory + if ( bKeep || Directory::remove( aTmp ) == FileBase::E_None ) + rName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + } + else + { + DBG_ASSERT( bKeep, "Too expensive, use directory for creating name!" ); + File aFile( aTmp ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); +#ifdef UNX +umask(old_mode); +#endif + if ( err == FileBase::E_None ) + { + rName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create files + // but if there is a folder with such name proceed further + + DirectoryItem aTmpItem; + FileStatus aTmpStatus( FileStatusMask_Type ); + if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None + || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None + || aTmpStatus.getFileType() != FileStatus::Directory ) + break; + } + } + } +} + +void lcl_createName(TempFile_Impl& _rImpl,const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory) +{ + _rImpl.bIsDirectory = bDirectory; + + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + sal_Bool bUseNumber = _bStartWithZero; + // now use special naming scheme ( name takes leading chars and an index counting up from zero + aName += rLeadingChars; + for ( sal_Int32 i=0;; i++ ) + { + String aTmp( aName ); + if ( bUseNumber ) + aTmp += String::CreateFromInt32( i ); + bUseNumber = sal_True; + if ( pExtension ) + aTmp += *pExtension; + else + aTmp += String::CreateFromAscii( ".tmp" ); + if ( bDirectory ) + { + FileBase::RC err = Directory::create( aTmp ); + if ( err == FileBase::E_None ) + { + _rImpl.aName = aTmp; + break; + } + else if ( err != FileBase::E_EXIST ) + // if f.e. name contains invalid chars stop trying to create dirs + break; + } + else + { + File aFile( aTmp ); +#ifdef UNX +/* RW permission for the user only! */ + mode_t old_mode = umask(077); +#endif + FileBase::RC err = aFile.open(osl_File_OpenFlag_Create); +#ifdef UNX +umask(old_mode); +#endif + if ( err == FileBase::E_None ) + { + _rImpl.aName = aTmp; + aFile.close(); + break; + } + else if ( err != FileBase::E_EXIST ) + { + // if f.e. name contains invalid chars stop trying to create dirs + // but if there is a folder with such name proceed further + + DirectoryItem aTmpItem; + FileStatus aTmpStatus( FileStatusMask_Type ); + if ( DirectoryItem::get( aTmp, aTmpItem ) != FileBase::E_None + || aTmpItem.getFileStatus( aTmpStatus ) != FileBase::E_None + || aTmpStatus.getFileType() != FileStatus::Directory ) + break; + } + } + if ( !_bStartWithZero ) + aTmp += String::CreateFromInt32( i ); + } +} + + +String TempFile::CreateTempName( const String* pParent ) +{ + // get correct directory + String aName = ConstructTempDir_Impl( pParent ); + + // get TempFile name with default naming scheme + CreateTempName_Impl( aName, sal_False ); + + // convert to file URL + rtl::OUString aTmp; + if ( aName.Len() ) + FileBase::getSystemPathFromFileURL( aName, aTmp ); + return aTmp; +} + +TempFile::TempFile( const String* pParent, sal_Bool bDirectory ) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + pImp->bIsDirectory = bDirectory; + + // get correct directory + pImp->aName = ConstructTempDir_Impl( pParent ); + + // get TempFile with default naming scheme + CreateTempName_Impl( pImp->aName, sal_True, bDirectory ); +} + +TempFile::TempFile( const String& rLeadingChars, const String* pExtension, const String* pParent, sal_Bool bDirectory) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + lcl_createName(*pImp,rLeadingChars,sal_True, pExtension, pParent, bDirectory); +} +TempFile::TempFile( const String& rLeadingChars,sal_Bool _bStartWithZero, const String* pExtension, const String* pParent, sal_Bool bDirectory) + : pImp( new TempFile_Impl ) + , bKillingFileEnabled( sal_False ) +{ + lcl_createName(*pImp,rLeadingChars,_bStartWithZero, pExtension, pParent, bDirectory); +} + +TempFile::~TempFile() +{ + delete pImp->pStream; + if ( bKillingFileEnabled ) + { + if ( pImp->bIsDirectory ) + { + // at the moment no recursiv algorithm present + Directory::remove( pImp->aName ); + } + else + { + File::remove( pImp->aName ); + } + } + + delete pImp; +} + +sal_Bool TempFile::IsValid() const +{ + return pImp->aName.Len() != 0; +} + +String TempFile::GetFileName() const +{ + rtl::OUString aTmp; + FileBase::getSystemPathFromFileURL( pImp->aName, aTmp ); + return aTmp; +} + +String TempFile::GetURL() const +{ + if ( !pImp->aURL.Len() ) + { + String aTmp; + LocalFileHelper::ConvertPhysicalNameToURL( GetFileName(), aTmp ); + pImp->aURL = aTmp; + } + + return pImp->aURL; +} + +SvStream* TempFile::GetStream( StreamMode eMode ) +{ + if ( !pImp->pStream ) + { + if ( GetURL().Len() ) + pImp->pStream = UcbStreamHelper::CreateStream( pImp->aURL, eMode, sal_True /* bFileExists */ ); + else + pImp->pStream = new SvMemoryStream( eMode ); + } + + return pImp->pStream; +} + +void TempFile::CloseStream() +{ + if ( pImp->pStream ) + { + delete pImp->pStream; + pImp->pStream = NULL; + } +} + +String TempFile::SetTempNameBaseDirectory( const String &rBaseName ) +{ + if( !rBaseName.Len() ) + return String(); + + rtl::OUString aUnqPath( rBaseName ); + + // remove trailing slash + if ( rBaseName.GetChar( rBaseName.Len() - 1 ) == sal_Unicode( '/' ) ) + aUnqPath = rBaseName.Copy( 0, rBaseName.Len() - 1 ); + + // try to create the directory + sal_Bool bRet = sal_False; + osl::FileBase::RC err = osl::Directory::create( aUnqPath ); + if ( err != FileBase::E_None && err != FileBase::E_EXIST ) + // perhaps parent(s) don't exist + bRet = ensuredir( aUnqPath ); + else + bRet = sal_True; + + // failure to create base directory means returning an empty string + rtl::OUString aTmp; + if ( bRet ) + { + // append own internal directory + bRet = sal_True; + ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + rTempNameBase_Impl = rBaseName; + rTempNameBase_Impl += String( '/' ); + + TempFile aBase( NULL, sal_True ); + if ( aBase.IsValid() ) + // use it in case of success + rTempNameBase_Impl = aBase.pImp->aName; + + // return system path of used directory + FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp ); + } + + return aTmp; +} + +String TempFile::GetTempNameBaseDirectory() +{ + const ::rtl::OUString &rTempNameBase_Impl = TempNameBase_Impl::get(); + if ( !rTempNameBase_Impl.getLength() ) + return String(); + + rtl::OUString aTmp; + FileBase::getSystemPathFromFileURL( rTempNameBase_Impl, aTmp ); + return aTmp; +} + +} diff --git a/unotools/source/ucbhelper/ucbhelper.cxx b/unotools/source/ucbhelper/ucbhelper.cxx new file mode 100644 index 000000000000..8befb8a0f209 --- /dev/null +++ b/unotools/source/ucbhelper/ucbhelper.cxx @@ -0,0 +1,925 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" + +#include "unotools/ucbhelper.hxx" +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContentIdentifierFactory.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/IllegalIdentifierException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/ContentInfo.hpp> +#include <com/sun/star/ucb/ContentInfoAttribute.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <comphelper/processfactory.hxx> +#include <osl/file.hxx> + +#include <tools/wldcrd.hxx> +#include <tools/ref.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <tools/datetime.hxx> +#include <ucbhelper/contentbroker.hxx> + +#include "unotools/localfilehelper.hxx" + +using namespace ucbhelper; +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::lang; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::task; +using namespace com::sun::star::uno; +using namespace com::sun::star::ucb; +using namespace rtl; +using namespace comphelper; +using namespace osl; + +DECLARE_LIST( StringList_Impl, OUString* ) + +#define CONVERT_DATETIME( aUnoDT, aToolsDT ) \ + aToolsDT = DateTime( Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year ), \ + Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.HundredthSeconds ) ); + +namespace utl +{ + +sal_Bool UCBContentHelper::Transfer_Impl( const String& rSource, const String& rDest, sal_Bool bMoveData, sal_Int32 nNameClash ) +{ + sal_Bool bRet = sal_True, bKillSource = sal_False; + INetURLObject aSourceObj( rSource ); + DBG_ASSERT( aSourceObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + INetURLObject aDestObj( rDest ); + DBG_ASSERT( aDestObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + if ( bMoveData && aSourceObj.GetProtocol() != aDestObj.GetProtocol() ) + { + bMoveData = sal_False; + bKillSource = sal_True; + } + String aName = aDestObj.getName(); + aDestObj.removeSegment(); + aDestObj.setFinalSlash(); + + try + { + Content aDestPath( aDestObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + uno::Reference< ::com::sun::star::ucb::XCommandInfo > xInfo = aDestPath.getCommands(); + OUString aTransferName = OUString::createFromAscii( "transfer" ); + if ( xInfo->hasCommandByName( aTransferName ) ) + { + aDestPath.executeCommand( aTransferName, makeAny( + ::com::sun::star::ucb::TransferInfo( bMoveData, aSourceObj.GetMainURL( INetURLObject::NO_DECODE ), aName, nNameClash ) ) ); + } + else + { + DBG_ERRORFILE( "transfer command not available" ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + bRet = sal_False; + } + catch( ::com::sun::star::uno::Exception& ) + { + bRet = sal_False; + } + + if ( bKillSource ) + UCBContentHelper::Kill( rSource ); + + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::IsDocument( const String& rContent ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + bRet = aCnt.isDocument(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +Any UCBContentHelper::GetProperty( const String& rContent, const ::rtl::OUString& rName ) +{ + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + return aCnt.getPropertyValue( rName ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return Any(); +} + +sal_Bool UCBContentHelper::IsFolder( const String& rContent ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + bRet = aCnt.isFolder(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + } + catch( ::com::sun::star::ucb::IllegalIdentifierException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ContentCreationException& ) + { + DBG_WARNING( "IllegalIdentifierException" ); + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::GetTitle( const String& rContent, String& rTitle ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + OUString aTemp; + if ( aCnt.getPropertyValue( OUString::createFromAscii( "Title" ) ) >>= aTemp ) + { + rTitle = String( aTemp ); + bRet = sal_True; + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::Kill( const String& rContent ) +{ + sal_Bool bRet = sal_True; + INetURLObject aDeleteObj( rContent ); + DBG_ASSERT( aDeleteObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + try + { + Content aCnt( aDeleteObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + DBG_WARNING( "CommandAbortedException" ); + bRet = sal_False; + } + catch( ::com::sun::star::uno::Exception& ) + { + DBG_WARNING( "Any other exception" ); + bRet = sal_False; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +Sequence < OUString > UCBContentHelper::GetFolderContents( const String& rFolder, sal_Bool bFolder, sal_Bool bSorted ) +{ + StringList_Impl* pFiles = NULL; + INetURLObject aFolderObj( rFolder ); + DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + uno::Reference< XResultSet > xResultSet; + Sequence< OUString > aProps( bSorted ? 2 : 1 ); + OUString* pProps = aProps.getArray(); + pProps[0] = OUString::createFromAscii( "Title" ); + if ( bSorted ) + pProps[1] = OUString::createFromAscii( "IsFolder" ); + + try + { + ResultSetInclude eInclude = bFolder ? INCLUDE_FOLDERS_AND_DOCUMENTS : INCLUDE_DOCUMENTS_ONLY; + if ( !bSorted ) + { + xResultSet = aCnt.createCursor( aProps, eInclude ); + } + else + { + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynResultSet; + xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude ); + + uno::Reference < com::sun::star::ucb::XAnyCompareFactory > xFactory; + uno::Reference < XMultiServiceFactory > xMgr = getProcessServiceFactory(); + uno::Reference < com::sun::star::ucb::XSortedDynamicResultSetFactory > xSRSFac( + xMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.ucb.SortedDynamicResultSetFactory") ), UNO_QUERY ); + + Sequence< com::sun::star::ucb::NumberedSortingInfo > aSortInfo( 2 ); + com::sun::star::ucb::NumberedSortingInfo* pInfo = aSortInfo.getArray(); + pInfo[ 0 ].ColumnIndex = 2; + pInfo[ 0 ].Ascending = sal_False; + pInfo[ 1 ].ColumnIndex = 1; + pInfo[ 1 ].Ascending = sal_True; + + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynamicResultSet; + xDynamicResultSet = + xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xFactory ); + if ( xDynamicResultSet.is() ) + { + xResultSet = xDynamicResultSet->getStaticResultSet(); + } + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + // folder not exists? + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( xResultSet.is() ) + { + pFiles = new StringList_Impl; + uno::Reference< com::sun::star::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + try + { + while ( xResultSet->next() ) + { + OUString aId = xContentAccess->queryContentIdentifierString(); + OUString* pFile = new OUString( aId ); + pFiles->Insert( pFile, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( pFiles ) + { + ULONG nCount = pFiles->Count(); + Sequence < OUString > aRet( nCount ); + OUString* pRet = aRet.getArray(); + for ( ULONG i = 0; i < nCount; ++i ) + { + OUString* pFile = pFiles->GetObject(i); + pRet[i] = *( pFile ); + delete pFile; + } + delete pFiles; + return aRet; + } + else + return Sequence < OUString > (); +} + +// ----------------------------------------------------------------------- + +Sequence < OUString > UCBContentHelper::GetResultSet( const String& rURL ) +{ + StringList_Impl* pList = NULL; + try + { + Content aCnt( rURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + uno::Reference< XResultSet > xResultSet; + uno::Reference< com::sun::star::ucb::XDynamicResultSet > xDynResultSet; + Sequence< OUString > aProps(3); + OUString* pProps = aProps.getArray(); + pProps[0] = OUString::createFromAscii( "Title" ); + pProps[1] = OUString::createFromAscii( "ContentType" ); + // TODO: can be optimized, property never used: + pProps[2] = OUString::createFromAscii( "IsFolder" ); + + try + { + xDynResultSet = aCnt.createDynamicCursor( aProps, INCLUDE_FOLDERS_AND_DOCUMENTS ); + if ( xDynResultSet.is() ) + xResultSet = xDynResultSet->getStaticResultSet(); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( xResultSet.is() ) + { + pList = new StringList_Impl; + uno::Reference< com::sun::star::sdbc::XRow > xRow( xResultSet, UNO_QUERY ); + uno::Reference< com::sun::star::ucb::XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + + try + { + while ( xResultSet->next() ) + { + String aTitle( xRow->getString(1) ); + String aType( xRow->getString(2) ); + String aRow = aTitle; + aRow += '\t'; + aRow += aType; + aRow += '\t'; + aRow += String( xContentAccess->queryContentIdentifierString() ); + OUString* pRow = new OUString( aRow ); + pList->Insert( pRow, LIST_APPEND ); + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + } + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + if ( pList ) + { + ULONG nCount = pList->Count(); + Sequence < OUString > aRet( nCount ); + OUString* pRet = aRet.getArray(); + for ( ULONG i = 0; i < nCount; ++i ) + { + OUString* pEntry = pList->GetObject(i); + pRet[i] = *( pEntry ); + delete pEntry; + } + delete pList; + return aRet; + } + else + return Sequence < OUString > (); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::CopyTo( const String& rSource, const String& rDest ) +{ + return Transfer_Impl( rSource, rDest, sal_False, NameClash::ERROR ); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::MoveTo( const String& rSource, const String& rDest, sal_Int32 nNameClash ) +{ + return Transfer_Impl( rSource, rDest, sal_True, nNameClash ); +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::CanMakeFolder( const String& rFolder ) +{ + try + { + Content aCnt( rFolder, uno::Reference< XCommandEnvironment > () ); + Sequence< ContentInfo > aInfo = aCnt.queryCreatableContentsInfo(); + sal_Int32 nCount = aInfo.getLength(); + if ( nCount == 0 ) + return sal_False; + + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Simply look for the first KIND_FOLDER... + const ContentInfo & rCurr = aInfo[i]; + if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER ) + return sal_True; + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) {} + catch( RuntimeException& ) {} + catch( Exception& ) {} + + return sal_False; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::MakeFolder( const String& rFolder, sal_Bool bNewOnly ) +{ + INetURLObject aURL( rFolder ); + DBG_ASSERT( aURL.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + String aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + aURL.removeSegment(); + Content aCnt; + Content aNew; + uno::Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + uno::Reference< XInteractionHandler > xInteractionHandler = uno::Reference< XInteractionHandler > ( + xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), UNO_QUERY ); + if ( Content::create( aURL.GetMainURL( INetURLObject::NO_DECODE ), new CommandEnvironment( xInteractionHandler, uno::Reference< XProgressHandler >() ), aCnt ) ) + return MakeFolder( aCnt, aTitle, aNew, bNewOnly ); + else + return sal_False; +} + +sal_Bool UCBContentHelper::MakeFolder( Content& aCnt, const String& aTitle, Content& rNew, sal_Bool bNewOnly ) +{ + sal_Bool bAlreadyExists = sal_False; + + try + { + Sequence< ContentInfo > aInfo = aCnt.queryCreatableContentsInfo(); + sal_Int32 nCount = aInfo.getLength(); + if ( nCount == 0 ) + return sal_False; + + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Simply look for the first KIND_FOLDER... + const ContentInfo & rCurr = aInfo[i]; + if ( rCurr.Attributes & ContentInfoAttribute::KIND_FOLDER ) + { + // Make sure the only required bootstrap property is "Title", + const Sequence< Property > & rProps = rCurr.Properties; + if ( rProps.getLength() != 1 ) + continue; + + if ( !rProps[ 0 ].Name.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) + continue; + + Sequence<OUString> aNames(1); + OUString* pNames = aNames.getArray(); + pNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ); + Sequence<Any> aValues(1); + Any* pValues = aValues.getArray(); + pValues[0] = makeAny( OUString( aTitle ) ); + + if ( !aCnt.insertNewContent( rCurr.Type, aNames, aValues, rNew ) ) + continue; + + return sal_True; + } + } + } + catch ( InteractiveIOException& r ) + { + if ( r.Code == IOErrorCode_ALREADY_EXISTING ) + { + bAlreadyExists = sal_True; + } + } + catch ( NameClashException& ) + { + bAlreadyExists = sal_True; + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( RuntimeException& ) + { + } + catch( Exception& ) + { + } + + if( bAlreadyExists && !bNewOnly ) + { + INetURLObject aObj( aCnt.getURL() ); + aObj.Append( aTitle ); + rNew = Content( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference < XCommandEnvironment >() ); + return sal_True; + } + + return sal_False; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::HasParentFolder( const String& rFolder ) +{ + sal_Bool bRet = sal_False; + try + { + Content aCnt( rFolder, uno::Reference< XCommandEnvironment > () ); + uno::Reference< XChild > xChild( aCnt.get(), UNO_QUERY ); + if ( xChild.is() ) + { + uno::Reference< XContent > xParent( xChild->getParent(), UNO_QUERY ); + if ( xParent.is() ) + { + String aParentURL = String( xParent->getIdentifier()->getContentIdentifier() ); + bRet = ( aParentURL.Len() > 0 && aParentURL != rFolder ); + } + } + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +ULONG UCBContentHelper::GetSize( const String& rContent ) +{ + ULONG nSize = 0; + sal_Int64 nTemp = 0; + INetURLObject aObj( rContent ); + DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + aCnt.getPropertyValue( OUString::createFromAscii( "Size" ) ) >>= nTemp; + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + nSize = (UINT32)nTemp; + return nSize; +} + +// ----------------------------------------------------------------------- + +sal_Bool UCBContentHelper::IsYounger( const String& rIsYoung, const String& rIsOlder ) +{ + DateTime aYoungDate, aOlderDate; + INetURLObject aYoungObj( rIsYoung ); + DBG_ASSERT( aYoungObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + INetURLObject aOlderObj( rIsOlder ); + DBG_ASSERT( aOlderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + try + { + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > aCmdEnv; + Content aYoung( aYoungObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv ); + ::com::sun::star::util::DateTime aTempYoungDate; + aYoung.getPropertyValue( OUString::createFromAscii( "DateModified" ) ) >>= aTempYoungDate; + CONVERT_DATETIME( aTempYoungDate, aYoungDate ); + Content aOlder( aOlderObj.GetMainURL( INetURLObject::NO_DECODE ), aCmdEnv ); + ::com::sun::star::util::DateTime aTempOlderDate; + aOlder.getPropertyValue( OUString::createFromAscii( "DateModified" ) ) >>= aTempOlderDate; + CONVERT_DATETIME( aTempOlderDate, aOlderDate ); + } + catch( ::com::sun::star::ucb::CommandAbortedException& ) + { + } + catch( ::com::sun::star::uno::Exception& ) + { + } + + return ( aYoungDate > aOlderDate ); +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::Find( const String& rFolder, const String& rName, String& rFile, BOOL bAllowWildCards ) +{ + BOOL bWild = bAllowWildCards && ( rName.Search( '*' ) != STRING_NOTFOUND || rName.Search( '?' ) != STRING_NOTFOUND ); + + sal_Bool bRet = sal_False; + + // get a list of URLs for all children of rFolder + Sequence< ::rtl::OUString > aFiles = GetFolderContents( rFolder, sal_False ); + + const ::rtl::OUString* pFiles = aFiles.getConstArray(); + UINT32 i, nCount = aFiles.getLength(); + for ( i = 0; i < nCount; ++i ) + { + // get the last name of the URLs and compare it with rName + INetURLObject aFileObject( pFiles[i] ); + String aFile = aFileObject.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + if ( (bWild && WildCard( rName ).Matches( aFile )) || aFile == rName ) + { + // names match + rFile = aFileObject.GetMainURL( INetURLObject::NO_DECODE ); + bRet = sal_True; + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::Exists( const String& rURL ) +{ + + String sObjectPhysicalName; + sal_Bool bIsLocalFile = ::utl::LocalFileHelper::ConvertURLToPhysicalName( rURL, sObjectPhysicalName ); + // try to create a directory entry for the URL given + if ( bIsLocalFile ) + { + ::rtl::OUString sIn( sObjectPhysicalName ), sOut; + if ( osl_File_E_None == osl_getFileURLFromSystemPath( sIn.pData, &sOut.pData ) ) + { + // #106526 osl_getDirectoryItem is an existence check + // no further osl_getFileStatus call necessary + DirectoryItem aItem; + return (FileBase::E_None == DirectoryItem::get(sOut, aItem)); + } + return sal_False; + } + + // divide URL into folder and name part + sal_Bool bRet = sal_False; + INetURLObject aObj( rURL ); + ::rtl::OUString aFileName = aObj.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + aObj.removeSegment(); + aObj.removeFinalSlash(); + + // get a list of URLs for all children of rFolder + Sequence< ::rtl::OUString > aFiles = GetFolderContents( aObj.GetMainURL( INetURLObject::NO_DECODE ), sal_True, sal_False ); + + const ::rtl::OUString* pFiles = aFiles.getConstArray(); + UINT32 i, nCount = aFiles.getLength(); + for ( i = 0; i < nCount; ++i ) + { + // get the last name of the URLs and compare it with rName + INetURLObject aFileObject( pFiles[i] ); + ::rtl::OUString aFile = aFileObject.getName( + INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ).toAsciiLowerCase(); + if ( aFile == aFileName ) + { + // names match + bRet = sal_True; + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::FindInPath( const String& rPath, const String& rName, String& rFile, char cDelim, BOOL bAllowWildCards ) +{ + // extract the single folder names from the path variable and try to find the file in one of these folders + USHORT nTokenCount = rPath.GetTokenCount( cDelim ); + for ( USHORT nToken = 0; nToken < nTokenCount; ++nToken ) + { + String aPath = rPath.GetToken( nToken, cDelim ); + if ( Find( aPath, rName, rFile, bAllowWildCards ) ) + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::IsSubPath( const ::rtl::OUString& rPath, const ::rtl::OUString& rSubfolderCandidate, const uno::Reference< ::com::sun::star::ucb::XContentProvider >& xProv ) +{ + sal_Bool bResult = sal_False; + + uno::Reference< ::com::sun::star::ucb::XContentProvider > xContentProvider = xProv; + + // the comparing is done in the following way: + // - first compare in case sensitive way + // - if name are different try a fallback comparing inf case insensitive way + // - if the last comparing succeeded get casepreserving normalized names for the files and compare them + // ( the second step is required because retrieving of the normalized names might be very expensive in some cases ) + + INetURLObject aCandidate( rSubfolderCandidate ); + INetURLObject aCandidateLowCase( rSubfolderCandidate.toAsciiLowerCase() ); // will be used for case insensitive comparing + INetURLObject aParentFolder( rPath ); + INetURLObject aParentFolderLowCase( rPath.toAsciiLowerCase() ); // will be used for case insensitive comparing + + if ( aCandidate.GetProtocol() == aParentFolder.GetProtocol() ) + { + if ( !xContentProvider.is() ) + { + ::ucbhelper::ContentBroker* pBroker = NULL; + if ( aCandidate.GetProtocol() == INET_PROT_FILE ) + { + pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + xContentProvider = pBroker->getContentProviderInterface(); + } + } + + INetURLObject aLastTmpObj; + do + { + if ( aParentFolder == aCandidate ) + { + // if case sensitive comparing succeeded there is no need for additional checks + bResult = sal_True; + } + else if ( xContentProvider.is() && aParentFolderLowCase == aCandidateLowCase ) + { + // the comparing was done using caseinsensitive way + // the case sensitive comparing have failed already + // the normalized urls must be retrieved + try + { + uno::Reference< ::com::sun::star::ucb::XContent > xSecCont = + xContentProvider->queryContent( + uno::Reference< ::com::sun::star::ucb::XContentIdentifierFactory >( + xContentProvider, ::com::sun::star::uno::UNO_QUERY_THROW )->createContentIdentifier( + aParentFolder.GetMainURL( INetURLObject::NO_DECODE ) ) ); + + uno::Reference< ::com::sun::star::ucb::XContent > xLocCont = + xContentProvider->queryContent( + uno::Reference< ::com::sun::star::ucb::XContentIdentifierFactory >( + xContentProvider, ::com::sun::star::uno::UNO_QUERY_THROW )->createContentIdentifier( + aCandidate.GetMainURL( INetURLObject::NO_DECODE ) ) ); + + if ( !xSecCont.is() || !xLocCont.is() ) + throw ::com::sun::star::uno::RuntimeException(); + + ::rtl::OUString aSecNormStr; + ::rtl::OUString aLocNormStr; + + bResult = + ( ( uno::Reference< ::com::sun::star::ucb::XCommandProcessor >( + xSecCont, ::com::sun::star::uno::UNO_QUERY_THROW )->execute( + ::com::sun::star::ucb::Command( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCasePreservingURL" ) ), + -1, + ::com::sun::star::uno::Any() ), + 0, + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ) + >>= aSecNormStr ) + && ( uno::Reference< ::com::sun::star::ucb::XCommandProcessor >( + xLocCont, ::com::sun::star::uno::UNO_QUERY_THROW )->execute( + ::com::sun::star::ucb::Command( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCasePreservingURL" ) ), + -1, + ::com::sun::star::uno::Any() ), + 0, + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ) + >>= aLocNormStr ) + && aLocNormStr.equals( aSecNormStr ) ); + } + catch( ::com::sun::star::uno::Exception& ) + {} + } + + // INetURLObject::removeSegment sometimes return true without exchanging URL, + // for example in case of "file:///" + aLastTmpObj = aCandidate; + + } while( aCandidate.removeSegment() && aCandidateLowCase.removeSegment() && aCandidate != aLastTmpObj && !bResult ); + } + + return bResult; +} + +// ----------------------------------------------------------------------- +sal_Bool UCBContentHelper::EqualURLs( const ::rtl::OUString& aFirstURL, const ::rtl::OUString& aSecondURL ) +{ + sal_Bool bResult = sal_False; + + if ( aFirstURL.getLength() && aSecondURL.getLength() ) + { + INetURLObject aFirst( aFirstURL ); + INetURLObject aSecond( aSecondURL ); + + if ( aFirst.GetProtocol() != INET_PROT_NOT_VALID && aSecond.GetProtocol() != INET_PROT_NOT_VALID ) + { + try + { + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( !pBroker ) + throw uno::RuntimeException(); + + uno::Reference< ::com::sun::star::ucb::XContentIdentifierFactory > xIdFac + = pBroker->getContentIdentifierFactoryInterface(); + if ( !xIdFac.is() ) + throw uno::RuntimeException(); + + uno::Reference< ::com::sun::star::ucb::XContentIdentifier > xIdFirst + = xIdFac->createContentIdentifier( aFirst.GetMainURL( INetURLObject::NO_DECODE ) ); + uno::Reference< ::com::sun::star::ucb::XContentIdentifier > xIdSecond + = xIdFac->createContentIdentifier( aSecond.GetMainURL( INetURLObject::NO_DECODE ) ); + + if ( xIdFirst.is() && xIdSecond.is() ) + { + uno::Reference< ::com::sun::star::ucb::XContentProvider > xProvider = + pBroker->getContentProviderInterface(); + if ( !xProvider.is() ) + throw uno::RuntimeException(); + bResult = !xProvider->compareContentIds( xIdFirst, xIdSecond ); + } + } + catch( uno::Exception& ) + { + OSL_ENSURE( sal_False, "Can't compare URL's, treat as different!\n" ); + } + } + } + + return bResult; +} + + + +} // namespace utl + diff --git a/unotools/source/ucbhelper/ucblockbytes.cxx b/unotools/source/ucbhelper/ucblockbytes.cxx new file mode 100644 index 000000000000..f21855d20aed --- /dev/null +++ b/unotools/source/ucbhelper/ucblockbytes.cxx @@ -0,0 +1,1746 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" + +#include <unotools/ucblockbytes.hxx> +#include <comphelper/processfactory.hxx> +#include <salhelper/condition.hxx> +#ifndef _OSL_THREAD_HXX_ +#include <osl/thread.hxx> +#endif +#include <tools/urlobj.hxx> +#include <ucbhelper/interactionrequest.hxx> +#include <com/sun/star/task/XInteractionAbort.hpp> +#include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> +#include <com/sun/star/ucb/CommandFailedException.hpp> +#include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> +#ifndef _COM_SUN_STAR_UCB_INTERACTIVEIODEXCEPTION_HPP_ +#include <com/sun/star/ucb/InteractiveIOException.hpp> +#endif +#include <com/sun/star/io/XActiveDataStreamer.hpp> +#include <com/sun/star/ucb/DocumentHeaderField.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/ucb/XCommandProcessor.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/OpenCommandArgument2.hpp> +#include <com/sun/star/ucb/PostCommandArgument2.hpp> +#include <com/sun/star/ucb/OpenMode.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> +#include <tools/inetmsg.hxx> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +#include <comphelper/storagehelper.hxx> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/content.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + + +namespace utl +{ + +/** + Helper class for getting a XInputStream when opening a content + */ +class UcbDataSink_Impl : public ::cppu::WeakImplHelper2< XActiveDataControl, XActiveDataSink > +{ + UcbLockBytesRef m_xLockBytes; + +public: + UcbDataSink_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + SvLockBytes* getLockBytes (void) + { return m_xLockBytes; } + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataSink. + virtual void SAL_CALL setInputStream ( const Reference<XInputStream> &rxInputStream) throw(RuntimeException) + { m_xLockBytes->setInputStream_Impl (rxInputStream); } + virtual Reference<XInputStream> SAL_CALL getInputStream (void) throw(RuntimeException) + { return m_xLockBytes->getInputStream_Impl(); } +}; + +/** + Helper class for getting a XStream when opening a content + */ +class UcbStreamer_Impl : public ::cppu::WeakImplHelper2< XActiveDataStreamer, XActiveDataControl > +{ + Reference < XStream > m_xStream; + UcbLockBytesRef m_xLockBytes; + +public: + + UcbStreamer_Impl( UcbLockBytes* pLockBytes ) + : m_xLockBytes( pLockBytes ) + {} + + // XActiveDataControl. + virtual void SAL_CALL addListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL removeListener ( const Reference<XStreamListener> &/*rxListener*/) throw(RuntimeException) {} + virtual void SAL_CALL start (void) throw(RuntimeException) {} + virtual void SAL_CALL terminate (void) throw(RuntimeException) + { m_xLockBytes->terminate_Impl(); } + + // XActiveDataStreamer + virtual void SAL_CALL setStream( const Reference< XStream >& aStream ) throw(RuntimeException) + { m_xStream = aStream; m_xLockBytes->setStream_Impl( aStream ); } + virtual Reference< XStream > SAL_CALL getStream() throw(RuntimeException) + { return m_xStream; } +}; + +/** + Helper class for progress handling while executing UCB commands + */ +class ProgressHandler_Impl: public ::cppu::WeakImplHelper1< XProgressHandler > +{ + Link m_aProgress; + +public: + ProgressHandler_Impl( const Link& rLink ) + : m_aProgress( rLink ) + {} + // XProgressHandler + virtual void SAL_CALL push(const Any & /*rStatus*/) throw (RuntimeException) {} + virtual void SAL_CALL pop() throw (RuntimeException) {} + virtual void SAL_CALL update(const Any & /*rStatus*/) throw (RuntimeException) + { if ( m_aProgress.IsSet() ) m_aProgress.Call( 0 ); } +}; + +/** + Helper class for managing interactions and progress when executing UCB commands + */ +class UcbTaskEnvironment : public ::cppu::WeakImplHelper1< XCommandEnvironment > +{ + Reference< XInteractionHandler > m_xInteractionHandler; + Reference< XProgressHandler > m_xProgressHandler; + +public: + UcbTaskEnvironment( const Reference< XInteractionHandler>& rxInteractionHandler, + const Reference< XProgressHandler>& rxProgressHandler ) + : m_xInteractionHandler( rxInteractionHandler ) + , m_xProgressHandler( rxProgressHandler ) + {} + + + virtual Reference<XInteractionHandler> SAL_CALL getInteractionHandler() throw (RuntimeException) + { return m_xInteractionHandler; } + + virtual Reference<XProgressHandler> SAL_CALL getProgressHandler() throw (RuntimeException) + { return m_xProgressHandler; } +}; + + +/** + Helper class for property change notifies when executing UCB commands +*/ +class UcbPropertiesChangeListener_Impl : public ::cppu::WeakImplHelper1< XPropertiesChangeListener > +{ +public: + UcbLockBytesRef m_xLockBytes; + + UcbPropertiesChangeListener_Impl( UcbLockBytesRef rRef ) + : m_xLockBytes( rRef ) + {} + + virtual void SAL_CALL disposing ( const EventObject &/*rEvent*/) throw(RuntimeException) {} + virtual void SAL_CALL propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException); +}; + +void SAL_CALL UcbPropertiesChangeListener_Impl::propertiesChange ( const Sequence<PropertyChangeEvent> &rEvent) throw(RuntimeException) +{ + sal_Int32 i, n = rEvent.getLength(); + for (i = 0; i < n; i++) + { + PropertyChangeEvent evt (rEvent[i]); + if (evt.PropertyName == ::rtl::OUString::createFromAscii ("DocumentHeader")) + { + Sequence<DocumentHeaderField> aHead; + if (evt.NewValue >>= aHead) + { + sal_Int32 k, m = aHead.getLength(); + for (k = 0; k < m; k++) + { + String aName( aHead[k].Name ); + String aValue( aHead[k].Value ); + + if (aName.CompareIgnoreCaseToAscii("Expires") == COMPARE_EQUAL) + { + DateTime aExpires (0, 0); + if (INetRFC822Message::ParseDateField (aValue, aExpires)) + { + aExpires.ConvertToLocalTime(); + m_xLockBytes->SetExpireDate_Impl( aExpires ); + } + } + } + } + + m_xLockBytes->SetStreamValid_Impl(); + } + else if (evt.PropertyName == rtl::OUString::createFromAscii ("PresentationURL")) + { + ::rtl::OUString aUrl; + if (evt.NewValue >>= aUrl) + { + ::rtl::OUString aBad (::rtl::OUString::createFromAscii ("private:")); + if (!(aUrl.compareTo (aBad, aBad.getLength()) == 0)) + { + // URL changed (Redirection). + m_xLockBytes->SetRealURL_Impl( aUrl ); + } + } + } + else if (evt.PropertyName == ::rtl::OUString::createFromAscii ("MediaType")) + { + ::rtl::OUString aContentType; + if (evt.NewValue >>= aContentType) + m_xLockBytes->SetContentType_Impl( aContentType ); + } + } +} + + + +class Moderator + : public osl::Thread +{ + // usage restriction: + // It might be possible, that the call to the interactionhandler and/or + // progresshandler is done asynchrounsly, while the 'execute' simply + // returns. This would imply that these class must be refcounted !!! + +public: + + Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg + ) + throw( + ContentCreationException, + RuntimeException + ); + + ~Moderator(); + + + enum ResultType { + NORESULT, + + INTERACTIONREQUEST, // reply expected + + PROGRESSPUSH, + PROGRESSUPDATE, + PROGRESSPOP, + + INPUTSTREAM, + STREAM, + + RESULT, + TIMEDOUT, + COMMANDABORTED, + COMMANDFAILED, + INTERACTIVEIO, + UNSUPPORTED, + GENERAL + }; + + + class ConditionRes + : public salhelper::Condition + { + public: + + ConditionRes(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aResultType != NORESULT; + } + + private: + + Moderator& m_aModerator; + }; + + + struct Result { + ResultType type; + Any result; + sal_Int32 ioErrorCode; + }; + + + Result getResult(const sal_uInt32 milliSec); + + + enum ReplyType { + NOREPLY, + EXIT, + RETRY, + REQUESTHANDLED + }; + + + class ConditionRep + : public salhelper::Condition + { + public: + + ConditionRep(osl::Mutex& aMutex,Moderator& aModerator) + : salhelper::Condition(aMutex), + m_aModerator(aModerator) + { + } + + protected: + + bool applies() const { + return m_aModerator.m_aReplyType != NOREPLY; + } + + private: + + Moderator& m_aModerator; + }; + + void setReply(ReplyType); + + + void handle( const Reference<XInteractionRequest >& Request ); + + void push( const Any& Status ); + + void update( const Any& Status ); + + void pop( ); + + void setStream(const Reference< XStream >& aStream); + + void setInputStream(const Reference<XInputStream> &rxInputStream); + + +protected: + + virtual void SAL_CALL run(); + + virtual void SAL_CALL onTerminated(); + +private: + + osl::Mutex m_aMutex; + + friend class ConditionRes; + + ConditionRes m_aRes; + ResultType m_aResultType; + sal_Int32 m_nIOErrorCode; + Any m_aResult; + + friend class ConditionRep; + + ConditionRep m_aRep; + ReplyType m_aReplyType; + + Command m_aArg; + ::ucbhelper::Content m_aContent; +}; + + +class ModeratorsActiveDataStreamer + : public ::cppu::WeakImplHelper1<XActiveDataStreamer> +{ +public: + + ModeratorsActiveDataStreamer(Moderator &theModerator); + + ~ModeratorsActiveDataStreamer(); + + // XActiveDataStreamer + virtual void SAL_CALL + setStream( + const Reference< XStream >& aStream + ) + throw( + RuntimeException + ); + + virtual Reference<XStream> SAL_CALL + getStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + + osl::Mutex m_aMutex; + Reference<XStream> m_xStream; +}; + + + +class ModeratorsActiveDataSink + : public ::cppu::WeakImplHelper1<XActiveDataSink> +{ +public: + + ModeratorsActiveDataSink(Moderator &theModerator); + + ~ModeratorsActiveDataSink(); + + // XActiveDataSink. + virtual void SAL_CALL + setInputStream ( + const Reference<XInputStream> &rxInputStream + ) + throw( + RuntimeException + ); + + virtual Reference<XInputStream> SAL_CALL + getInputStream ( + void + ) throw( + RuntimeException + ) + { + osl::MutexGuard aGuard(m_aMutex); + return m_xStream; + } + + +private: + + Moderator& m_aModerator; + osl::Mutex m_aMutex; + Reference<XInputStream> m_xStream; +}; + + + +ModeratorsActiveDataSink::ModeratorsActiveDataSink(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataSink::~ModeratorsActiveDataSink() +{ +} + +// XActiveDataSink. +void SAL_CALL +ModeratorsActiveDataSink::setInputStream ( + const Reference<XInputStream> &rxInputStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setInputStream(rxInputStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxInputStream; +} + + +ModeratorsActiveDataStreamer::ModeratorsActiveDataStreamer( + Moderator &theModerator +) + : m_aModerator(theModerator) +{ +} + + +ModeratorsActiveDataStreamer::~ModeratorsActiveDataStreamer() +{ +} + +// XActiveDataStreamer. +void SAL_CALL +ModeratorsActiveDataStreamer::setStream ( + const Reference<XStream> &rxStream +) + throw( + RuntimeException + ) +{ + m_aModerator.setStream(rxStream); + osl::MutexGuard aGuard(m_aMutex); + m_xStream = rxStream; +} + + + +class ModeratorsInteractionHandler + : public ::cppu::WeakImplHelper1<XInteractionHandler> +{ +public: + + ModeratorsInteractionHandler(Moderator &theModerator); + + ~ModeratorsInteractionHandler(); + + virtual void SAL_CALL + handle( const Reference<XInteractionRequest >& Request ) + throw (RuntimeException); + +private: + + Moderator& m_aModerator; +}; + + +class ModeratorsProgressHandler + : public ::cppu::WeakImplHelper1<XProgressHandler> +{ +public: + + ModeratorsProgressHandler(Moderator &theModerator); + + ~ModeratorsProgressHandler(); + + virtual void SAL_CALL push( const Any& Status ) + throw ( + RuntimeException); + + virtual void SAL_CALL update( const Any& Status ) + throw (RuntimeException); + + virtual void SAL_CALL pop( ) + throw (RuntimeException); + + +private: + + Moderator& m_aModerator; +}; + + +ModeratorsProgressHandler::ModeratorsProgressHandler(Moderator &theModerator) + : m_aModerator(theModerator) +{ +} + +ModeratorsProgressHandler::~ModeratorsProgressHandler() +{ +} + + +void SAL_CALL ModeratorsProgressHandler::push( const Any& Status ) + throw ( + RuntimeException) +{ + m_aModerator.push(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::update( const Any& Status ) + throw (RuntimeException) +{ + m_aModerator.update(Status); +} + + +void SAL_CALL ModeratorsProgressHandler::pop( ) + throw (RuntimeException) +{ + m_aModerator.pop(); +} + + + + +ModeratorsInteractionHandler::ModeratorsInteractionHandler( + Moderator &aModerator) + : m_aModerator(aModerator) +{ +} + + +ModeratorsInteractionHandler::~ModeratorsInteractionHandler() +{ +} + + +void SAL_CALL +ModeratorsInteractionHandler::handle( + const Reference<XInteractionRequest >& Request +) + throw ( + RuntimeException + ) +{ + // wakes up the mainthread + m_aModerator.handle(Request); +} + + + + +Moderator::Moderator( + Reference < XContent >& xContent, + Reference < XInteractionHandler >& xInteract, + Reference < XProgressHandler >& xProgress, + const Command& rArg +) + throw( + ::com::sun::star::ucb::ContentCreationException, + ::com::sun::star::uno::RuntimeException + ) + : m_aMutex(), + + m_aRes(m_aMutex,*this), + m_aResultType(NORESULT), + m_nIOErrorCode(0), + m_aResult(), + + m_aRep(m_aMutex,*this), + m_aReplyType(NOREPLY), + + m_aArg(rArg), + m_aContent( + xContent, + new UcbTaskEnvironment( + xInteract.is() ? new ModeratorsInteractionHandler(*this) : 0, + xProgress.is() ? new ModeratorsProgressHandler(*this) : 0 + )) +{ + // now exchange the whole data sink stuff + // with a thread safe version + + Reference<XInterface> *pxSink = NULL; + + PostCommandArgument2 aPostArg; + OpenCommandArgument2 aOpenArg; + + int dec(2); + if(m_aArg.Argument >>= aPostArg) { + pxSink = &aPostArg.Sink; + dec = 0; + } + else if(m_aArg.Argument >>= aOpenArg) { + pxSink = &aOpenArg.Sink; + dec = 1; + } + + if(dec ==2) + throw ContentCreationException(); + + Reference < XActiveDataSink > xActiveSink(*pxSink,UNO_QUERY); + if(xActiveSink.is()) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataSink(*this)); + + Reference<XActiveDataStreamer> xStreamer( *pxSink, UNO_QUERY ); + if ( xStreamer.is() ) + *pxSink = Reference<XInterface>( + (cppu::OWeakObject*)new ModeratorsActiveDataStreamer(*this)); + + if(dec == 0) + m_aArg.Argument <<= aPostArg; + else if(dec == 1) + m_aArg.Argument <<= aOpenArg; +} + + +Moderator::~Moderator() +{ +} + + +Moderator::Result Moderator::getResult(const sal_uInt32 milliSec) +{ + Result ret; + try { + salhelper::ConditionWaiter aWaiter(m_aRes,milliSec); + ret.type = m_aResultType; + ret.result = m_aResult; + ret.ioErrorCode = m_nIOErrorCode; + + // reset + m_aResultType = NORESULT; + } + catch(const salhelper::ConditionWaiter::timedout&) + { + ret.type = TIMEDOUT; + } + + return ret; +} + + +void Moderator::setReply(ReplyType aReplyType ) +{ + salhelper::ConditionModifier aMod(m_aRep); + m_aReplyType = aReplyType; +} + + +void Moderator::handle( const Reference<XInteractionRequest >& Request ) +{ + ReplyType aReplyType; + + do { + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INTERACTIONREQUEST; + m_aResult <<= Request; + } + + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + + // reset + m_aReplyType = NOREPLY; + } + + if(aReplyType == EXIT) { + Sequence<Reference<XInteractionContinuation> > aSeq( + Request->getContinuations()); + for(sal_Int32 i = 0; i < aSeq.getLength(); ++i) { + Reference<XInteractionAbort> aRef(aSeq[i],UNO_QUERY); + if(aRef.is()) { + aRef->select(); + } + } + + // resignal the exitcondition + setReply(EXIT); + break; + } + } while(aReplyType != REQUESTHANDLED); +} + + + +void Moderator::push( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPUSH; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::update( const Any& Status ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSUPDATE; + m_aResult = Status; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::pop( ) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = PROGRESSPOP; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setStream(const Reference< XStream >& aStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = STREAM; + m_aResult <<= aStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + +void Moderator::setInputStream(const Reference<XInputStream> &rxInputStream) +{ + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = INPUTSTREAM; + m_aResult <<= rxInputStream; + } + ReplyType aReplyType; + { + salhelper::ConditionWaiter aWait(m_aRep); + aReplyType = m_aReplyType; + m_aReplyType = NOREPLY; + } + if(aReplyType == EXIT) + setReply(EXIT); +} + + + +void SAL_CALL Moderator::run() +{ + ResultType aResultType; + Any aResult; + sal_Int32 nIOErrorCode = 0; + + try + { + aResult = m_aContent.executeCommand(m_aArg.Name,m_aArg.Argument); + aResultType = RESULT; + } + catch ( CommandAbortedException ) + { + aResultType = COMMANDABORTED; + } + catch ( CommandFailedException ) + { + aResultType = COMMANDFAILED; + } + catch ( InteractiveIOException& r ) + { + nIOErrorCode = r.Code; + aResultType = INTERACTIVEIO; + } + catch ( UnsupportedDataSinkException& ) + { + aResultType = UNSUPPORTED; + } + catch ( Exception ) + { + aResultType = GENERAL; + } + + { + salhelper::ConditionModifier aMod(m_aRes); + m_aResultType = aResultType; + m_aResult = aResult; + m_nIOErrorCode = nIOErrorCode; + } +} + + + +void SAL_CALL Moderator::onTerminated() +{ + { + salhelper::ConditionWaiter aWaiter(m_aRep); + } + delete this; +} + + +/** + Function for opening UCB contents synchronously, + but with handled timeout; +*/ + +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ); + + +static sal_Bool UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + // http protocol must be handled in a special way: + // during the opening process the input stream may change + // only the last inputstream after notifying the document + // headers is valid + + Reference<XContentIdentifier> xContId( + xContent.is() ? xContent->getIdentifier() : 0 ); + + rtl::OUString aScheme; + if(xContId.is()) + aScheme = xContId->getContentProviderScheme(); + + // now determine wether we use a timeout or not; + if( ! aScheme.equalsIgnoreAsciiCaseAscii("http") && + ! aScheme.equalsIgnoreAsciiCaseAscii("https") && + ! aScheme.equalsIgnoreAsciiCaseAscii("vnd.sun.star.webdav") && + ! aScheme.equalsIgnoreAsciiCaseAscii("ftp")) + return _UCBOpenContentSync( + xLockBytes,xContent,rArg,xSink,xInteract,xProgress,xHandler); + + if ( (aScheme.compareToAscii( "http" ) != COMPARE_EQUAL) || + (aScheme.compareToAscii( "https" ) != COMPARE_EQUAL) ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener; + Reference< XPropertiesChangeNotifier > xProps(xContent,UNO_QUERY); + if(xProps.is()) { + xListener = + new UcbPropertiesChangeListener_Impl(xLockBytes); + xProps->addPropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener); + } + + Any aResult; + bool bException(false); + bool bAborted(false); + bool bResultAchieved(false); + + Moderator* pMod = 0; + try { + pMod = new Moderator(xContent,xInteract,xProgress,rArg); + pMod->create(); + } catch(const ContentCreationException&) { + bResultAchieved = bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + sal_uInt32 nTimeout(5000); // initially 5000 milliSec + while(!bResultAchieved) { + + Moderator::Result res; + // try to get the result for with timeout + res = pMod->getResult(nTimeout); + + switch(res.type) { + case Moderator::PROGRESSPUSH: + { + if(xProgress.is()) + xProgress->push(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSUPDATE: + { + if(xProgress.is()) + xProgress->update(res.result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::PROGRESSPOP: + { + if(xProgress.is()) + xProgress->pop(); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::STREAM: + { + Reference<XStream> result; + if(res.result >>= result) { + Reference < XActiveDataStreamer > xStreamer( + xSink, UNO_QUERY + ); + + if(xStreamer.is()) + xStreamer->setStream(result); + } + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::INPUTSTREAM: + { + Reference<XInputStream> result; + res.result >>= result; + Reference < XActiveDataSink > xActiveSink( + xSink, UNO_QUERY + ); + + if(xActiveSink.is()) + xActiveSink->setInputStream(result); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::TIMEDOUT: + { + Reference<XInteractionRetry> xRet; + if(xInteract.is()) { + InteractiveNetworkConnectException aExcep; + INetURLObject aURL( + xContId.is() ? + xContId->getContentIdentifier() : + rtl::OUString() ); + aExcep.Server = aURL.GetHost(); + aExcep.Classification = InteractionClassification_ERROR; + aExcep.Message = + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "server not responding after five seconds")); + Any request; + request <<= aExcep; + ucbhelper::InteractionRequest *ir = + new ucbhelper::InteractionRequest(request); + Reference<XInteractionRequest> xIR(ir); + Sequence<Reference<XInteractionContinuation> > aSeq(2); + ucbhelper::InteractionRetry *retryP = + new ucbhelper::InteractionRetry(ir); + aSeq[0] = retryP; + ucbhelper::InteractionAbort *abortP = + new ucbhelper::InteractionAbort(ir); + aSeq[1] = abortP; + + ir->setContinuations(aSeq); + xInteract->handle(xIR); + rtl::Reference< ucbhelper::InteractionContinuation > ref + = ir->getSelection(); + if(ref.is()) { + Reference<XInterface> xInt(ref.get()); + xRet = Reference<XInteractionRetry>(xInt,UNO_QUERY); + } + } + + if(!xRet.is()) { + bAborted = true; + xLockBytes->SetError(ERRCODE_ABORT); + } + + break; + } + case Moderator::INTERACTIONREQUEST: + { + Reference<XInteractionRequest> Request; + res.result >>= Request; + xInteract->handle(Request); + pMod->setReply(Moderator::REQUESTHANDLED); + break; + } + case Moderator::RESULT: + { + bResultAchieved = true; + aResult = res.result; + break; + } + case Moderator::COMMANDABORTED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::COMMANDFAILED: + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + break; + } + case Moderator::INTERACTIVEIO: + { + bException = true; + if ( res.ioErrorCode == IOErrorCode_ACCESS_DENIED || + res.ioErrorCode == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( res.ioErrorCode == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( res.ioErrorCode == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + case Moderator::UNSUPPORTED: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + break; + } + default: + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + break; + } + } + + bResultAchieved |= bException; + bResultAchieved |= bAborted; + if(nTimeout == 5000) nTimeout *= 2; + } + + if(pMod) pMod->setReply(Moderator::EXIT); + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( + Sequence< ::rtl::OUString >(), + xListener ); + + return ( bAborted || bException ); +} + +/** + Function for opening UCB contents synchronously + */ +static sal_Bool _UCBOpenContentSync( + UcbLockBytesRef xLockBytes, + Reference < XContent > xContent, + const Command& rArg, + Reference < XInterface > xSink, + Reference < XInteractionHandler > xInteract, + Reference < XProgressHandler > xProgress, + UcbLockBytesHandlerRef xHandler ) +{ + ::ucbhelper::Content aContent( xContent, new UcbTaskEnvironment( xInteract, xProgress ) ); + Reference < XContentIdentifier > xIdent = xContent->getIdentifier(); + ::rtl::OUString aScheme = xIdent->getContentProviderScheme(); + + // http protocol must be handled in a special way: during the opening process the input stream may change + // only the last inputstream after notifying the document headers is valid + if ( aScheme.compareToAscii("http") != COMPARE_EQUAL ) + xLockBytes->SetStreamValid_Impl(); + + Reference< XPropertiesChangeListener > xListener = new UcbPropertiesChangeListener_Impl( xLockBytes ); + Reference< XPropertiesChangeNotifier > xProps ( xContent, UNO_QUERY ); + if ( xProps.is() ) + xProps->addPropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + Any aResult; + bool bException = false; + bool bAborted = false; + + try + { + aResult = aContent.executeCommand( rArg.Name, rArg.Argument ); + } + catch ( CommandAbortedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( CommandFailedException ) + { + bAborted = true; + xLockBytes->SetError( ERRCODE_ABORT ); + } + catch ( InteractiveIOException& r ) + { + bException = true; + if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION ) + xLockBytes->SetError( ERRCODE_IO_ACCESSDENIED ); + else if ( r.Code == IOErrorCode_NOT_EXISTING ) + xLockBytes->SetError( ERRCODE_IO_NOTEXISTS ); + else if ( r.Code == IOErrorCode_CANT_READ ) + xLockBytes->SetError( ERRCODE_IO_CANTREAD ); + else + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + catch ( UnsupportedDataSinkException& ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_NOTSUPPORTED ); + } + catch ( Exception ) + { + bException = true; + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + if ( bAborted || bException ) + { + if( xHandler.Is() ) + xHandler->Handle( UcbLockBytesHandler::CANCEL, xLockBytes ); + + Reference < XActiveDataSink > xActiveSink( xSink, UNO_QUERY ); + if ( xActiveSink.is() ) + xActiveSink->setInputStream( Reference < XInputStream >() ); + + Reference < XActiveDataStreamer > xStreamer( xSink, UNO_QUERY ); + if ( xStreamer.is() ) + xStreamer->setStream( Reference < XStream >() ); + } + + Reference < XActiveDataControl > xControl( xSink, UNO_QUERY ); + if ( xControl.is() ) + xControl->terminate(); + + + if ( xProps.is() ) + xProps->removePropertiesChangeListener( Sequence< ::rtl::OUString >(), xListener ); + + return ( bAborted || bException ); +} + + +//---------------------------------------------------------------------------- +UcbLockBytes::UcbLockBytes( UcbLockBytesHandler* pHandler ) + : m_xInputStream (NULL) + , m_pCommandThread( NULL ) + , m_xHandler( pHandler ) + , m_nError( ERRCODE_NONE ) + , m_bTerminated (sal_False) + , m_bDontClose( sal_False ) + , m_bStreamValid (sal_False) +{ + SetSynchronMode( TRUE ); +} + +//---------------------------------------------------------------------------- +UcbLockBytes::~UcbLockBytes() +{ + if ( !m_bDontClose ) + { + if ( m_xInputStream.is() ) + { + try + { + m_xInputStream->closeInput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } + } + + if ( !m_xInputStream.is() && m_xOutputStream.is() ) + { + try + { + m_xOutputStream->closeOutput(); + } + catch ( RuntimeException const & ) + {} + catch ( IOException const & ) + {} + } +} + +Reference < XInputStream > UcbLockBytes::getInputStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + m_bDontClose = sal_True; + return m_xInputStream; +} + +Reference < XStream > UcbLockBytes::getStream() +{ + vos::OClearableGuard aGuard( m_aMutex ); + Reference < XStream > xStream( m_xSeekable, UNO_QUERY ); + if ( xStream.is() ) + m_bDontClose = sal_True; + return xStream; +} + +//---------------------------------------------------------------------------- + +sal_Bool UcbLockBytes::setStream_Impl( const Reference<XStream>& aStream ) +{ + vos::OClearableGuard aGuard( m_aMutex ); + if ( aStream.is() ) + { + m_xOutputStream = aStream->getOutputStream(); + setInputStream_Impl( aStream->getInputStream(), sal_False ); + m_xSeekable = Reference < XSeekable > ( aStream, UNO_QUERY ); + } + else + { + m_xOutputStream = Reference < XOutputStream >(); + setInputStream_Impl( Reference < XInputStream >() ); + } + + return m_xInputStream.is(); +} + +sal_Bool UcbLockBytes::setInputStream_Impl( const Reference<XInputStream> &rxInputStream, sal_Bool bSetXSeekable ) +{ + sal_Bool bRet = sal_False; + + try + { + vos::OClearableGuard aGuard( m_aMutex ); + + if ( !m_bDontClose && m_xInputStream.is() ) + m_xInputStream->closeInput(); + + m_xInputStream = rxInputStream; + + if( bSetXSeekable ) + { + m_xSeekable = Reference < XSeekable > ( rxInputStream, UNO_QUERY ); + if( !m_xSeekable.is() && rxInputStream.is() ) + { + Reference < XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + Reference< XOutputStream > rxTempOut = Reference < XOutputStream > ( + xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), + UNO_QUERY ); + + if( rxTempOut.is() ) + { + ::comphelper::OStorageHelper::CopyInputToOutput( rxInputStream, rxTempOut ); + m_xInputStream = Reference< XInputStream >( rxTempOut, UNO_QUERY ); + m_xSeekable = Reference < XSeekable > ( rxTempOut, UNO_QUERY ); + } + } + } + + bRet = m_xInputStream.is(); + // aGuard.clear(); + } + catch( Exception& ) + {} + + if ( m_bStreamValid && m_xInputStream.is() ) + m_aInitialized.set(); + + return bRet; +} + +void UcbLockBytes::SetStreamValid_Impl() +{ + m_bStreamValid = sal_True; + if ( m_xInputStream.is() ) + m_aInitialized.set(); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::terminate_Impl() +{ + m_bTerminated = sal_True; + m_aInitialized.set(); + m_aTerminated.set(); + + if ( GetError() == ERRCODE_NONE && !m_xInputStream.is() ) + { + DBG_ERROR("No InputStream, but no error set!" ); + SetError( ERRCODE_IO_NOTEXISTS ); + } + + if ( m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DONE, this ); +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::SetSynchronMode (BOOL bSynchron) +{ + SvLockBytes::SetSynchronMode (bSynchron); +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::ReadAt ( ULONG nPos, void *pBuffer, ULONG nCount, ULONG *pRead) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + Reference <XInputStream> xStream = getInputStream_Impl(); + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_CANTREAD; + else + return ERRCODE_IO_PENDING; + } + + if ( pRead ) + *pRead = 0; + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + if ( !xSeekable.is() ) + return ERRCODE_IO_CANTREAD; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + catch (com::sun::star::lang::IllegalArgumentException) + { + return ERRCODE_IO_CANTSEEK; + } + + Sequence<sal_Int8> aData; + sal_Int32 nSize; + + nCount = VOS_MIN(nCount, 0x7FFFFFFF); + try + { + if ( !m_bTerminated && !IsSynchronMode() ) + { + sal_uInt64 nLen = xSeekable->getLength(); + if ( nPos + nCount > nLen ) + return ERRCODE_IO_PENDING; + } + + nSize = xStream->readBytes( aData, sal_Int32(nCount) ); + } + catch (IOException) + { + return ERRCODE_IO_CANTREAD; + } + + rtl_copyMemory (pBuffer, aData.getConstArray(), nSize); + if (pRead) + *pRead = ULONG(nSize); + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::WriteAt ( ULONG nPos, const void *pBuffer, ULONG nCount, ULONG *pWritten) +{ + if ( pWritten ) + *pWritten = 0; + + DBG_ASSERT( IsSynchronMode(), "Writing is only possible in SynchronMode!" ); + DBG_ASSERT( m_aInitialized.check(), "Writing bevor stream is ready!" ); + + Reference <XSeekable> xSeekable = getSeekable_Impl(); + Reference <XOutputStream> xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() || !xSeekable.is() ) + return ERRCODE_IO_CANTWRITE; + + try + { + xSeekable->seek( nPos ); + } + catch ( IOException ) + { + return ERRCODE_IO_CANTSEEK; + } + + sal_Int8* pData = (sal_Int8*) pBuffer; + Sequence<sal_Int8> aData( pData, nCount ); + try + { + xOutputStream->writeBytes( aData ); + if ( pWritten ) + *pWritten = nCount; + } + catch ( Exception ) + { + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Flush() const +{ + Reference <XOutputStream > xOutputStream = getOutputStream_Impl(); + if ( !xOutputStream.is() ) + return ERRCODE_IO_CANTWRITE; + xOutputStream->flush(); + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::SetSize (ULONG nNewSize) +{ + SvLockBytesStat aStat; + Stat( &aStat, (SvLockBytesStatFlag) 0 ); + ULONG nSize = aStat.nSize; + + if ( nSize > nNewSize ) + { + Reference < XTruncate > xTrunc( getOutputStream_Impl(), UNO_QUERY ); + if ( xTrunc.is() ) + { + xTrunc->truncate(); + nSize = 0; + } + else { + DBG_WARNING("Not truncatable!"); + } + } + + if ( nSize < nNewSize ) + { + ULONG nDiff = nNewSize-nSize, nCount=0; + BYTE* pBuffer = new BYTE[ nDiff ]; + memset(pBuffer, 0, nDiff); // initialize for enhanced security + WriteAt( nSize, pBuffer, nDiff, &nCount ); + delete[] pBuffer; + if ( nCount != nDiff ) + return ERRCODE_IO_CANTWRITE; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +ErrCode UcbLockBytes::Stat( SvLockBytesStat *pStat, SvLockBytesStatFlag) const +{ + if ( IsSynchronMode() ) + { + UcbLockBytes* pThis = const_cast < UcbLockBytes* >( this ); + pThis->m_aInitialized.wait(); + } + + if (!pStat) + return ERRCODE_IO_INVALIDPARAMETER; + + Reference <XInputStream> xStream = getInputStream_Impl(); + Reference <XSeekable> xSeekable = getSeekable_Impl(); + + if ( !xStream.is() ) + { + if ( m_bTerminated ) + return ERRCODE_IO_INVALIDACCESS; + else + return ERRCODE_IO_PENDING; + } + else if( !xSeekable.is() ) + return ERRCODE_IO_CANTTELL; + + try + { + pStat->nSize = ULONG(xSeekable->getLength()); + } + catch (IOException) + { + return ERRCODE_IO_CANTTELL; + } + + return ERRCODE_NONE; +} + +//---------------------------------------------------------------------------- +void UcbLockBytes::Cancel() +{ + // is alive only for compatibility reasons + OSL_ENSURE( m_bTerminated, "UcbLockBytes is not thread safe so it can be used only syncronously!\n" ); +} + +//---------------------------------------------------------------------------- +IMPL_LINK( UcbLockBytes, DataAvailHdl, void*, EMPTYARG ) +{ + if ( hasInputStream_Impl() && m_xHandler.Is() ) + m_xHandler->Handle( UcbLockBytesHandler::DATA_AVAILABLE, this ); + + return 0; +} + +UcbLockBytesRef UcbLockBytes::CreateInputLockBytes( const Reference< XInputStream >& xInputStream ) +{ + if( !xInputStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setInputStream_Impl( xInputStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference< XStream >& xStream ) +{ + if( !xStream.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes(); + xLockBytes->setDontClose_Impl(); + xLockBytes->setStream_Impl( xStream ); + xLockBytes->terminate_Impl(); + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const ::rtl::OUString& rReferer, const ::rtl::OUString& rMediaType, + const Reference < XInputStream >& xPostData, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + PostCommandArgument2 aArgument; + aArgument.Source = xPostData; + aArgument.Sink = xSink; + aArgument.MediaType = rMediaType; + aArgument.Referer = rReferer; + + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii ("post"); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +UcbLockBytesRef UcbLockBytes::CreateLockBytes( const Reference < XContent >& xContent, const Sequence < PropertyValue >& rProps, + StreamMode eOpenMode, const Reference < XInteractionHandler >& xInteractionHandler, UcbLockBytesHandler* pHandler ) +{ + if( !xContent.is() ) + return NULL;; + + UcbLockBytesRef xLockBytes = new UcbLockBytes( pHandler ); + xLockBytes->SetSynchronMode( !pHandler ); + Reference< XActiveDataControl > xSink; + if ( eOpenMode & STREAM_WRITE ) + xSink = (XActiveDataControl*) new UcbStreamer_Impl( xLockBytes ); + else + xSink = (XActiveDataControl*) new UcbDataSink_Impl( xLockBytes ); + + if ( rProps.getLength() ) + { + Reference < XCommandProcessor > xProcessor( xContent, UNO_QUERY ); + Command aCommand; + aCommand.Name = ::rtl::OUString::createFromAscii("setPropertyValues"); + aCommand.Handle = -1; /* unknown */ + aCommand.Argument <<= rProps; + xProcessor->execute( aCommand, 0, Reference < XCommandEnvironment >() ); + } + + OpenCommandArgument2 aArgument; + aArgument.Sink = xSink; + aArgument.Mode = OpenMode::DOCUMENT; + + Command aCommand; + aCommand.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("open") ); + aCommand.Argument <<= aArgument; + + Reference< XProgressHandler > xProgressHdl = new ProgressHandler_Impl( LINK( &xLockBytes, UcbLockBytes, DataAvailHdl ) ); + + sal_Bool bError = UCBOpenContentSync( xLockBytes, + xContent, + aCommand, + xSink, + xInteractionHandler, + xProgressHdl, + pHandler ); + + if ( xLockBytes->GetError() == ERRCODE_NONE && ( bError || !xLockBytes->getInputStream().is() ) ) + { + DBG_ERROR("No InputStream, but no error set!" ); + xLockBytes->SetError( ERRCODE_IO_GENERAL ); + } + + return xLockBytes; +} + +} diff --git a/unotools/source/ucbhelper/ucbstreamhelper.cxx b/unotools/source/ucbhelper/ucbstreamhelper.cxx new file mode 100644 index 000000000000..f27f663b3698 --- /dev/null +++ b/unotools/source/ucbhelper/ucbstreamhelper.cxx @@ -0,0 +1,248 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_unotools.hxx" + +#include <unotools/ucblockbytes.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/ucb/CommandAbortedException.hpp> + +#ifndef _COM_SUN_STAR_UCB_XCOMMANDENVIRONMENT_HDL_ +#include <com/sun/star/ucb/XCommandEnvironment.hdl> +#endif +#include <com/sun/star/ucb/InsertCommandArgument.hpp> +#include <com/sun/star/io/XActiveDataStreamer.hpp> + +#include <ucbhelper/contentbroker.hxx> +#include <ucbhelper/content.hxx> +#include <tools/debug.hxx> +#include <unotools/streamwrap.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +namespace utl +{ + +static SvStream* lcl_CreateStream( const String& rFileName, StreamMode eOpenMode, + Reference < XInteractionHandler > xInteractionHandler, + UcbLockBytesHandler* pHandler, sal_Bool /*bForceSynchron*/, sal_Bool bEnsureFileExists ) +{ + SvStream* pStream = NULL; + ::ucbhelper::ContentBroker* pBroker = ::ucbhelper::ContentBroker::get(); + if ( pBroker ) + { + UcbLockBytesRef xLockBytes; + if ( eOpenMode & STREAM_WRITE ) + { + sal_Bool bTruncate = ( eOpenMode & STREAM_TRUNC ) != 0; + if ( bTruncate ) + { + try + { + // truncate is implemented with deleting the original file + ::ucbhelper::Content aCnt( rFileName, Reference < XCommandEnvironment >() ); + aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) ); + } + + catch ( CommandAbortedException& ) + { + // couldn't truncate/delete + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + + if ( bEnsureFileExists || bTruncate ) + { + try + { + // make sure that the desired file exists before trying to open + SvMemoryStream aStream(0,0); + ::utl::OInputStreamWrapper* pInput = new ::utl::OInputStreamWrapper( aStream ); + Reference< XInputStream > xInput( pInput ); + + ::ucbhelper::Content aContent( rFileName, Reference < XCommandEnvironment >() ); + InsertCommandArgument aInsertArg; + aInsertArg.Data = xInput; + + aInsertArg.ReplaceExisting = sal_False; + Any aCmdArg; + aCmdArg <<= aInsertArg; + aContent.executeCommand( ::rtl::OUString::createFromAscii( "insert" ), aCmdArg ); + } + + // it is NOT an error when the stream already exists and no truncation was desired + catch ( CommandAbortedException& ) + { + // currently never an error is detected ! + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + } + + try + { + // create LockBytes using UCB + ::ucbhelper::Content aContent( rFileName, Reference < XCommandEnvironment >() ); + xLockBytes = UcbLockBytes::CreateLockBytes( aContent.get(), Sequence < PropertyValue >(), + eOpenMode, xInteractionHandler, pHandler ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + catch ( CommandAbortedException& ) + { + } + catch ( ContentCreationException& ) + { + } + catch ( Exception& ) + { + } + } + else + // if no UCB is present at least conventional file io is supported + pStream = new SvFileStream( rFileName, eOpenMode ); + + return pStream; +} + +//============================================================================ + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, Reference < XInteractionHandler >(), pHandler, bForceSynchron, sal_True /* bEnsureFileExists */ ); +} + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + Reference < XInteractionHandler > xInteractionHandler, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, xInteractionHandler, pHandler, bForceSynchron, sal_True /* bEnsureFileExists */ ); +} + +SvStream* UcbStreamHelper::CreateStream( const String& rFileName, StreamMode eOpenMode, + sal_Bool bFileExists, + UcbLockBytesHandler* pHandler, sal_Bool bForceSynchron ) +{ + return lcl_CreateStream( rFileName, eOpenMode, Reference < XInteractionHandler >(), pHandler, bForceSynchron, !bFileExists ); +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XInputStream > xStream ) +{ + SvStream* pStream = NULL; + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateInputLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + + return pStream; +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XStream > xStream ) +{ + SvStream* pStream = NULL; + if ( xStream->getOutputStream().is() ) + { + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + else + return CreateStream( xStream->getInputStream() ); + + return pStream; +} + +SvStream* UcbStreamHelper::CreateStream( Reference < XInputStream > xStream, sal_Bool bCloseStream ) +{ + SvStream* pStream = NULL; + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateInputLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + if ( !bCloseStream ) + xLockBytes->setDontClose_Impl(); + + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + + return pStream; +}; + +SvStream* UcbStreamHelper::CreateStream( Reference < XStream > xStream, sal_Bool bCloseStream ) +{ + SvStream* pStream = NULL; + if ( xStream->getOutputStream().is() ) + { + UcbLockBytesRef xLockBytes = UcbLockBytes::CreateLockBytes( xStream ); + if ( xLockBytes.Is() ) + { + if ( !bCloseStream ) + xLockBytes->setDontClose_Impl(); + + pStream = new SvStream( xLockBytes ); + pStream->SetBufferSize( 4096 ); + pStream->SetError( xLockBytes->GetError() ); + } + } + else + return CreateStream( xStream->getInputStream(), bCloseStream ); + + return pStream; +}; + +} diff --git a/unotools/source/ucbhelper/xtempfile.cxx b/unotools/source/ucbhelper/xtempfile.cxx new file mode 100644 index 000000000000..023211dc3527 --- /dev/null +++ b/unotools/source/ucbhelper/xtempfile.cxx @@ -0,0 +1,576 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include "precompiled_unotools.hxx" +#include <XTempFile.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/typeprovider.hxx> +#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP +#include <com/sun/star/registry/XRegistryKey.hpp> +#endif +#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP +#include <com/sun/star/beans/PropertyAttribute.hpp> +#endif +#include <unotools/tempfile.hxx> +#include <osl/file.hxx> +#include <unotools/configmgr.hxx> +#include <tools/urlobj.hxx> +#include <tools/debug.hxx> + +namespace css = com::sun::star; + +// copy define from desktop\source\app\appinit.cxx + +#define DESKTOP_TEMPNAMEBASE_DIR "/temp/soffice.tmp" + +OTempFileService::OTempFileService(::css::uno::Reference< ::css::uno::XComponentContext > const & context) +: ::cppu::PropertySetMixin< ::css::io::XTempFile >( + context + , static_cast< Implements >( IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET | IMPLEMENTS_PROPERTY_ACCESS ) + , com::sun::star::uno::Sequence< rtl::OUString >() ) +, mpStream( NULL ) +, mbRemoveFile( sal_True ) +, mbInClosed( sal_False ) +, mbOutClosed( sal_False ) +, mnCachedPos( 0 ) +, mbHasCachedPos( sal_False ) + +{ + mpTempFile = new ::utl::TempFile; + mpTempFile->EnableKillingFile ( sal_True ); +} + +OTempFileService::~OTempFileService () +{ + if ( mpTempFile ) + delete mpTempFile; +} + + +// XInterface + +::css::uno::Any SAL_CALL OTempFileService::queryInterface( ::css::uno::Type const & aType ) +throw ( ::css::uno::RuntimeException ) +{ + ::css::uno::Any aResult( OTempFileBase::queryInterface( aType ) ); + if (!aResult.hasValue()) + aResult = cppu::PropertySetMixin< ::css::io::XTempFile >::queryInterface( aType ) ; + return aResult; +}; +void SAL_CALL OTempFileService::acquire( ) +throw () +{ + OTempFileBase::acquire(); +} +void SAL_CALL OTempFileService::release( ) +throw () +{ + OTempFileBase::release(); +} + +// XTypeProvider + +::css::uno::Sequence< ::css::uno::Type > SAL_CALL OTempFileService::getTypes( ) +throw ( ::css::uno::RuntimeException ) +{ + static ::cppu::OTypeCollection* pTypeCollection = NULL; + if ( pTypeCollection == NULL ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; + + if ( pTypeCollection == NULL ) + { + static ::cppu::OTypeCollection aTypeCollection( + ::getCppuType( ( const ::css::uno::Reference< ::css::beans::XPropertySet >*)NULL ) + ,OTempFileBase::getTypes() ); + pTypeCollection = &aTypeCollection; + } + } + return pTypeCollection->getTypes(); +}; +::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId( ) +throw ( ::css::uno::RuntimeException ) +{ + return OTempFileBase::getImplementationId(); +} + +// XTempFile + +sal_Bool SAL_CALL OTempFileService::getRemoveFile() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + // the stream is already disconnected + throw ::css::uno::RuntimeException(); + } + + return mbRemoveFile; +}; +void SAL_CALL OTempFileService::setRemoveFile( sal_Bool _removefile ) +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + // the stream is already disconnected + throw ::css::uno::RuntimeException(); + } + + mbRemoveFile = _removefile; + mpTempFile->EnableKillingFile( mbRemoveFile ); +}; +::rtl::OUString SAL_CALL OTempFileService::getUri() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + throw ::css::uno::RuntimeException(); + } + + return ::rtl::OUString( mpTempFile->GetURL() ); + +}; +::rtl::OUString SAL_CALL OTempFileService::getResourceName() +throw ( ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( !mpTempFile ) + { + throw ::css::uno::RuntimeException(); +} + + return ::rtl::OUString( mpTempFile->GetFileName() ); +}; + + + +// XInputStream + +sal_Int32 SAL_CALL OTempFileService::readBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) +throw (::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + if (nBytesToRead < 0) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); + + aData.realloc(nBytesToRead); + + sal_uInt32 nRead = mpStream->Read(static_cast < void* > ( aData.getArray() ), nBytesToRead); + checkError(); + + if (nRead < static_cast < sal_uInt32 > ( nBytesToRead ) ) + aData.realloc( nRead ); + + if ( sal::static_int_cast<sal_uInt32>(nBytesToRead) > nRead ) + { + // usually that means that the stream was read till the end + // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) + mnCachedPos = mpStream->Tell(); + mbHasCachedPos = sal_True; + + mpStream = NULL; + if ( mpTempFile ) + mpTempFile->CloseStream(); + } + + return nRead; +} +sal_Int32 SAL_CALL OTempFileService::readSomeBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + checkError(); + + if (nMaxBytesToRead < 0) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast < ::css::uno::XWeak * >( this ) ); + + if (mpStream->IsEof()) + { + aData.realloc(0); + return 0; + } + else + return readBytes(aData, nMaxBytesToRead); +} +void SAL_CALL OTempFileService::skipBytes( sal_Int32 nBytesToSkip ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + checkError(); + mpStream->SeekRel(nBytesToSkip); + checkError(); +} +sal_Int32 SAL_CALL OTempFileService::available( ) +throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + + sal_uInt32 nPos = mpStream->Tell(); + checkError(); + + mpStream->Seek(STREAM_SEEK_TO_END); + checkError(); + + sal_Int32 nAvailable = (sal_Int32)mpStream->Tell() - nPos; + mpStream->Seek(nPos); + checkError(); + + return nAvailable; +} +void SAL_CALL OTempFileService::closeInput( ) +throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbInClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + mbInClosed = sal_True; + + if ( mbOutClosed ) + { + // stream will be deleted by TempFile implementation + mpStream = NULL; + + if ( mpTempFile ) + { + delete mpTempFile; + mpTempFile = NULL; + } + } +} + +// XOutputStream + +void SAL_CALL OTempFileService::writeBytes( const ::css::uno::Sequence< sal_Int8 >& aData ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + sal_uInt32 nWritten = mpStream->Write(aData.getConstArray(),aData.getLength()); + checkError(); + if ( nWritten != (sal_uInt32)aData.getLength()) + throw ::css::io::BufferSizeExceededException( ::rtl::OUString(),static_cast < ::css::uno::XWeak * > ( this ) ); +} +void SAL_CALL OTempFileService::flush( ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + checkConnected(); + mpStream->Flush(); + checkError(); +} +void SAL_CALL OTempFileService::closeOutput( ) +throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + if ( mbOutClosed ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); + + mbOutClosed = sal_True; + + // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) + if ( mpStream ) + { + mnCachedPos = mpStream->Tell(); + mbHasCachedPos = sal_True; + + mpStream = NULL; + if ( mpTempFile ) + mpTempFile->CloseStream(); + } + + if ( mbInClosed ) + { + // stream will be deleted by TempFile implementation + mpStream = NULL; + + if ( mpTempFile ) + { + delete mpTempFile; + mpTempFile = NULL; + } + } +} + + +void OTempFileService::checkError () const +{ + if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE ) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); +} +void OTempFileService::checkConnected () +{ + if (!mpStream && mpTempFile) + { + mpStream = mpTempFile->GetStream( STREAM_STD_READWRITE ); + if ( mpStream && mbHasCachedPos ) + { + mpStream->Seek( sal::static_int_cast<sal_Size>(mnCachedPos) ); + if ( mpStream->SvStream::GetError () == ERRCODE_NONE ) + { + mbHasCachedPos = sal_False; + mnCachedPos = 0; + } + else + { + mpStream = NULL; + mpTempFile->CloseStream(); + } + } + } + + if (!mpStream) + throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); +} + +// XSeekable + +void SAL_CALL OTempFileService::seek( sal_Int64 nLocation ) +throw ( ::css::lang::IllegalArgumentException, ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + if ( nLocation < 0 || nLocation > getLength() ) + throw ::css::lang::IllegalArgumentException(); + + mpStream->Seek((sal_uInt32) nLocation ); + checkError(); +} +sal_Int64 SAL_CALL OTempFileService::getPosition( ) +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + + sal_uInt32 nPos = mpStream->Tell(); + checkError(); + return (sal_Int64)nPos; +} +sal_Int64 SAL_CALL OTempFileService::getLength( ) +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + + sal_uInt32 nCurrentPos = mpStream->Tell(); + checkError(); + + mpStream->Seek(STREAM_SEEK_TO_END); + sal_uInt32 nEndPos = mpStream->Tell(); + mpStream->Seek(nCurrentPos); + + checkError(); + + return (sal_Int64)nEndPos; +} + + +// XStream + +::css::uno::Reference< ::css::io::XInputStream > SAL_CALL OTempFileService::getInputStream() +throw ( ::css::uno::RuntimeException ) + { + return ::css::uno::Reference< ::css::io::XInputStream >( *this, ::css::uno::UNO_QUERY ); +} + +::css::uno::Reference< ::css::io::XOutputStream > SAL_CALL OTempFileService::getOutputStream() +throw ( ::css::uno::RuntimeException ) + { + return ::css::uno::Reference< ::css::io::XOutputStream >( *this, ::css::uno::UNO_QUERY ); + } + +// XTruncate + +void SAL_CALL OTempFileService::truncate() +throw ( ::css::io::IOException, ::css::uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( maMutex ); + checkConnected(); + // SetStreamSize() call does not change the position + mpStream->Seek( 0 ); + mpStream->SetStreamSize( 0 ); + checkError(); +} + +// XServiceInfo + +::rtl::OUString SAL_CALL OTempFileService::getImplementationName() +throw ( ::css::uno::RuntimeException ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL OTempFileService::supportsService( ::rtl::OUString const & rServiceName ) +throw ( ::css::uno::RuntimeException ) +{ + ::css::uno::Sequence< ::rtl::OUString > aServices(getSupportedServiceNames_Static()); + return rServiceName == aServices[0]; +} + +::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames() +throw ( ::css::uno::RuntimeException ) +{ + return getSupportedServiceNames_Static(); +} + + + +::rtl::OUString OTempFileService::getImplementationName_Static () +{ + return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) ); +} +::css::uno::Sequence < ::rtl::OUString > OTempFileService::getSupportedServiceNames_Static() +{ + ::css::uno::Sequence < ::rtl::OUString > aNames ( 1 ); + aNames[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); + return aNames; +} +::css::uno::Reference < ::css::uno::XInterface >SAL_CALL XTempFile_createInstance( + css::uno::Reference< ::css::uno::XComponentContext > const & context) + SAL_THROW( ( css::uno::Exception ) ) +{ + return static_cast< ::cppu::OWeakObject * >( new OTempFileService(context) ); +} + +::css::uno::Reference < ::css::lang::XSingleComponentFactory > OTempFileService::createServiceFactory_Static( ::css::uno::Reference < ::css::lang::XMultiServiceFactory > const & ) +{ + return ::cppu::createSingleComponentFactory( XTempFile_createInstance, getImplementationName_Static(), getSupportedServiceNames_Static() ); +} + +static sal_Bool writeInfo( void * pRegistryKey, + const ::rtl::OUString & rImplementationName, + ::css::uno::Sequence< ::rtl::OUString > const & rServiceNames ) +{ + ::rtl::OUString aKeyName( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + aKeyName += rImplementationName; + aKeyName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "/UNO/SERVICES" ) ); + + ::css::uno::Reference< ::css::registry::XRegistryKey > xKey; + try + { + xKey = static_cast< ::css::registry::XRegistryKey * >( + pRegistryKey )->createKey( aKeyName ); + } + catch ( ::css::registry::InvalidRegistryException const & ) + { + } + + if ( !xKey.is() ) + return sal_False; + + sal_Bool bSuccess = sal_True; + + for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n ) + { + try + { + xKey->createKey( rServiceNames[ n ] ); + } + catch ( ::css::registry::InvalidRegistryException const & ) + { + bSuccess = sal_False; + break; + } + } + return bSuccess; +} +// C functions to implement this as a component + +extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + +/** + * This function creates an implementation section in the registry and another subkey + * for each supported service. + * @param pServiceManager generic uno interface providing a service manager + * @param pRegistryKey generic uno interface providing registry key to write + */ +extern "C" SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( void* /*pServiceManager*/, void* pRegistryKey ) +{ + return pRegistryKey && + writeInfo (pRegistryKey, + OTempFileService::getImplementationName_Static(), + OTempFileService::getSupportedServiceNames_Static() ); +} + + +/** + * This function is called to get service factories for an implementation. + * @param pImplName name of implementation + * @param pServiceManager generic uno interface providing a service manager to instantiate components + * @param pRegistryKey registry data key to read and write component persistent data + * @return a component factory (generic uno interface) + */ +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + ::css::uno::Reference< ::css::lang::XMultiServiceFactory > xSMgr( + reinterpret_cast< ::css::lang::XMultiServiceFactory * >( pServiceManager ) ); + ::css::uno::Reference< ::css::lang::XSingleComponentFactory > xFactory; + + if (OTempFileService::getImplementationName_Static().compareToAscii( pImplName ) == 0) + xFactory = OTempFileService::createServiceFactory_Static ( xSMgr ); + + if ( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} |