| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sot.hxx" |
| #include <com/sun/star/io/NotConnectedException.hpp> |
| #include <com/sun/star/io/BufferSizeExceededException.hpp> |
| #include <com/sun/star/uno/RuntimeException.hpp> |
| #include <com/sun/star/lang/IllegalArgumentException.hpp> |
| #include <ucbhelper/content.hxx> |
| #include <com/sun/star/uno/Reference.h> |
| #include <com/sun/star/ucb/XCommandEnvironment.hpp> |
| #include <unotools/tempfile.hxx> |
| #include <unotools/ucbstreamhelper.hxx> |
| #include <com/sun/star/io/XInputStream.hpp> |
| #include <com/sun/star/ucb/InsertCommandArgument.hpp> |
| #include <com/sun/star/ucb/ResultSetException.hpp> |
| #include <com/sun/star/uno/Sequence.h> |
| #include <com/sun/star/sdbc/XResultSet.hdl> |
| #include <com/sun/star/ucb/XContentAccess.hpp> |
| #include <com/sun/star/sdbc/XRow.hpp> |
| #include <com/sun/star/ucb/CommandAbortedException.hpp> |
| #include <com/sun/star/datatransfer/DataFlavor.hpp> |
| #include <com/sun/star/ucb/ContentInfo.hpp> |
| #include <com/sun/star/ucb/ContentInfoAttribute.hpp> |
| #include <com/sun/star/beans/Property.hpp> |
| #include <com/sun/star/packages/manifest/XManifestWriter.hpp> |
| #include <com/sun/star/packages/manifest/XManifestReader.hpp> |
| #include <com/sun/star/ucb/InteractiveIOException.hpp> |
| |
| #include <rtl/digest.h> |
| #include <tools/ref.hxx> |
| #include <tools/debug.hxx> |
| #include <unotools/streamhelper.hxx> |
| #include <unotools/streamwrap.hxx> |
| #include <unotools/ucbhelper.hxx> |
| #include <unotools/localfilehelper.hxx> |
| #include <tools/list.hxx> |
| #include <tools/urlobj.hxx> |
| #include <unotools/streamwrap.hxx> |
| #include <comphelper/processfactory.hxx> |
| #include <cppuhelper/implbase2.hxx> |
| #include <ucbhelper/commandenvironment.hxx> |
| |
| #include "sot/stg.hxx" |
| #include "sot/storinfo.hxx" |
| #include <sot/storage.hxx> |
| #include <sot/exchange.hxx> |
| #include <sot/formats.hxx> |
| #include "sot/clsids.hxx" |
| |
| #include "unostorageholder.hxx" |
| |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::beans; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::ucb; |
| using namespace ::com::sun::star::io; |
| using namespace ::com::sun::star::sdbc; |
| using namespace ::ucbhelper; |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| #include <stdio.h> |
| static int nOpenFiles=0; |
| static int nOpenStreams=0; |
| #endif |
| |
| typedef ::cppu::WeakImplHelper2 < XInputStream, XSeekable > FileInputStreamWrapper_Base; |
| class FileStreamWrapper_Impl : public FileInputStreamWrapper_Base |
| { |
| protected: |
| ::osl::Mutex m_aMutex; |
| String m_aURL; |
| SvStream* m_pSvStream; |
| |
| public: |
| FileStreamWrapper_Impl( const String& rName ); |
| virtual ~FileStreamWrapper_Impl(); |
| |
| //DECLARE_UNO3_AGG_DEFAULTS( FileStreamWrapper_Impl, FileInputStreamWrapper_Base); |
| |
| virtual void SAL_CALL seek( sal_Int64 _nLocation ) throw ( IllegalArgumentException, IOException, RuntimeException); |
| virtual sal_Int64 SAL_CALL getPosition( ) throw ( IOException, RuntimeException); |
| virtual sal_Int64 SAL_CALL getLength( ) throw ( IOException, RuntimeException); |
| virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException ); |
| virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException ); |
| virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException); |
| virtual sal_Int32 SAL_CALL available() throw( NotConnectedException, RuntimeException ); |
| virtual void SAL_CALL closeInput() throw( NotConnectedException, RuntimeException ); |
| |
| protected: |
| void checkConnected(); |
| void checkError(); |
| }; |
| |
| //------------------------------------------------------------------ |
| FileStreamWrapper_Impl::FileStreamWrapper_Impl( const String& rName ) |
| : m_aURL( rName ) |
| , m_pSvStream(0) |
| { |
| // if no URL is provided the stream is empty |
| } |
| |
| //------------------------------------------------------------------ |
| FileStreamWrapper_Impl::~FileStreamWrapper_Impl() |
| { |
| if ( m_pSvStream ) |
| { |
| delete m_pSvStream; |
| #if OSL_DEBUG_LEVEL > 1 |
| --nOpenFiles; |
| #endif |
| } |
| |
| if ( m_aURL.Len() ) |
| ::utl::UCBContentHelper::Kill( m_aURL ); |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 SAL_CALL FileStreamWrapper_Impl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) |
| throw( NotConnectedException, BufferSizeExceededException, RuntimeException ) |
| { |
| if ( !m_aURL.Len() ) |
| { |
| aData.realloc( 0 ); |
| return 0; |
| } |
| |
| checkConnected(); |
| |
| if (nBytesToRead < 0) |
| throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this)); |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| |
| aData.realloc(nBytesToRead); |
| |
| sal_uInt32 nRead = m_pSvStream->Read((void*)aData.getArray(), nBytesToRead); |
| checkError(); |
| |
| // Wenn gelesene Zeichen < MaxLength, Sequence anpassen |
| if (nRead < (sal_uInt32)nBytesToRead) |
| aData.realloc( nRead ); |
| |
| return nRead; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 SAL_CALL FileStreamWrapper_Impl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) throw( NotConnectedException, BufferSizeExceededException, RuntimeException ) |
| { |
| if ( !m_aURL.Len() ) |
| { |
| aData.realloc( 0 ); |
| return 0; |
| } |
| |
| checkError(); |
| |
| if (nMaxBytesToRead < 0) |
| throw BufferSizeExceededException(::rtl::OUString(),static_cast<XWeak*>(this)); |
| |
| if (m_pSvStream->IsEof()) |
| { |
| aData.realloc(0); |
| return 0; |
| } |
| else |
| return readBytes(aData, nMaxBytesToRead); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL FileStreamWrapper_Impl::skipBytes(sal_Int32 nBytesToSkip) throw( NotConnectedException, BufferSizeExceededException, RuntimeException ) |
| { |
| if ( !m_aURL.Len() ) |
| return; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkError(); |
| |
| #ifdef DBG_UTIL |
| sal_uInt32 nCurrentPos = m_pSvStream->Tell(); |
| #endif |
| |
| m_pSvStream->SeekRel(nBytesToSkip); |
| checkError(); |
| |
| #ifdef DBG_UTIL |
| nCurrentPos = m_pSvStream->Tell(); |
| #endif |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int32 SAL_CALL FileStreamWrapper_Impl::available() throw( NotConnectedException, RuntimeException ) |
| { |
| if ( !m_aURL.Len() ) |
| return 0; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkConnected(); |
| |
| sal_uInt32 nPos = m_pSvStream->Tell(); |
| checkError(); |
| |
| m_pSvStream->Seek(STREAM_SEEK_TO_END); |
| checkError(); |
| |
| sal_Int32 nAvailable = (sal_Int32)m_pSvStream->Tell() - nPos; |
| m_pSvStream->Seek(nPos); |
| checkError(); |
| |
| return nAvailable; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL FileStreamWrapper_Impl::closeInput() throw( NotConnectedException, RuntimeException ) |
| { |
| if ( !m_aURL.Len() ) |
| return; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkConnected(); |
| DELETEZ( m_pSvStream ); |
| #if OSL_DEBUG_LEVEL > 1 |
| --nOpenFiles; |
| #endif |
| ::utl::UCBContentHelper::Kill( m_aURL ); |
| m_aURL.Erase(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| void SAL_CALL FileStreamWrapper_Impl::seek( sal_Int64 _nLocation ) throw (IllegalArgumentException, IOException, RuntimeException) |
| { |
| if ( !m_aURL.Len() ) |
| return; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkConnected(); |
| |
| m_pSvStream->Seek((sal_uInt32)_nLocation); |
| checkError(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int64 SAL_CALL FileStreamWrapper_Impl::getPosition( ) throw (IOException, RuntimeException) |
| { |
| if ( !m_aURL.Len() ) |
| return 0; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkConnected(); |
| |
| sal_uInt32 nPos = m_pSvStream->Tell(); |
| checkError(); |
| return (sal_Int64)nPos; |
| } |
| |
| //------------------------------------------------------------------------------ |
| sal_Int64 SAL_CALL FileStreamWrapper_Impl::getLength( ) throw (IOException, RuntimeException) |
| { |
| if ( !m_aURL.Len() ) |
| return 0; |
| |
| ::osl::MutexGuard aGuard( m_aMutex ); |
| checkConnected(); |
| |
| sal_uInt32 nCurrentPos = m_pSvStream->Tell(); |
| checkError(); |
| |
| m_pSvStream->Seek(STREAM_SEEK_TO_END); |
| sal_uInt32 nEndPos = m_pSvStream->Tell(); |
| m_pSvStream->Seek(nCurrentPos); |
| |
| checkError(); |
| |
| return (sal_Int64)nEndPos; |
| } |
| |
| //------------------------------------------------------------------------------ |
| void FileStreamWrapper_Impl::checkConnected() |
| { |
| if ( !m_aURL.Len() ) |
| throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this))); |
| if ( !m_pSvStream ) |
| { |
| m_pSvStream = ::utl::UcbStreamHelper::CreateStream( m_aURL, STREAM_STD_READ ); |
| #if OSL_DEBUG_LEVEL > 1 |
| ++nOpenFiles; |
| #endif |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| void FileStreamWrapper_Impl::checkError() |
| { |
| checkConnected(); |
| |
| if (m_pSvStream->SvStream::GetError() != ERRCODE_NONE) |
| // TODO: really evaluate the error |
| throw NotConnectedException(::rtl::OUString(), const_cast<XWeak*>(static_cast<const XWeak*>(this))); |
| } |
| |
| TYPEINIT1( UCBStorageStream, BaseStorageStream ); |
| TYPEINIT1( UCBStorage, BaseStorage ); |
| |
| #define COMMIT_RESULT_FAILURE 0 |
| #define COMMIT_RESULT_NOTHING_TO_DO 1 |
| #define COMMIT_RESULT_SUCCESS 2 |
| |
| #define min( x, y ) (( x < y ) ? x : y) |
| #define max( x, y ) (( x > y ) ? x : y) |
| |
| sal_Int32 GetFormatId_Impl( SvGlobalName aName ) |
| { |
| // if ( aName == SvGlobalName( SO3_SW_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARWRITER_8; |
| // if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARWRITERWEB_8; |
| // if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARWRITERGLOB_8; |
| // if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARDRAW_8; |
| // if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARIMPRESS_8; |
| // if ( aName == SvGlobalName( SO3_SC_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARCALC_8; |
| // if ( aName == SvGlobalName( SO3_SCH_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARCHART_8; |
| // if ( aName == SvGlobalName( SO3_SM_CLASSID_8 ) ) |
| // return SOT_FORMATSTR_ID_STARMATH_8; |
| if ( aName == SvGlobalName( SO3_SW_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARWRITER_60; |
| if ( aName == SvGlobalName( SO3_SWWEB_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARWRITERWEB_60; |
| if ( aName == SvGlobalName( SO3_SWGLOB_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARWRITERGLOB_60; |
| if ( aName == SvGlobalName( SO3_SDRAW_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARDRAW_60; |
| if ( aName == SvGlobalName( SO3_SIMPRESS_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARIMPRESS_60; |
| if ( aName == SvGlobalName( SO3_SC_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARCALC_60; |
| if ( aName == SvGlobalName( SO3_SCH_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARCHART_60; |
| if ( aName == SvGlobalName( SO3_SM_CLASSID_60 ) ) |
| return SOT_FORMATSTR_ID_STARMATH_60; |
| if ( aName == SvGlobalName( SO3_OUT_CLASSID ) || |
| aName == SvGlobalName( SO3_APPLET_CLASSID ) || |
| aName == SvGlobalName( SO3_PLUGIN_CLASSID ) || |
| aName == SvGlobalName( SO3_IFRAME_CLASSID ) ) |
| // allowed, but not supported |
| return 0; |
| else |
| { |
| DBG_ERROR( "Unknown UCB storage format!" ); |
| return 0; |
| } |
| } |
| |
| |
| SvGlobalName GetClassId_Impl( sal_Int32 nFormat ) |
| { |
| switch ( nFormat ) |
| { |
| case SOT_FORMATSTR_ID_STARWRITER_8 : |
| case SOT_FORMATSTR_ID_STARWRITER_8_TEMPLATE : |
| return SvGlobalName( SO3_SW_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARWRITERWEB_8 : |
| return SvGlobalName( SO3_SWWEB_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARWRITERGLOB_8 : |
| return SvGlobalName( SO3_SWGLOB_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARDRAW_8 : |
| case SOT_FORMATSTR_ID_STARDRAW_8_TEMPLATE : |
| return SvGlobalName( SO3_SDRAW_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARIMPRESS_8 : |
| case SOT_FORMATSTR_ID_STARIMPRESS_8_TEMPLATE : |
| return SvGlobalName( SO3_SIMPRESS_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARCALC_8 : |
| case SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE : |
| return SvGlobalName( SO3_SC_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARCHART_8 : |
| case SOT_FORMATSTR_ID_STARCHART_8_TEMPLATE : |
| return SvGlobalName( SO3_SCH_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARMATH_8 : |
| case SOT_FORMATSTR_ID_STARMATH_8_TEMPLATE : |
| return SvGlobalName( SO3_SM_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARWRITER_60 : |
| return SvGlobalName( SO3_SW_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARWRITERWEB_60 : |
| return SvGlobalName( SO3_SWWEB_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARWRITERGLOB_60 : |
| return SvGlobalName( SO3_SWGLOB_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARDRAW_60 : |
| return SvGlobalName( SO3_SDRAW_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARIMPRESS_60 : |
| return SvGlobalName( SO3_SIMPRESS_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARCALC_60 : |
| return SvGlobalName( SO3_SC_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARCHART_60 : |
| return SvGlobalName( SO3_SCH_CLASSID_60 ); |
| case SOT_FORMATSTR_ID_STARMATH_60 : |
| return SvGlobalName( SO3_SM_CLASSID_60 ); |
| default : |
| //DBG_ERROR( "Unknown UCB storage format!" ); |
| return SvGlobalName(); |
| } |
| } |
| |
| // All storage and streams are refcounted internally; outside of this classes they are only accessible through a handle |
| // class, that uses the refcounted object as impl-class. |
| |
| enum RepresentModes { |
| nonset, |
| svstream, |
| xinputstream |
| }; |
| |
| class UCBStorageStream_Impl : public SvRefBase, public SvStream |
| { |
| ~UCBStorageStream_Impl(); |
| public: |
| |
| virtual sal_uLong GetData( void* pData, sal_uLong nSize ); |
| virtual sal_uLong PutData( const void* pData, sal_uLong nSize ); |
| virtual sal_uLong SeekPos( sal_uLong nPos ); |
| virtual void SetSize( sal_uLong nSize ); |
| virtual void FlushData(); |
| virtual void ResetError(); |
| |
| UCBStorageStream* m_pAntiImpl; // only valid if an external reference exists |
| |
| String m_aOriginalName;// the original name before accessing the stream |
| String m_aName; // the actual name ( changed with a Rename command at the parent ) |
| String m_aURL; // the full path name to create the content |
| String m_aContentType; |
| String m_aOriginalContentType; |
| ByteString m_aKey; |
| ::ucbhelper::Content* m_pContent; // the content that provides the data |
| Reference<XInputStream> m_rSource; // the stream covering the original data of the content |
| SvStream* m_pStream; // the stream worked on; for readonly streams it is the original stream of the content |
| // for read/write streams it's a copy into a temporary file |
| String m_aTempURL; // URL of this temporary stream |
| RepresentModes m_nRepresentMode; // should it be used as XInputStream or as SvStream |
| long m_nError; |
| StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing ) |
| sal_Bool m_bSourceRead; // Source still contains useful information |
| sal_Bool m_bModified; // only modified streams will be sent to the original content |
| sal_Bool m_bCommited; // sending the streams is coordinated by the root storage of the package |
| sal_Bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages |
| // this means that the root storage does an autocommit when its external |
| // reference is destroyed |
| sal_Bool m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream |
| |
| UCBStorageStream_Impl( const String&, StreamMode, UCBStorageStream*, sal_Bool, const ByteString* pKey=0, sal_Bool bRepair = sal_False, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() ); |
| |
| void Free(); |
| sal_Bool Init(); |
| sal_Bool Clear(); |
| sal_Int16 Commit(); // if modified and commited: transfer an XInputStream to the content |
| sal_Bool Revert(); // discard all changes |
| BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream |
| sal_uLong GetSize(); |
| |
| sal_uLong ReadSourceWriteTemporary( sal_uLong aLength ); // read aLength from source and copy to temporary, |
| // no seeking is produced |
| sal_uLong ReadSourceWriteTemporary(); // read source till the end and copy to temporary, |
| // no seeking is produced |
| #if 0 |
| sal_uLong CopySourceToTemporary( sal_uLong aLength ); // same as ReadSourceWriteToTemporary( aLength ) |
| // but the writing is done at the end of temporary |
| // pointer position is not changed |
| #endif |
| |
| sal_uLong CopySourceToTemporary(); // same as ReadSourceWriteToTemporary() |
| // but the writing is done at the end of temporary |
| // pointer position is not changed |
| Reference<XInputStream> GetXInputStream(); // return XInputStream, after that |
| // this class is close to be unusable |
| // since it can not read and write |
| using SvStream::SetError; |
| void SetError( sal_uInt32 nError ); |
| void PrepareCachedForReopen( StreamMode nMode ); |
| }; |
| |
| SV_DECL_IMPL_REF( UCBStorageStream_Impl ); |
| |
| struct UCBStorageElement_Impl; |
| DECLARE_LIST( UCBStorageElementList_Impl, UCBStorageElement_Impl* ) |
| |
| class UCBStorage_Impl : public SvRefBase |
| { |
| ~UCBStorage_Impl(); |
| public: |
| UCBStorage* m_pAntiImpl; // only valid if external references exists |
| |
| String m_aOriginalName;// the original name before accessing the storage |
| String m_aName; // the actual name ( changed with a Rename command at the parent ) |
| String m_aURL; // the full path name to create the content |
| String m_aContentType; |
| String m_aOriginalContentType; |
| ::ucbhelper::Content* m_pContent; // the content that provides the storage elements |
| ::utl::TempFile* m_pTempFile; // temporary file, only for storages on stream |
| SvStream* m_pSource; // original stream, only for storages on a stream |
| //SvStream* m_pStream; // the corresponding editable stream, only for storage on a stream |
| long m_nError; |
| StreamMode m_nMode; // open mode ( read/write/trunc/nocreate/sharing ) |
| sal_Bool m_bModified; // only modified elements will be sent to the original content |
| sal_Bool m_bCommited; // sending the streams is coordinated by the root storage of the package |
| sal_Bool m_bDirect; // the storage and its streams are opened in direct mode; for UCBStorages |
| // this means that the root storage does an autocommit when its external |
| // reference is destroyed |
| sal_Bool m_bIsRoot; // marks this storage as root storages that manages all oommits and reverts |
| sal_Bool m_bDirty; // ??? |
| sal_Bool m_bIsLinked; |
| sal_Bool m_bListCreated; |
| sal_uLong m_nFormat; |
| String m_aUserTypeName; |
| SvGlobalName m_aClassId; |
| |
| UCBStorageElementList_Impl m_aChildrenList; |
| |
| sal_Bool m_bRepairPackage; |
| Reference< XProgressHandler > m_xProgressHandler; |
| |
| UNOStorageHolderList* m_pUNOStorageHolderList; |
| UCBStorage_Impl( const ::ucbhelper::Content&, const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() ); |
| UCBStorage_Impl( const String&, StreamMode, UCBStorage*, sal_Bool, sal_Bool, sal_Bool = sal_False, Reference< XProgressHandler > = Reference< XProgressHandler >() ); |
| UCBStorage_Impl( SvStream&, UCBStorage*, sal_Bool ); |
| void Init(); |
| sal_Int16 Commit(); |
| sal_Bool Revert(); |
| sal_Bool Insert( ::ucbhelper::Content *pContent ); |
| UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect ); |
| UCBStorageStream_Impl* OpenStream( UCBStorageElement_Impl*, StreamMode, sal_Bool, const ByteString* pKey=0 ); |
| void SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& ); |
| void GetProps( sal_Int32&, Sequence < Sequence < PropertyValue > >& rSequence, const String& ); |
| sal_Int32 GetObjectCount(); |
| void ReadContent(); |
| void CreateContent(); |
| ::ucbhelper::Content* GetContent() |
| { if ( !m_pContent ) CreateContent(); return m_pContent; } |
| UCBStorageElementList_Impl& GetChildrenList() |
| { |
| long nError = m_nError; |
| ReadContent(); |
| if ( m_nMode & STREAM_WRITE ) |
| { |
| m_nError = nError; |
| if ( m_pAntiImpl ) |
| { |
| m_pAntiImpl->ResetError(); |
| m_pAntiImpl->SetError( nError ); |
| } |
| } |
| |
| return m_aChildrenList; |
| } |
| |
| void SetError( long nError ); |
| }; |
| |
| SV_DECL_IMPL_REF( UCBStorage_Impl ); |
| |
| // this struct contains all neccessary information on an element inside a UCBStorage |
| struct UCBStorageElement_Impl |
| { |
| String m_aName; // the actual URL relative to the root "folder" |
| String m_aOriginalName;// the original name in the content |
| sal_uLong m_nSize; |
| sal_Bool m_bIsFolder; // Only sal_True when it is a UCBStorage ! |
| sal_Bool m_bIsStorage; // Also sal_True when it is an OLEStorage ! |
| sal_Bool m_bIsRemoved; // element will be removed on commit |
| sal_Bool m_bIsInserted; // element will be removed on revert |
| UCBStorage_ImplRef m_xStorage; // reference to the "real" storage |
| UCBStorageStream_ImplRef m_xStream; // reference to the "real" stream |
| |
| UCBStorageElement_Impl( const ::rtl::OUString& rName, |
| sal_Bool bIsFolder = sal_False, sal_uLong nSize = 0 ) |
| : m_aName( rName ) |
| , m_aOriginalName( rName ) |
| , m_nSize( nSize ) |
| , m_bIsFolder( bIsFolder ) |
| , m_bIsStorage( bIsFolder ) |
| , m_bIsRemoved( sal_False ) |
| , m_bIsInserted( sal_False ) |
| { |
| } |
| |
| ::ucbhelper::Content* GetContent(); |
| sal_Bool IsModified(); |
| String GetContentType(); |
| void SetContentType( const String& ); |
| String GetOriginalContentType(); |
| sal_Bool IsLoaded() |
| { return m_xStream.Is() || m_xStorage.Is(); } |
| }; |
| |
| ::ucbhelper::Content* UCBStorageElement_Impl::GetContent() |
| { |
| if ( m_xStream.Is() ) |
| return m_xStream->m_pContent; |
| else if ( m_xStorage.Is() ) |
| return m_xStorage->GetContent(); |
| else |
| return NULL; |
| } |
| |
| String UCBStorageElement_Impl::GetContentType() |
| { |
| if ( m_xStream.Is() ) |
| return m_xStream->m_aContentType; |
| else if ( m_xStorage.Is() ) |
| return m_xStorage->m_aContentType; |
| else |
| { |
| DBG_ERROR("Element not loaded!"); |
| return String(); |
| } |
| } |
| |
| void UCBStorageElement_Impl::SetContentType( const String& rType ) |
| { |
| if ( m_xStream.Is() ) { |
| m_xStream->m_aContentType = m_xStream->m_aOriginalContentType = rType; |
| } |
| else if ( m_xStorage.Is() ) { |
| m_xStorage->m_aContentType = m_xStorage->m_aOriginalContentType = rType; |
| } |
| else { |
| DBG_ERROR("Element not loaded!"); |
| } |
| } |
| |
| String UCBStorageElement_Impl::GetOriginalContentType() |
| { |
| if ( m_xStream.Is() ) |
| return m_xStream->m_aOriginalContentType; |
| else if ( m_xStorage.Is() ) |
| return m_xStorage->m_aOriginalContentType; |
| else |
| return String(); |
| } |
| |
| sal_Bool UCBStorageElement_Impl::IsModified() |
| { |
| sal_Bool bModified = m_bIsRemoved || m_bIsInserted || m_aName != m_aOriginalName; |
| if ( bModified ) |
| { |
| if ( m_xStream.Is() ) |
| bModified = m_xStream->m_aContentType != m_xStream->m_aOriginalContentType; |
| else if ( m_xStorage.Is() ) |
| bModified = m_xStorage->m_aContentType != m_xStorage->m_aOriginalContentType; |
| } |
| |
| return bModified; |
| } |
| |
| UCBStorageStream_Impl::UCBStorageStream_Impl( const String& rName, StreamMode nMode, UCBStorageStream* pStream, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress ) |
| : m_pAntiImpl( pStream ) |
| , m_aURL( rName ) |
| , m_pContent( NULL ) |
| , m_pStream( NULL ) |
| , m_nRepresentMode( nonset ) |
| , m_nError( 0 ) |
| , m_nMode( nMode ) |
| , m_bSourceRead( !( nMode & STREAM_TRUNC ) ) |
| , m_bModified( sal_False ) |
| , m_bCommited( sal_False ) |
| , m_bDirect( bDirect ) |
| , m_bIsOLEStorage( sal_False ) |
| { |
| // name is last segment in URL |
| INetURLObject aObj( rName ); |
| m_aName = m_aOriginalName = aObj.GetLastName(); |
| try |
| { |
| // create the content |
| Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; |
| |
| ::rtl::OUString aTemp( rName ); |
| |
| if ( bRepair ) |
| { |
| xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(), |
| xProgress ); |
| aTemp += rtl::OUString::createFromAscii("?repairpackage"); |
| } |
| |
| m_pContent = new ::ucbhelper::Content( aTemp, xComEnv ); |
| |
| if ( pKey ) |
| { |
| m_aKey = *pKey; |
| |
| // stream is encrypted and should be decrypted (without setting the key we'll get the raw data) |
| sal_uInt8 aBuffer[RTL_DIGEST_LENGTH_SHA1]; |
| rtlDigestError nErr = rtl_digest_SHA1( pKey->GetBuffer(), pKey->Len(), aBuffer, RTL_DIGEST_LENGTH_SHA1 ); |
| if ( nErr == rtl_Digest_E_None ) |
| { |
| sal_uInt8* pBuffer = aBuffer; |
| ::com::sun::star::uno::Sequence < sal_Int8 > aSequ( (sal_Int8*) pBuffer, RTL_DIGEST_LENGTH_SHA1 ); |
| ::com::sun::star::uno::Any aAny; |
| aAny <<= aSequ; |
| m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii("EncryptionKey"), aAny ); |
| } |
| } |
| } |
| catch ( ContentCreationException& ) |
| { |
| // content could not be created |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| } |
| |
| UCBStorageStream_Impl::~UCBStorageStream_Impl() |
| { |
| if( m_rSource.is() ) |
| m_rSource = Reference< XInputStream >(); |
| |
| if( m_pStream ) |
| delete m_pStream; |
| |
| if ( m_aTempURL.Len() ) |
| ::utl::UCBContentHelper::Kill( m_aTempURL ); |
| |
| if( m_pContent ) |
| delete m_pContent; |
| } |
| |
| |
| Reference<XInputStream> UCBStorageStream_Impl::GetXInputStream() |
| { |
| Reference< XInputStream > aResult; |
| |
| if( m_pAntiImpl && m_nRepresentMode != nonset ) |
| { |
| DBG_ERROR( "Misuse of the XInputstream!" ); |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| } |
| else |
| { |
| if( m_bModified ) |
| { |
| // use wrapper around temporary stream |
| if( Init() ) |
| { |
| CopySourceToTemporary(); |
| |
| // owner transfer of stream to wrapper |
| aResult = new ::utl::OInputStreamWrapper( m_pStream, sal_True ); |
| m_pStream->Seek(0); |
| |
| if( aResult.is() ) |
| { |
| // temporary stream can not be used here any more |
| // and can not be opened untill wrapper is closed |
| // stream is deleted by wrapper after use |
| m_pStream = NULL; |
| m_nRepresentMode = xinputstream; |
| } |
| } |
| } |
| else |
| { |
| Free(); |
| |
| // open a new instance of XInputStream |
| try |
| { |
| aResult = m_pContent->openStream(); |
| } |
| catch ( Exception& ) |
| { |
| // usually means that stream could not be opened |
| } |
| |
| if( aResult.is() ) |
| m_nRepresentMode = xinputstream; |
| else |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| } |
| } |
| |
| return aResult; |
| } |
| |
| sal_Bool UCBStorageStream_Impl::Init() |
| { |
| if( m_nRepresentMode == xinputstream ) |
| { |
| DBG_ERROR( "XInputStream misuse!" ); |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| return sal_False; |
| } |
| |
| if( !m_pStream ) |
| { |
| // no temporary stream was created |
| // create one |
| |
| m_nRepresentMode = svstream; // can not be used as XInputStream |
| |
| if ( !m_aTempURL.Len() ) |
| m_aTempURL = ::utl::TempFile().GetURL(); |
| |
| m_pStream = ::utl::UcbStreamHelper::CreateStream( m_aTempURL, STREAM_STD_READWRITE, sal_True /* bFileExists */ ); |
| #if OSL_DEBUG_LEVEL > 1 |
| ++nOpenFiles; |
| #endif |
| |
| if( !m_pStream ) |
| { |
| DBG_ERROR( "Suspicious temporary stream creation!" ); |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| return sal_False; |
| } |
| |
| SetError( m_pStream->GetError() ); |
| } |
| |
| if( m_bSourceRead && !m_rSource.is() ) |
| { |
| // source file contain usefull information and is not opened |
| // open it from the point of noncopied data |
| |
| try |
| { |
| m_rSource = m_pContent->openStream(); |
| } |
| catch ( Exception& ) |
| { |
| // usually means that stream could not be opened |
| } |
| |
| if( m_rSource.is() ) |
| { |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| |
| try |
| { |
| m_rSource->skipBytes( m_pStream->Tell() ); |
| } |
| catch( BufferSizeExceededException& ) |
| { |
| // the temporary stream already contain all the data |
| m_bSourceRead = sal_False; |
| } |
| catch( Exception& ) |
| { |
| // something is really wrong |
| m_bSourceRead = sal_False; |
| DBG_ERROR( "Can not operate original stream!" ); |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| |
| m_pStream->Seek( 0 ); |
| } |
| else |
| { |
| // if the new file is edited than no source exist |
| m_bSourceRead = sal_False; |
| //SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| } |
| |
| DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" ); |
| |
| return sal_True; |
| } |
| |
| sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary() |
| { |
| // read source stream till the end and copy all the data to |
| // the current position of the temporary stream |
| |
| sal_uLong aResult = 0; |
| |
| if( m_bSourceRead ) |
| { |
| Sequence<sal_Int8> aData(32000); |
| |
| try |
| { |
| sal_uLong aReaded; |
| do |
| { |
| aReaded = m_rSource->readBytes( aData, 32000 ); |
| aResult += m_pStream->Write( aData.getArray(), aReaded ); |
| } while( aReaded == 32000 ); |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| catch( Exception & e ) |
| { |
| OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| #else |
| catch( Exception & ) |
| { |
| #endif |
| } |
| } |
| |
| m_bSourceRead = sal_False; |
| |
| return aResult; |
| |
| } |
| |
| sal_uLong UCBStorageStream_Impl::ReadSourceWriteTemporary( sal_uLong aLength ) |
| { |
| // read aLength bite from the source stream and copy them to the current |
| // position of the temporary stream |
| |
| sal_uLong aResult = 0; |
| |
| if( m_bSourceRead ) |
| { |
| Sequence<sal_Int8> aData(32000); |
| |
| try |
| { |
| |
| sal_uLong aReaded = 32000; |
| |
| for( sal_uLong pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 ) |
| { |
| sal_uLong aToCopy = min( aLength - pInd, 32000 ); |
| aReaded = m_rSource->readBytes( aData, aToCopy ); |
| aResult += m_pStream->Write( aData.getArray(), aReaded ); |
| } |
| |
| if( aResult < aLength ) |
| m_bSourceRead = sal_False; |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| catch( Exception & e ) |
| { |
| OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| #else |
| catch( Exception & ) |
| { |
| #endif |
| } |
| } |
| |
| return aResult; |
| } |
| |
| sal_uLong UCBStorageStream_Impl::CopySourceToTemporary() |
| { |
| // current position of the temporary stream is not changed |
| sal_uLong aResult = 0; |
| |
| if( m_bSourceRead ) |
| { |
| sal_uLong aPos = m_pStream->Tell(); |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| aResult = ReadSourceWriteTemporary(); |
| m_pStream->Seek( aPos ); |
| } |
| |
| return aResult; |
| |
| } |
| |
| #if 0 |
| sal_uLong UCBStorageStream_Impl::CopySourceToTemporary( sal_uLong aLength ) |
| { |
| // current position of the temporary stream is not changed |
| sal_uLong aResult = 0; |
| |
| if( m_bSourceRead ) |
| { |
| sal_uLong aPos = m_pStream->Tell(); |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| aResult = ReadSourceWriteTemporary( aLength ); |
| m_pStream->Seek( aPos ); |
| } |
| |
| return aResult; |
| |
| } |
| #endif |
| |
| // UCBStorageStream_Impl must have a SvStream interface, because it then can be used as underlying stream |
| // of an OLEStorage; so every write access caused by storage operations marks the UCBStorageStream as modified |
| sal_uLong UCBStorageStream_Impl::GetData( void* pData, sal_uLong nSize ) |
| { |
| sal_uLong aResult = 0; |
| |
| if( !Init() ) |
| return 0; |
| |
| |
| // read data that is in temporary stream |
| aResult = m_pStream->Read( pData, nSize ); |
| if( m_bSourceRead && aResult < nSize ) |
| { |
| // read the tail of the data from original stream |
| // copy this tail to the temporary stream |
| |
| sal_uLong aToRead = nSize - aResult; |
| pData = (void*)( (char*)pData + aResult ); |
| |
| try |
| { |
| Sequence<sal_Int8> aData( aToRead ); |
| sal_uLong aReaded = m_rSource->readBytes( aData, aToRead ); |
| aResult += m_pStream->Write( (void*)aData.getArray(), aReaded ); |
| memcpy( pData, aData.getArray(), aReaded ); |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| catch( Exception & e ) |
| { |
| OSL_ENSURE( sal_False, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| #else |
| catch( Exception & ) |
| { |
| #endif |
| } |
| |
| if( aResult < nSize ) |
| m_bSourceRead = sal_False; |
| } |
| |
| return aResult; |
| } |
| |
| sal_uLong UCBStorageStream_Impl::PutData( const void* pData, sal_uLong nSize ) |
| { |
| if ( !(m_nMode & STREAM_WRITE) ) |
| { |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| return 0; // ?mav? |
| } |
| |
| if( !nSize || !Init() ) |
| return 0; |
| |
| sal_uLong aResult = m_pStream->Write( pData, nSize ); |
| |
| m_bModified = aResult > 0; |
| |
| return aResult; |
| |
| } |
| |
| sal_uLong UCBStorageStream_Impl::SeekPos( sal_uLong nPos ) |
| { |
| if( !Init() ) |
| return 0; |
| |
| sal_uLong aResult; |
| |
| if( nPos == STREAM_SEEK_TO_END ) |
| { |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| ReadSourceWriteTemporary(); |
| aResult = m_pStream->Tell(); |
| } |
| else |
| { |
| // the problem is that even if nPos is larger the the length |
| // of the stream the stream pointer will be moved to this position |
| // so we have to check if temporary stream does not contain required position |
| |
| if( m_pStream->Tell() > nPos |
| || m_pStream->Seek( STREAM_SEEK_TO_END ) > nPos ) |
| { |
| // no copiing is required |
| aResult = m_pStream->Seek( nPos ); |
| } |
| else |
| { |
| // the temp stream pointer points to the end now |
| aResult = m_pStream->Tell(); |
| |
| if( aResult < nPos ) |
| { |
| if( m_bSourceRead ) |
| { |
| aResult += ReadSourceWriteTemporary( nPos - aResult ); |
| if( aResult < nPos ) |
| m_bSourceRead = sal_False; |
| |
| DBG_ASSERT( aResult == m_pStream->Tell(), "Error in stream arithmetic!\n" ); |
| } |
| |
| if( (m_nMode & STREAM_WRITE) && !m_bSourceRead && aResult < nPos ) |
| { |
| // it means that all the Source stream was copied already |
| // but the required position still was not reached |
| // for writable streams it should be done |
| m_pStream->SetStreamSize( nPos ); |
| aResult = m_pStream->Seek( STREAM_SEEK_TO_END ); |
| DBG_ASSERT( aResult == nPos, "Error in stream arithmetic!\n" ); |
| } |
| } |
| } |
| } |
| |
| return aResult; |
| } |
| |
| void UCBStorageStream_Impl::SetSize( sal_uLong nSize ) |
| { |
| if ( !(m_nMode & STREAM_WRITE) ) |
| { |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| return; |
| } |
| |
| if( !Init() ) |
| return; |
| |
| m_bModified = sal_True; |
| |
| if( m_bSourceRead ) |
| { |
| sal_uLong aPos = m_pStream->Tell(); |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| if( m_pStream->Tell() < nSize ) |
| ReadSourceWriteTemporary( nSize - m_pStream->Tell() ); |
| m_pStream->Seek( aPos ); |
| } |
| |
| m_pStream->SetStreamSize( nSize ); |
| m_bSourceRead = sal_False; |
| } |
| |
| void UCBStorageStream_Impl::FlushData() |
| { |
| if( m_pStream ) |
| { |
| CopySourceToTemporary(); |
| m_pStream->Flush(); |
| } |
| |
| m_bCommited = sal_True; |
| } |
| |
| void UCBStorageStream_Impl::SetError( sal_uInt32 nErr ) |
| { |
| if ( !m_nError ) |
| { |
| m_nError = nErr; |
| SvStream::SetError( nErr ); |
| if ( m_pAntiImpl ) m_pAntiImpl->SetError( nErr ); |
| } |
| } |
| |
| void UCBStorageStream_Impl::ResetError() |
| { |
| m_nError = 0; |
| SvStream::ResetError(); |
| if ( m_pAntiImpl ) |
| m_pAntiImpl->ResetError(); |
| } |
| |
| sal_uLong UCBStorageStream_Impl::GetSize() |
| { |
| if( !Init() ) |
| return 0; |
| |
| sal_uLong nPos = m_pStream->Tell(); |
| m_pStream->Seek( STREAM_SEEK_TO_END ); |
| ReadSourceWriteTemporary(); |
| sal_uLong nRet = m_pStream->Tell(); |
| m_pStream->Seek( nPos ); |
| |
| return nRet; |
| } |
| |
| BaseStorage* UCBStorageStream_Impl::CreateStorage() |
| { |
| // create an OLEStorage on a SvStream ( = this ) |
| // it gets the root attribute because otherwise it would probably not write before my root is commited |
| UCBStorageStream* pNewStorageStream = new UCBStorageStream( this ); |
| Storage *pStorage = new Storage( *pNewStorageStream, m_bDirect ); |
| |
| // GetError() call cleares error code for OLE storages, must be changed in future |
| long nTmpErr = pStorage->GetError(); |
| pStorage->SetError( nTmpErr ); |
| |
| m_bIsOLEStorage = !nTmpErr; |
| return static_cast< BaseStorage* > ( pStorage ); |
| } |
| |
| sal_Int16 UCBStorageStream_Impl::Commit() |
| { |
| // send stream to the original content |
| // the parent storage is responsible for the correct handling of deleted contents |
| if ( m_bCommited || m_bIsOLEStorage || m_bDirect ) |
| { |
| // modified streams with OLEStorages on it have autocommit; it is assumed that the OLEStorage |
| // was commited as well ( if not opened in direct mode ) |
| |
| if ( m_bModified ) |
| { |
| try |
| { |
| CopySourceToTemporary(); |
| |
| // release all stream handles |
| Free(); |
| |
| // the temporary file does not exist only for truncated streams |
| DBG_ASSERT( m_aTempURL.Len() || ( m_nMode & STREAM_TRUNC ), "No temporary file to read from!"); |
| if ( !m_aTempURL.Len() && !( m_nMode & STREAM_TRUNC ) ) |
| throw RuntimeException(); |
| |
| // create wrapper to stream that is only used while reading inside package component |
| Reference < XInputStream > xStream = new FileStreamWrapper_Impl( m_aTempURL ); |
| |
| Any aAny; |
| InsertCommandArgument aArg; |
| aArg.Data = xStream; |
| aArg.ReplaceExisting = sal_True; |
| aAny <<= aArg; |
| m_pContent->executeCommand( ::rtl::OUString::createFromAscii("insert"), aAny ); |
| |
| // wrapper now controls lifetime of temporary file |
| m_aTempURL.Erase(); |
| |
| INetURLObject aObj( m_aURL ); |
| aObj.SetName( m_aName ); |
| m_aURL = aObj.GetMainURL( INetURLObject::NO_DECODE ); |
| m_bModified = sal_False; |
| m_bSourceRead = sal_True; |
| } |
| catch ( CommandAbortedException& ) |
| { |
| // any command wasn't executed successfully - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( Exception& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| |
| m_bCommited = sal_False; |
| return COMMIT_RESULT_SUCCESS; |
| } |
| } |
| |
| return COMMIT_RESULT_NOTHING_TO_DO; |
| } |
| |
| sal_Bool UCBStorageStream_Impl::Revert() |
| { |
| // if an OLEStorage is created on this stream, no "revert" is neccessary because OLEStorages do nothing on "Revert" ! |
| if ( m_bCommited ) |
| { |
| DBG_ERROR("Revert while commit is in progress!" ); |
| return sal_False; // ??? |
| } |
| |
| Free(); |
| if ( m_aTempURL.Len() ) |
| { |
| ::utl::UCBContentHelper::Kill( m_aTempURL ); |
| m_aTempURL.Erase(); |
| } |
| |
| m_bSourceRead = sal_False; |
| try |
| { |
| m_rSource = m_pContent->openStream(); |
| if( m_rSource.is() ) |
| { |
| if ( m_pAntiImpl && ( m_nMode & STREAM_TRUNC ) ) |
| // stream is in use and should be truncated |
| m_bSourceRead = sal_False; |
| else |
| { |
| m_nMode &= ~STREAM_TRUNC; |
| m_bSourceRead = sal_True; |
| } |
| } |
| else |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| catch ( ContentCreationException& ) |
| { |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( RuntimeException& ) |
| { |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( Exception& ) |
| { |
| } |
| |
| m_bModified = sal_False; |
| m_aName = m_aOriginalName; |
| m_aContentType = m_aOriginalContentType; |
| return ( GetError() == ERRCODE_NONE ); |
| } |
| |
| sal_Bool UCBStorageStream_Impl::Clear() |
| { |
| sal_Bool bRet = ( m_pAntiImpl == NULL ); |
| DBG_ASSERT( bRet, "Removing used stream!" ); |
| if( bRet ) |
| { |
| Free(); |
| } |
| |
| return bRet; |
| } |
| |
| void UCBStorageStream_Impl::Free() |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| if ( m_pStream ) |
| { |
| if ( m_aTempURL.Len() ) |
| --nOpenFiles; |
| else |
| --nOpenStreams; |
| } |
| #endif |
| |
| m_nRepresentMode = nonset; |
| m_rSource = Reference< XInputStream >(); |
| DELETEZ( m_pStream ); |
| } |
| |
| void UCBStorageStream_Impl::PrepareCachedForReopen( StreamMode nMode ) |
| { |
| sal_Bool isWritable = (( m_nMode & STREAM_WRITE ) != 0 ); |
| if ( isWritable ) |
| { |
| // once stream was writable, never reset to readonly |
| nMode |= STREAM_WRITE; |
| } |
| |
| m_nMode = nMode; |
| Free(); |
| |
| if ( nMode & STREAM_TRUNC ) |
| { |
| m_bSourceRead = 0; // usually it should be 0 already but just in case... |
| |
| if ( m_aTempURL.Len() ) |
| { |
| ::utl::UCBContentHelper::Kill( m_aTempURL ); |
| m_aTempURL.Erase(); |
| } |
| } |
| } |
| |
| UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey ) |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorageStream ! |
| pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey ); |
| pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorageStream::UCBStorageStream( const String& rName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey, sal_Bool bRepair, Reference< XProgressHandler > xProgress ) |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorageStream ! |
| pImp = new UCBStorageStream_Impl( rName, nMode, this, bDirect, pKey, bRepair, xProgress ); |
| pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorageStream::UCBStorageStream( UCBStorageStream_Impl *pImpl ) |
| : pImp( pImpl ) |
| { |
| pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used |
| pImp->m_pAntiImpl = this; |
| SetError( pImp->m_nError ); |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorageStream::~UCBStorageStream() |
| { |
| if ( pImp->m_nMode & STREAM_WRITE ) |
| pImp->Flush(); |
| pImp->m_pAntiImpl = NULL; |
| pImp->Free(); |
| pImp->ReleaseRef(); |
| } |
| |
| sal_uLong UCBStorageStream::Read( void * pData, sal_uLong nSize ) |
| { |
| //return pImp->m_pStream->Read( pData, nSize ); |
| return pImp->GetData( pData, nSize ); |
| } |
| |
| sal_uLong UCBStorageStream::Write( const void* pData, sal_uLong nSize ) |
| { |
| /* |
| // mba: does occur in writer ! |
| if ( pImp->m_bCommited ) |
| { |
| DBG_ERROR("Writing while commit is in progress!" ); |
| return 0; |
| } |
| */ |
| // pImp->m_bModified = sal_True; |
| //return pImp->m_pStream->Write( pData, nSize ); |
| return pImp->PutData( pData, nSize ); |
| } |
| |
| sal_uLong UCBStorageStream::Seek( sal_uLong nPos ) |
| { |
| //return pImp->m_pStream->Seek( nPos ); |
| return pImp->Seek( nPos ); |
| } |
| |
| sal_uLong UCBStorageStream::Tell() |
| { |
| if( !pImp->Init() ) |
| return 0; |
| return pImp->m_pStream->Tell(); |
| } |
| |
| void UCBStorageStream::Flush() |
| { |
| // streams are never really transacted, so flush also means commit ! |
| Commit(); |
| } |
| |
| sal_Bool UCBStorageStream::SetSize( sal_uLong nNewSize ) |
| { |
| /* |
| if ( pImp->m_bCommited ) |
| { |
| DBG_ERROR("Changing stream size while commit is in progress!" ); |
| return sal_False; |
| } |
| */ |
| // pImp->m_bModified = sal_True; |
| //return pImp->m_pStream->SetStreamSize( nNewSize ); |
| pImp->SetSize( nNewSize ); |
| return !pImp->GetError(); |
| } |
| |
| sal_Bool UCBStorageStream::Validate( sal_Bool bWrite ) const |
| { |
| return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) ); |
| } |
| |
| sal_Bool UCBStorageStream::ValidateMode( StreamMode m ) const |
| { |
| // ??? |
| if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx |
| return sal_True; |
| sal_uInt16 nCurMode = 0xFFFF; |
| if( ( m & 3 ) == STREAM_READ ) |
| { |
| // only SHARE_DENYWRITE or SHARE_DENYALL allowed |
| if( ( ( m & STREAM_SHARE_DENYWRITE ) |
| && ( nCurMode & STREAM_SHARE_DENYWRITE ) ) |
| || ( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) ) |
| return sal_True; |
| } |
| else |
| { |
| // only SHARE_DENYALL allowed |
| // storages open in r/o mode are OK, since only |
| // the commit may fail |
| if( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) |
| return sal_True; |
| } |
| |
| return sal_True; |
| } |
| |
| const SvStream* UCBStorageStream::GetSvStream() const |
| { |
| if( !pImp->Init() ) |
| return NULL; |
| |
| pImp->CopySourceToTemporary(); |
| return pImp->m_pStream; // should not live longer then pImp!!! |
| } |
| |
| SvStream* UCBStorageStream::GetModifySvStream() |
| { |
| return (SvStream*)pImp; |
| } |
| |
| Reference< XInputStream > UCBStorageStream::GetXInputStream() const |
| { |
| return pImp->GetXInputStream(); |
| } |
| |
| sal_Bool UCBStorageStream::Equals( const BaseStorageStream& rStream ) const |
| { |
| // ??? |
| return ((BaseStorageStream*) this ) == &rStream; |
| } |
| |
| sal_Bool UCBStorageStream::Commit() |
| { |
| // mark this stream for sending it on root commit |
| pImp->FlushData(); |
| return sal_True; |
| } |
| |
| sal_Bool UCBStorageStream::Revert() |
| { |
| return pImp->Revert(); |
| } |
| |
| sal_Bool UCBStorageStream::CopyTo( BaseStorageStream* pDestStm ) |
| { |
| if( !pImp->Init() ) |
| return sal_False; |
| |
| UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm ); |
| if ( pStg ) |
| pStg->pImp->m_aContentType = pImp->m_aContentType; |
| |
| pDestStm->SetSize( 0 ); |
| Seek( STREAM_SEEK_TO_END ); |
| sal_Int32 n = Tell(); |
| if( n < 0 ) |
| return sal_False; |
| |
| if( pDestStm->SetSize( n ) && n ) |
| { |
| sal_uInt8* p = new sal_uInt8[ 4096 ]; |
| Seek( 0L ); |
| pDestStm->Seek( 0L ); |
| while( n ) |
| { |
| sal_uInt32 nn = n; |
| if( nn > 4096 ) |
| nn = 4096; |
| if( Read( p, nn ) != nn ) |
| break; |
| if( pDestStm->Write( p, nn ) != nn ) |
| break; |
| n -= nn; |
| } |
| |
| delete[] p; |
| } |
| |
| return sal_True; |
| } |
| |
| sal_Bool UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue ) |
| { |
| if ( rName.CompareToAscii("Title") == COMPARE_EQUAL ) |
| return sal_False; |
| |
| if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL ) |
| { |
| ::rtl::OUString aTmp; |
| rValue >>= aTmp; |
| pImp->m_aContentType = aTmp; |
| } |
| |
| try |
| { |
| if ( pImp->m_pContent ) |
| { |
| pImp->m_pContent->setPropertyValue( rName, rValue ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| |
| return sal_False; |
| } |
| |
| sal_Bool UCBStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue ) |
| { |
| try |
| { |
| if ( pImp->m_pContent ) |
| { |
| rValue = pImp->m_pContent->getPropertyValue( rName ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| |
| return sal_False; |
| } |
| |
| UCBStorage::UCBStorage( SvStream& rStrm, sal_Bool bDirect ) |
| { |
| String aURL = GetLinkedFile( rStrm ); |
| if ( aURL.Len() ) |
| { |
| StreamMode nMode = STREAM_READ; |
| if( rStrm.IsWritable() ) |
| nMode = STREAM_READ | STREAM_WRITE; |
| |
| ::ucbhelper::Content aContent( aURL, Reference < XCommandEnvironment >() ); |
| pImp = new UCBStorage_Impl( aContent, aURL, nMode, this, bDirect, sal_True ); |
| } |
| else |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorage ! |
| pImp = new UCBStorage_Impl( rStrm, this, bDirect ); |
| } |
| |
| pImp->AddRef(); |
| pImp->Init(); |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorage::UCBStorage( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot ) |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorage ! |
| pImp = new UCBStorage_Impl( rContent, rName, nMode, this, bDirect, bIsRoot ); |
| pImp->AddRef(); |
| pImp->Init(); |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler ) |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorage ! |
| pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, bIsRepair, xProgressHandler ); |
| pImp->AddRef(); |
| pImp->Init(); |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorage::UCBStorage( const String& rName, StreamMode nMode, sal_Bool bDirect, sal_Bool bIsRoot ) |
| { |
| // pImp must be initialized in the body, because otherwise the vtable of the stream is not initialized |
| // to class UCBStorage ! |
| pImp = new UCBStorage_Impl( rName, nMode, this, bDirect, bIsRoot, sal_False, Reference< XProgressHandler >() ); |
| pImp->AddRef(); |
| pImp->Init(); |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorage::UCBStorage( UCBStorage_Impl *pImpl ) |
| : pImp( pImpl ) |
| { |
| pImp->m_pAntiImpl = this; |
| SetError( pImp->m_nError ); |
| pImp->AddRef(); // use direct refcounting because in header file only a pointer should be used |
| StorageBase::m_nMode = pImp->m_nMode; |
| } |
| |
| UCBStorage::~UCBStorage() |
| { |
| if ( pImp->m_bIsRoot && pImp->m_bDirect && ( !pImp->m_pTempFile || pImp->m_pSource ) ) |
| // DirectMode is simulated with an AutoCommit |
| Commit(); |
| |
| pImp->m_pAntiImpl = NULL; |
| pImp->ReleaseRef(); |
| } |
| |
| UCBStorage_Impl::UCBStorage_Impl( const ::ucbhelper::Content& rContent, const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler ) |
| : m_pAntiImpl( pStorage ) |
| , m_pContent( new ::ucbhelper::Content( rContent ) ) |
| , m_pTempFile( NULL ) |
| , m_pSource( NULL ) |
| //, m_pStream( NULL ) |
| , m_nError( 0 ) |
| , m_nMode( nMode ) |
| , m_bModified( sal_False ) |
| , m_bCommited( sal_False ) |
| , m_bDirect( bDirect ) |
| , m_bIsRoot( bIsRoot ) |
| , m_bDirty( sal_False ) |
| , m_bIsLinked( sal_True ) |
| , m_bListCreated( sal_False ) |
| , m_nFormat( 0 ) |
| , m_aClassId( SvGlobalName() ) |
| , m_bRepairPackage( bIsRepair ) |
| , m_xProgressHandler( xProgressHandler ) |
| , m_pUNOStorageHolderList( NULL ) |
| |
| { |
| String aName( rName ); |
| if( !aName.Len() ) |
| { |
| // no name given = use temporary name! |
| DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" ); |
| m_pTempFile = new ::utl::TempFile; |
| m_pTempFile->EnableKillingFile( sal_True ); |
| m_aName = m_aOriginalName = aName = m_pTempFile->GetURL(); |
| } |
| |
| m_aURL = rName; |
| } |
| |
| UCBStorage_Impl::UCBStorage_Impl( const String& rName, StreamMode nMode, UCBStorage* pStorage, sal_Bool bDirect, sal_Bool bIsRoot, sal_Bool bIsRepair, Reference< XProgressHandler > xProgressHandler ) |
| : m_pAntiImpl( pStorage ) |
| , m_pContent( NULL ) |
| , m_pTempFile( NULL ) |
| , m_pSource( NULL ) |
| //, m_pStream( NULL ) |
| , m_nError( 0 ) |
| , m_nMode( nMode ) |
| , m_bModified( sal_False ) |
| , m_bCommited( sal_False ) |
| , m_bDirect( bDirect ) |
| , m_bIsRoot( bIsRoot ) |
| , m_bDirty( sal_False ) |
| , m_bIsLinked( sal_False ) |
| , m_bListCreated( sal_False ) |
| , m_nFormat( 0 ) |
| , m_aClassId( SvGlobalName() ) |
| , m_bRepairPackage( bIsRepair ) |
| , m_xProgressHandler( xProgressHandler ) |
| , m_pUNOStorageHolderList( NULL ) |
| { |
| String aName( rName ); |
| if( !aName.Len() ) |
| { |
| // no name given = use temporary name! |
| DBG_ASSERT( m_bIsRoot, "SubStorage must have a name!" ); |
| m_pTempFile = new ::utl::TempFile; |
| m_pTempFile->EnableKillingFile( sal_True ); |
| m_aName = m_aOriginalName = aName = m_pTempFile->GetURL(); |
| } |
| |
| if ( m_bIsRoot ) |
| { |
| // create the special package URL for the package content |
| String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://"); |
| aTemp += String(INetURLObject::encode( aName, INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL )); |
| m_aURL = aTemp; |
| |
| if ( m_nMode & STREAM_WRITE ) |
| { |
| // the root storage opens the package, so make sure that there is any |
| SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aName, STREAM_STD_READWRITE, m_pTempFile != 0 /* bFileExists */ ); |
| delete pStream; |
| } |
| } |
| else |
| { |
| // substorages are opened like streams: the URL is a "child URL" of the root package URL |
| m_aURL = rName; |
| if ( m_aURL.CompareToAscii( "vnd.sun.star.pkg://", 19 ) != 0 ) |
| m_bIsLinked = sal_True; |
| } |
| } |
| |
| UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, sal_Bool bDirect ) |
| : m_pAntiImpl( pStorage ) |
| , m_pContent( NULL ) |
| , m_pTempFile( new ::utl::TempFile ) |
| , m_pSource( &rStream ) |
| , m_nError( 0 ) |
| , m_bModified( sal_False ) |
| , m_bCommited( sal_False ) |
| , m_bDirect( bDirect ) |
| , m_bIsRoot( sal_True ) |
| , m_bDirty( sal_False ) |
| , m_bIsLinked( sal_False ) |
| , m_bListCreated( sal_False ) |
| , m_nFormat( 0 ) |
| , m_aClassId( SvGlobalName() ) |
| , m_bRepairPackage( sal_False ) |
| , m_pUNOStorageHolderList( NULL ) |
| { |
| // opening in direct mode is too fuzzy because the data is transferred to the stream in the Commit() call, |
| // which will be called in the storages' dtor |
| m_pTempFile->EnableKillingFile( sal_True ); |
| DBG_ASSERT( !bDirect, "Storage on a stream must not be opened in direct mode!" ); |
| |
| // UCBStorages work on a content, so a temporary file for a content must be created, even if the stream is only |
| // accessed readonly |
| // the root storage opens the package; create the special package URL for the package content |
| String aTemp = String::CreateFromAscii("vnd.sun.star.pkg://"); |
| aTemp += String(INetURLObject::encode( m_pTempFile->GetURL(), INetURLObject::PART_AUTHORITY, '%', INetURLObject::ENCODE_ALL )); |
| m_aURL = aTemp; |
| |
| // copy data into the temporary file |
| SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READWRITE, sal_True /* bFileExists */ ); |
| if ( pStream ) |
| { |
| rStream.Seek(0); |
| rStream >> *pStream; |
| pStream->Flush(); |
| DELETEZ( pStream ); |
| } |
| |
| // close stream and let content access the file |
| m_pSource->Seek(0); |
| |
| // check opening mode |
| m_nMode = STREAM_READ; |
| if( rStream.IsWritable() ) |
| m_nMode = STREAM_READ | STREAM_WRITE; |
| } |
| |
| void UCBStorage_Impl::Init() |
| { |
| // name is last segment in URL |
| INetURLObject aObj( m_aURL ); |
| if ( !m_aName.Len() ) |
| // if the name was not already set to a temp name |
| m_aName = m_aOriginalName = aObj.GetLastName(); |
| |
| // don't create the content for disk spanned files, avoid too early access to directory and/or manifest |
| if ( !m_pContent && !( m_nMode & STORAGE_DISKSPANNED_MODE ) ) |
| CreateContent(); |
| |
| if ( m_nMode & STORAGE_DISKSPANNED_MODE ) |
| { |
| // Hack! Avoid access to the manifest file until mediatype is not available in the first segment of a |
| // disk spanned file |
| m_aContentType = m_aOriginalContentType = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/vnd.sun.xml.impress") ); |
| } |
| else if ( m_pContent ) |
| { |
| if ( m_bIsLinked ) |
| { |
| if( m_bIsRoot ) |
| { |
| ReadContent(); |
| if ( m_nError == ERRCODE_NONE ) |
| { |
| // read the manifest.xml file |
| aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("META-INF") ) ); |
| aObj.Append( String( RTL_CONSTASCII_USTRINGPARAM("manifest.xml") ) ); |
| |
| // create input stream |
| SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aObj.GetMainURL( INetURLObject::NO_DECODE ), STREAM_STD_READ ); |
| // no stream means no manifest.xml |
| if ( pStream ) |
| { |
| if ( !pStream->GetError() ) |
| { |
| ::utl::OInputStreamWrapper* pHelper = new ::utl::OInputStreamWrapper( *pStream ); |
| com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > xInputStream( pHelper ); |
| |
| // create a manifest reader object that will read in the manifest from the stream |
| Reference < ::com::sun::star::packages::manifest::XManifestReader > xReader = |
| Reference< ::com::sun::star::packages::manifest::XManifestReader > |
| ( ::comphelper::getProcessServiceFactory()->createInstance( |
| ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestReader" )), UNO_QUERY) ; |
| Sequence < Sequence < PropertyValue > > aProps = xReader->readManifestSequence( xInputStream ); |
| |
| // cleanup |
| xReader = NULL; |
| xInputStream = NULL; |
| SetProps( aProps, String() ); |
| } |
| |
| delete pStream; |
| } |
| } |
| } |
| else |
| ReadContent(); |
| } |
| else |
| { |
| // get the manifest information from the package |
| try { |
| Any aAny = m_pContent->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ); |
| rtl::OUString aTmp; |
| if ( ( aAny >>= aTmp ) && aTmp.getLength() ) |
| m_aContentType = m_aOriginalContentType = aTmp; |
| } |
| catch( Exception& ) |
| { |
| DBG_ASSERT( sal_False, |
| "getPropertyValue has thrown an exception! Please let developers know the scenario!" ); |
| } |
| } |
| } |
| |
| if ( m_aContentType.Len() ) |
| { |
| // get the clipboard format using the content type |
| ::com::sun::star::datatransfer::DataFlavor aDataFlavor; |
| aDataFlavor.MimeType = m_aContentType; |
| m_nFormat = SotExchange::GetFormat( aDataFlavor ); |
| |
| // get the ClassId using the clipboard format ( internal table ) |
| m_aClassId = GetClassId_Impl( m_nFormat ); |
| |
| // get human presentable name using the clipboard format |
| SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor ); |
| m_aUserTypeName = aDataFlavor.HumanPresentableName; |
| |
| if( m_pContent && !m_bIsLinked && m_aClassId != SvGlobalName() ) |
| ReadContent(); |
| } |
| } |
| |
| void UCBStorage_Impl::CreateContent() |
| { |
| try |
| { |
| // create content; where to put StreamMode ?! ( already done when opening the file of the package ? ) |
| Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; |
| |
| ::rtl::OUString aTemp( m_aURL ); |
| |
| if ( m_bRepairPackage ) |
| { |
| xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(), |
| m_xProgressHandler ); |
| aTemp += rtl::OUString::createFromAscii("?repairpackage"); |
| } |
| |
| m_pContent = new ::ucbhelper::Content( aTemp, xComEnv ); |
| } |
| catch ( ContentCreationException& ) |
| { |
| // content could not be created |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| } |
| } |
| |
| void UCBStorage_Impl::ReadContent() |
| { |
| if ( m_bListCreated ) |
| return; |
| |
| m_bListCreated = sal_True; |
| |
| // create cursor for access to children |
| Sequence< ::rtl::OUString > aProps(4); |
| ::rtl::OUString* pProps = aProps.getArray(); |
| pProps[0] = ::rtl::OUString::createFromAscii( "Title" ); |
| pProps[1] = ::rtl::OUString::createFromAscii( "IsFolder" ); |
| pProps[2] = ::rtl::OUString::createFromAscii( "MediaType" ); |
| pProps[3] = ::rtl::OUString::createFromAscii( "Size" ); |
| ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS; |
| |
| try |
| { |
| GetContent(); |
| if ( !m_pContent ) |
| return; |
| |
| Reference< XResultSet > xResultSet = m_pContent->createCursor( aProps, eInclude ); |
| Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); |
| Reference< XRow > xRow( xResultSet, UNO_QUERY ); |
| if ( xResultSet.is() ) |
| { |
| while ( xResultSet->next() ) |
| { |
| // insert all into the children list |
| ::rtl::OUString aTitle( xRow->getString(1) ); |
| ::rtl::OUString aContentType; |
| if ( m_bIsLinked ) |
| { |
| // unpacked storages have to deal with the meta-inf folder by themselves |
| if( aTitle.equalsAscii("META-INF") ) |
| continue; |
| } |
| else |
| { |
| aContentType = xRow->getString(3); |
| } |
| |
| sal_Bool bIsFolder( xRow->getBoolean(2) ); |
| sal_Int64 nSize = xRow->getLong(4); |
| UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (sal_uLong) nSize ); |
| m_aChildrenList.Insert( pElement, LIST_APPEND ); |
| |
| sal_Bool bIsOfficeDocument = m_bIsLinked || ( m_aClassId != SvGlobalName() ); |
| if ( bIsFolder ) |
| { |
| if ( m_bIsLinked ) |
| OpenStorage( pElement, m_nMode, m_bDirect ); |
| if ( pElement->m_xStorage.Is() ) |
| pElement->m_xStorage->Init(); |
| } |
| else if ( bIsOfficeDocument ) |
| { |
| // streams can be external OLE objects, so they are now folders, but storages! |
| String aName( m_aURL ); |
| aName += '/'; |
| aName += String( xRow->getString(1) ); |
| |
| Reference< ::com::sun::star::ucb::XCommandEnvironment > xComEnv; |
| if ( m_bRepairPackage ) |
| { |
| xComEnv = new ::ucbhelper::CommandEnvironment( Reference< ::com::sun::star::task::XInteractionHandler >(), |
| m_xProgressHandler ); |
| aName += String( RTL_CONSTASCII_USTRINGPARAM( "?repairpackage" ) ); |
| } |
| |
| ::ucbhelper::Content aContent( aName, xComEnv ); |
| |
| ::rtl::OUString aMediaType; |
| Any aAny = aContent.getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ); |
| if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) ) |
| pElement->m_bIsStorage = sal_True; |
| else if ( !aMediaType.getLength() ) |
| { |
| // older files didn't have that special content type, so they must be detected |
| OpenStream( pElement, STREAM_STD_READ, m_bDirect ); |
| if ( Storage::IsStorageFile( pElement->m_xStream ) ) |
| pElement->m_bIsStorage = sal_True; |
| else |
| pElement->m_xStream->Free(); |
| } |
| } |
| } |
| } |
| } |
| catch ( InteractiveIOException& r ) |
| { |
| if ( r.Code != IOErrorCode_NOT_EXISTING ) |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( CommandAbortedException& ) |
| { |
| // any command wasn't executed successfully - not specified |
| if ( !( m_nMode & STREAM_WRITE ) ) |
| // if the folder was just inserted and not already commited, this is not an error! |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( ResultSetException& ) |
| { |
| // means that the package file is broken |
| SetError( ERRCODE_IO_BROKENPACKAGE ); |
| } |
| catch ( SQLException& ) |
| { |
| // means that the file can be broken |
| SetError( ERRCODE_IO_WRONGFORMAT ); |
| } |
| catch ( Exception& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| } |
| |
| void UCBStorage_Impl::SetError( long nError ) |
| { |
| if ( !m_nError ) |
| { |
| m_nError = nError; |
| if ( m_pAntiImpl ) m_pAntiImpl->SetError( nError ); |
| } |
| } |
| |
| sal_Int32 UCBStorage_Impl::GetObjectCount() |
| { |
| sal_Int32 nCount = m_aChildrenList.Count(); |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| while ( pElement ) |
| { |
| DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" ); |
| if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() ) |
| nCount += pElement->m_xStorage->GetObjectCount(); |
| pElement = m_aChildrenList.Next(); |
| } |
| |
| return nCount; |
| } |
| |
| ::rtl::OUString Find_Impl( const Sequence < Sequence < PropertyValue > >& rSequence, const ::rtl::OUString& rPath ) |
| { |
| sal_Bool bFound = sal_False; |
| for ( sal_Int32 nSeqs=0; nSeqs<rSequence.getLength(); nSeqs++ ) |
| { |
| const Sequence < PropertyValue >& rMyProps = rSequence[nSeqs]; |
| ::rtl::OUString aType; |
| |
| for ( sal_Int32 nProps=0; nProps<rMyProps.getLength(); nProps++ ) |
| { |
| const PropertyValue& rAny = rMyProps[nProps]; |
| if ( rAny.Name.equalsAscii("FullPath") ) |
| { |
| rtl::OUString aTmp; |
| if ( ( rAny.Value >>= aTmp ) && aTmp == rPath ) |
| bFound = sal_True; |
| if ( aType.getLength() ) |
| break; |
| } |
| else if ( rAny.Name.equalsAscii("MediaType") ) |
| { |
| if ( ( rAny.Value >>= aType ) && aType.getLength() && bFound ) |
| break; |
| } |
| } |
| |
| if ( bFound ) |
| return aType; |
| } |
| |
| return ::rtl::OUString(); |
| } |
| |
| void UCBStorage_Impl::SetProps( const Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath ) |
| { |
| String aPath( rPath ); |
| if ( !m_bIsRoot ) |
| aPath += m_aName; |
| aPath += '/'; |
| |
| m_aContentType = m_aOriginalContentType = Find_Impl( rSequence, aPath ); |
| |
| if ( m_bIsRoot ) |
| // the "FullPath" of a child always starts without '/' |
| aPath.Erase(); |
| |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| while ( pElement ) |
| { |
| DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" ); |
| if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() ) |
| pElement->m_xStorage->SetProps( rSequence, aPath ); |
| else |
| { |
| String aElementPath( aPath ); |
| aElementPath += pElement->m_aName; |
| pElement->SetContentType( Find_Impl( rSequence, aElementPath ) ); |
| } |
| |
| pElement = m_aChildrenList.Next(); |
| } |
| |
| if ( m_aContentType.Len() ) |
| { |
| // get the clipboard format using the content type |
| ::com::sun::star::datatransfer::DataFlavor aDataFlavor; |
| aDataFlavor.MimeType = m_aContentType; |
| m_nFormat = SotExchange::GetFormat( aDataFlavor ); |
| |
| // get the ClassId using the clipboard format ( internal table ) |
| m_aClassId = GetClassId_Impl( m_nFormat ); |
| |
| // get human presentable name using the clipboard format |
| SotExchange::GetFormatDataFlavor( m_nFormat, aDataFlavor ); |
| m_aUserTypeName = aDataFlavor.HumanPresentableName; |
| } |
| } |
| |
| void UCBStorage_Impl::GetProps( sal_Int32& nProps, Sequence < Sequence < PropertyValue > >& rSequence, const String& rPath ) |
| { |
| // first my own properties |
| Sequence < PropertyValue > aProps(2); |
| |
| // first property is the "FullPath" name |
| // it's '/' for the root storage and m_aName for each element, followed by a '/' if it's a folder |
| String aPath( rPath ); |
| if ( !m_bIsRoot ) |
| aPath += m_aName; |
| aPath += '/'; |
| aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType"); |
| aProps[0].Value <<= (::rtl::OUString ) m_aContentType; |
| aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath"); |
| aProps[1].Value <<= (::rtl::OUString ) aPath; |
| rSequence[ nProps++ ] = aProps; |
| |
| if ( m_bIsRoot ) |
| // the "FullPath" of a child always starts without '/' |
| aPath.Erase(); |
| |
| // now the properties of my elements |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| while ( pElement ) |
| { |
| DBG_ASSERT( !pElement->m_bIsFolder || pElement->m_xStorage.Is(), "Storage should be open!" ); |
| if ( pElement->m_bIsFolder && pElement->m_xStorage.Is() ) |
| // storages add there properties by themselves ( see above ) |
| pElement->m_xStorage->GetProps( nProps, rSequence, aPath ); |
| else |
| { |
| // properties of streams |
| String aElementPath( aPath ); |
| aElementPath += pElement->m_aName; |
| aProps[0].Name = ::rtl::OUString::createFromAscii("MediaType"); |
| aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType(); |
| aProps[1].Name = ::rtl::OUString::createFromAscii("FullPath"); |
| aProps[1].Value <<= (::rtl::OUString ) aElementPath; |
| rSequence[ nProps++ ] = aProps; |
| } |
| |
| pElement = m_aChildrenList.Next(); |
| } |
| } |
| |
| UCBStorage_Impl::~UCBStorage_Impl() |
| { |
| if ( m_pUNOStorageHolderList ) |
| { |
| for ( UNOStorageHolderList::iterator aIter = m_pUNOStorageHolderList->begin(); |
| aIter != m_pUNOStorageHolderList->end(); aIter++ ) |
| if ( *aIter ) |
| { |
| (*aIter)->InternalDispose(); |
| (*aIter)->release(); |
| (*aIter) = NULL; |
| } |
| |
| m_pUNOStorageHolderList->clear(); |
| DELETEZ( m_pUNOStorageHolderList ); |
| } |
| |
| // first delete elements! |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| while ( pElement ) |
| { |
| delete pElement; |
| pElement = m_aChildrenList.Next(); |
| } |
| |
| m_aChildrenList.Clear(); |
| delete m_pContent; |
| delete m_pTempFile; |
| } |
| |
| sal_Bool UCBStorage_Impl::Insert( ::ucbhelper::Content *pContent ) |
| { |
| // a new substorage is inserted into a UCBStorage ( given by the parameter pContent ) |
| // it must be inserted with a title and a type |
| sal_Bool bRet = sal_False; |
| |
| try |
| { |
| Sequence< ContentInfo > aInfo = pContent->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 < ::rtl::OUString > aNames(1); |
| ::rtl::OUString* pNames = aNames.getArray(); |
| pNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ); |
| Sequence < Any > aValues(1); |
| Any* pValues = aValues.getArray(); |
| pValues[0] = makeAny( ::rtl::OUString( m_aName ) ); |
| |
| Content aNewFolder; |
| if ( !pContent->insertNewContent( rCurr.Type, aNames, aValues, aNewFolder ) ) |
| continue; |
| |
| // remove old content, create an "empty" new one and initialize it with the new inserted |
| DELETEZ( m_pContent ); |
| m_pContent = new ::ucbhelper::Content( aNewFolder ); |
| bRet = sal_True; |
| } |
| } |
| } |
| catch ( CommandAbortedException& ) |
| { |
| // any command wasn't executed successfully - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| catch ( Exception& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| } |
| |
| return bRet; |
| } |
| |
| sal_Int16 UCBStorage_Impl::Commit() |
| { |
| // send all changes to the package |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| sal_Int16 nRet = COMMIT_RESULT_NOTHING_TO_DO; |
| |
| // there is nothing to do if the storage has been opened readonly or if it was opened in transacted mode and no |
| // commit command has been sent |
| if ( ( m_nMode & STREAM_WRITE ) && ( m_bCommited || m_bDirect ) ) |
| { |
| try |
| { |
| // all errors will be caught in the "catch" statement outside the loop |
| while ( pElement && nRet ) |
| { |
| ::ucbhelper::Content* pContent = pElement->GetContent(); |
| sal_Bool bDeleteContent = sal_False; |
| if ( !pContent && pElement->IsModified() ) |
| { |
| // if the element has never been opened, no content has been created until now |
| bDeleteContent = sal_True; // remember to delete it later |
| String aName( m_aURL ); |
| aName += '/'; |
| aName += pElement->m_aOriginalName; |
| pContent = new ::ucbhelper::Content( aName, Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); |
| } |
| |
| if ( pElement->m_bIsRemoved ) |
| { |
| // was it inserted, then removed (so there would be nothing to do!) |
| if ( !pElement->m_bIsInserted ) |
| { |
| // first remove all open stream handles |
| if( !pElement->m_xStream.Is() || pElement->m_xStream->Clear() ) |
| { |
| pContent->executeCommand( ::rtl::OUString::createFromAscii("delete"), makeAny( sal_Bool( sal_True ) ) ); |
| nRet = COMMIT_RESULT_SUCCESS; |
| } |
| else |
| // couldn't release stream because there are external references to it |
| nRet = COMMIT_RESULT_FAILURE; |
| } |
| } |
| else |
| { |
| sal_Int16 nLocalRet = COMMIT_RESULT_NOTHING_TO_DO; |
| if ( pElement->m_xStorage.Is() ) |
| { |
| // element is a storage |
| // do a commit in the following cases: |
| // - if storage is already inserted, and changed |
| // - storage is not in a package |
| // - it's a new storage, try to insert and commit if successful inserted |
| if ( !pElement->m_bIsInserted || m_bIsLinked || pElement->m_xStorage->Insert( m_pContent ) ) |
| { |
| nLocalRet = pElement->m_xStorage->Commit(); |
| pContent = pElement->GetContent(); |
| } |
| } |
| else if ( pElement->m_xStream.Is() ) |
| { |
| // element is a stream |
| nLocalRet = pElement->m_xStream->Commit(); |
| if ( pElement->m_xStream->m_bIsOLEStorage ) |
| { |
| // OLE storage should be stored encrytped, if the storage uses encryption |
| pElement->m_xStream->m_aContentType = String::CreateFromAscii("application/vnd.sun.star.oleobject"); |
| Any aValue; |
| aValue <<= (sal_Bool) sal_True; |
| pElement->m_xStream->m_pContent->setPropertyValue(String::CreateFromAscii("Encrypted"), aValue ); |
| } |
| |
| pContent = pElement->GetContent(); |
| } |
| |
| if ( pElement->m_aName != pElement->m_aOriginalName ) |
| { |
| // name ( title ) of the element was changed |
| nLocalRet = COMMIT_RESULT_SUCCESS; |
| Any aAny; |
| aAny <<= (rtl::OUString) pElement->m_aName; |
| pContent->setPropertyValue( ::rtl::OUString::createFromAscii("Title"), aAny ); |
| } |
| |
| if ( pElement->IsLoaded() && pElement->GetContentType() != pElement->GetOriginalContentType() ) |
| { |
| // mediatype of the element was changed |
| nLocalRet = COMMIT_RESULT_SUCCESS; |
| Any aAny; |
| aAny <<= (rtl::OUString) pElement->GetContentType(); |
| pContent->setPropertyValue( ::rtl::OUString::createFromAscii("MediaType"), aAny ); |
| } |
| |
| if ( nLocalRet != COMMIT_RESULT_NOTHING_TO_DO ) |
| nRet = nLocalRet; |
| } |
| |
| if ( bDeleteContent ) |
| // content was created inside the loop |
| delete pContent; |
| |
| if ( nRet == COMMIT_RESULT_FAILURE ) |
| break; |
| |
| pElement = m_aChildrenList.Next(); |
| } |
| } |
| catch ( ContentCreationException& ) |
| { |
| // content could not be created |
| SetError( ERRCODE_IO_NOTEXISTS ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( CommandAbortedException& ) |
| { |
| // any command wasn't executed successfully - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( RuntimeException& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( Exception& ) |
| { |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| |
| if ( m_bIsRoot && m_pContent ) |
| { |
| // the root storage must flush the root package content |
| if ( nRet == COMMIT_RESULT_SUCCESS ) |
| { |
| try |
| { |
| // commit the media type to the JAR file |
| // clipboard format and ClassId will be retrieved from the media type when the file is loaded again |
| Any aType; |
| aType <<= (rtl::OUString) m_aContentType; |
| m_pContent->setPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ), aType ); |
| |
| if ( m_bIsLinked ) |
| { |
| // write a manifest file |
| // first create a subfolder "META-inf" |
| Content aNewSubFolder; |
| sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, String::CreateFromAscii("META-INF"), aNewSubFolder ); |
| if ( bRet ) |
| { |
| // create a stream to write the manifest file - use a temp file |
| String aURL( aNewSubFolder.getURL() ); |
| ::utl::TempFile* pTempFile = new ::utl::TempFile( &aURL ); |
| |
| // get the stream from the temp file and create an output stream wrapper |
| SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE ); |
| ::utl::OOutputStreamWrapper* pHelper = new ::utl::OOutputStreamWrapper( *pStream ); |
| com::sun::star::uno::Reference < ::com::sun::star::io::XOutputStream > xOutputStream( pHelper ); |
| |
| // create a manifest writer object that will fill the stream |
| Reference < ::com::sun::star::packages::manifest::XManifestWriter > xWriter = |
| Reference< ::com::sun::star::packages::manifest::XManifestWriter > |
| ( ::comphelper::getProcessServiceFactory()->createInstance( |
| ::rtl::OUString::createFromAscii( "com.sun.star.packages.manifest.ManifestWriter" )), UNO_QUERY) ; |
| sal_Int32 nCount = GetObjectCount() + 1; |
| Sequence < Sequence < PropertyValue > > aProps( nCount ); |
| sal_Int32 nProps = 0; |
| GetProps( nProps, aProps, String() ); |
| xWriter->writeManifestSequence( xOutputStream, aProps ); |
| |
| // move the stream to its desired location |
| Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() ); |
| xWriter = NULL; |
| xOutputStream = NULL; |
| DELETEZ( pTempFile ); |
| aNewSubFolder.transferContent( aSource, InsertOperation_MOVE, ::rtl::OUString::createFromAscii("manifest.xml"), NameClash::OVERWRITE ); |
| } |
| } |
| else |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| fprintf ( stderr, "Files: %i\n", nOpenFiles ); |
| fprintf ( stderr, "Streams: %i\n", nOpenStreams ); |
| #endif |
| // force writing |
| Any aAny; |
| m_pContent->executeCommand( ::rtl::OUString::createFromAscii("flush"), aAny ); |
| if ( m_pSource != 0 ) |
| { |
| SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( m_pTempFile->GetURL(), STREAM_STD_READ ); |
| m_pSource->SetStreamSize(0); |
| // m_pSource->Seek(0); |
| *pStream >> *m_pSource; |
| DELETEZ( pStream ); |
| m_pSource->Seek(0); |
| } |
| } |
| } |
| catch ( CommandAbortedException& ) |
| { |
| // how to tell the content : forget all changes ?! |
| // or should we assume that the content does it by itself because he throwed an exception ?! |
| // any command wasn't executed successfully - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( RuntimeException& ) |
| { |
| // how to tell the content : forget all changes ?! |
| // or should we assume that the content does it by itself because he throwed an exception ?! |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( InteractiveIOException& r ) |
| { |
| if ( r.Code == IOErrorCode_ACCESS_DENIED || r.Code == IOErrorCode_LOCKING_VIOLATION ) |
| SetError( ERRCODE_IO_ACCESSDENIED ); |
| else if ( r.Code == IOErrorCode_NOT_EXISTING ) |
| SetError( ERRCODE_IO_NOTEXISTS ); |
| else if ( r.Code == IOErrorCode_CANT_READ ) |
| SetError( ERRCODE_IO_CANTREAD ); |
| else if ( r.Code == IOErrorCode_CANT_WRITE ) |
| SetError( ERRCODE_IO_CANTWRITE ); |
| else |
| SetError( ERRCODE_IO_GENERAL ); |
| |
| return COMMIT_RESULT_FAILURE; |
| } |
| catch ( Exception& ) |
| { |
| // how to tell the content : forget all changes ?! |
| // or should we assume that the content does it by itself because he throwed an exception ?! |
| // any other error - not specified |
| SetError( ERRCODE_IO_GENERAL ); |
| return COMMIT_RESULT_FAILURE; |
| } |
| } |
| else if ( nRet != COMMIT_RESULT_NOTHING_TO_DO ) |
| { |
| // how to tell the content : forget all changes ?! Should we ?! |
| SetError( ERRCODE_IO_GENERAL ); |
| return nRet; |
| } |
| |
| // after successfull root commit all elements names and types are adjusted and all removed elements |
| // are also removed from the lists |
| UCBStorageElement_Impl* pInnerElement = m_aChildrenList.First(); |
| sal_Bool bRet = sal_True; |
| while ( pInnerElement && bRet ) |
| { |
| UCBStorageElement_Impl* pNext = m_aChildrenList.Next(); |
| if ( pInnerElement->m_bIsRemoved ) |
| { |
| // is this correct use of our list class ?! |
| m_aChildrenList.Remove( pInnerElement ); |
| } |
| else |
| { |
| pInnerElement->m_aOriginalName = pInnerElement->m_aName; |
| pInnerElement->m_bIsInserted = sal_False; |
| } |
| |
| pInnerElement = pNext; |
| } |
| } |
| |
| m_bCommited = sal_False; |
| } |
| |
| return nRet; |
| } |
| |
| sal_Bool UCBStorage_Impl::Revert() |
| { |
| UCBStorageElement_Impl* pElement = m_aChildrenList.First(); |
| sal_Bool bRet = sal_True; |
| while ( pElement && bRet ) |
| { |
| pElement->m_bIsRemoved = sal_False; |
| if ( pElement->m_bIsInserted ) |
| { |
| m_aChildrenList.Remove( pElement ); // correct usage of list ??? |
| } |
| else |
| { |
| if ( pElement->m_xStream.Is() ) |
| { |
| pElement->m_xStream->m_bCommited = sal_False; |
| pElement->m_xStream->Revert(); |
| } |
| else if ( pElement->m_xStorage.Is() ) |
| { |
| pElement->m_xStorage->m_bCommited = sal_False; |
| pElement->m_xStorage->Revert(); |
| } |
| |
| pElement->m_aName = pElement->m_aOriginalName; |
| pElement->m_bIsRemoved = sal_False; |
| } |
| |
| pElement = m_aChildrenList.Next(); |
| } |
| |
| return bRet; |
| } |
| |
| const String& UCBStorage::GetName() const |
| { |
| return pImp->m_aName; // pImp->m_aURL ?! |
| } |
| |
| sal_Bool UCBStorage::IsRoot() const |
| { |
| return pImp->m_bIsRoot; |
| } |
| |
| void UCBStorage::SetDirty() |
| { |
| pImp->m_bDirty = sal_True; |
| } |
| |
| void UCBStorage::SetClass( const SvGlobalName & rClass, sal_uLong nOriginalClipFormat, const String & rUserTypeName ) |
| { |
| pImp->m_aClassId = rClass; |
| pImp->m_nFormat = nOriginalClipFormat; |
| pImp->m_aUserTypeName = rUserTypeName; |
| |
| // in UCB storages only the content type will be stored, all other information can be reconstructed |
| // ( see the UCBStorage_Impl::Init() method ) |
| ::com::sun::star::datatransfer::DataFlavor aDataFlavor; |
| SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor ); |
| pImp->m_aContentType = aDataFlavor.MimeType; |
| } |
| |
| void UCBStorage::SetClassId( const ClsId& rClsId ) |
| { |
| pImp->m_aClassId = SvGlobalName( (const CLSID&) rClsId ); |
| if ( pImp->m_aClassId == SvGlobalName() ) |
| return; |
| |
| // in OLE storages the clipboard format an the user name will be transferred when a storage is copied because both are |
| // stored in one the substreams |
| // UCB storages store the content type information as content type in the manifest file and so this information must be |
| // kept up to date, and also the other type information that is hold only at runtime because it can be reconstructed from |
| // the content type |
| pImp->m_nFormat = GetFormatId_Impl( pImp->m_aClassId ); |
| if ( pImp->m_nFormat ) |
| { |
| ::com::sun::star::datatransfer::DataFlavor aDataFlavor; |
| SotExchange::GetFormatDataFlavor( pImp->m_nFormat, aDataFlavor ); |
| pImp->m_aUserTypeName = aDataFlavor.HumanPresentableName; |
| pImp->m_aContentType = aDataFlavor.MimeType; |
| } |
| } |
| |
| const ClsId& UCBStorage::GetClassId() const |
| { |
| return ( const ClsId& ) pImp->m_aClassId.GetCLSID(); |
| } |
| |
| void UCBStorage::SetConvertClass( const SvGlobalName & /*rConvertClass*/, sal_uLong /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ ) |
| { |
| // ??? |
| } |
| |
| sal_Bool UCBStorage::ShouldConvert() |
| { |
| // ??? |
| return sal_False; |
| } |
| |
| SvGlobalName UCBStorage::GetClassName() |
| { |
| return pImp->m_aClassId; |
| } |
| |
| sal_uLong UCBStorage::GetFormat() |
| { |
| return pImp->m_nFormat; |
| } |
| |
| String UCBStorage::GetUserName() |
| { |
| DBG_ERROR("UserName is not implemented in UCB storages!" ); |
| return pImp->m_aUserTypeName; |
| } |
| |
| void UCBStorage::FillInfoList( SvStorageInfoList* pList ) const |
| { |
| // put information in childrenlist into StorageInfoList |
| UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First(); |
| while ( pElement ) |
| { |
| if ( !pElement->m_bIsRemoved ) |
| { |
| // problem: what about the size of a substorage ?! |
| sal_uLong nSize = pElement->m_nSize; |
| if ( pElement->m_xStream.Is() ) |
| nSize = pElement->m_xStream->GetSize(); |
| SvStorageInfo aInfo( pElement->m_aName, nSize, pElement->m_bIsStorage ); |
| pList->Append( aInfo ); |
| } |
| |
| pElement = pImp->m_aChildrenList.Next(); |
| } |
| } |
| |
| sal_Bool UCBStorage::CopyStorageElement_Impl( UCBStorageElement_Impl& rElement, BaseStorage* pDest, const String& rNew ) const |
| { |
| // insert stream or storage into the list or stream of the destination storage |
| // not into the content, this will be done on commit ! |
| // be aware of name changes ! |
| if ( !rElement.m_bIsStorage ) |
| { |
| // copy the streams data |
| // the destination stream must not be open |
| BaseStorageStream* pOtherStream = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ); |
| BaseStorageStream* pStream = NULL; |
| sal_Bool bDeleteStream = sal_False; |
| |
| // if stream is already open, it is allowed to copy it, so be aware of this |
| if ( rElement.m_xStream.Is() ) |
| pStream = rElement.m_xStream->m_pAntiImpl; |
| if ( !pStream ) |
| { |
| pStream = ( const_cast < UCBStorage* > (this) )->OpenStream( rElement.m_aName, STREAM_STD_READ, pImp->m_bDirect ); |
| bDeleteStream = sal_True; |
| } |
| |
| pStream->CopyTo( pOtherStream ); |
| SetError( pStream->GetError() ); |
| if( pOtherStream->GetError() ) |
| pDest->SetError( pOtherStream->GetError() ); |
| else |
| pOtherStream->Commit(); |
| |
| if ( bDeleteStream ) |
| delete pStream; |
| delete pOtherStream; |
| } |
| else |
| { |
| // copy the storage content |
| // the destination storage must not be open |
| BaseStorage* pStorage = NULL; |
| |
| // if stream is already open, it is allowed to copy it, so be aware of this |
| sal_Bool bDeleteStorage = sal_False; |
| if ( rElement.m_xStorage.Is() ) |
| pStorage = rElement.m_xStorage->m_pAntiImpl; |
| if ( !pStorage ) |
| { |
| pStorage = ( const_cast < UCBStorage* > (this) )->OpenStorage( rElement.m_aName, pImp->m_nMode, pImp->m_bDirect ); |
| bDeleteStorage = sal_True; |
| } |
| |
| UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest ); |
| UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage ); |
| |
| sal_Bool bOpenUCBStorage = pUCBDest && pUCBCopy; |
| BaseStorage* pOtherStorage = bOpenUCBStorage ? |
| pDest->OpenUCBStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ) : |
| pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pImp->m_bDirect ); |
| |
| // For UCB storages, the class id and the format id may differ, |
| // do passing the class id is not sufficient. |
| if( bOpenUCBStorage ) |
| pOtherStorage->SetClass( pStorage->GetClassName(), |
| pStorage->GetFormat(), |
| pUCBCopy->pImp->m_aUserTypeName ); |
| else |
| pOtherStorage->SetClassId( pStorage->GetClassId() ); |
| pStorage->CopyTo( pOtherStorage ); |
| SetError( pStorage->GetError() ); |
| if( pOtherStorage->GetError() ) |
| pDest->SetError( pOtherStorage->GetError() ); |
| else |
| pOtherStorage->Commit(); |
| |
| if ( bDeleteStorage ) |
| delete pStorage; |
| delete pOtherStorage; |
| } |
| |
| return sal_Bool( Good() && pDest->Good() ); |
| } |
| |
| UCBStorageElement_Impl* UCBStorage::FindElement_Impl( const String& rName ) const |
| { |
| DBG_ASSERT( rName.Len(), "Name is empty!" ); |
| UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First(); |
| while ( pElement ) |
| { |
| if ( pElement->m_aName == rName && !pElement->m_bIsRemoved ) |
| break; |
| pElement = pImp->m_aChildrenList.Next(); |
| } |
| |
| return pElement; |
| } |
| |
| sal_Bool UCBStorage::CopyTo( BaseStorage* pDestStg ) const |
| { |
| DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" ); |
| if ( pDestStg == ((BaseStorage*)this) ) |
| return sal_False; |
| |
| // perhaps it's also a problem if one storage is a parent of the other ?! |
| // or if not: could be optimized ?! |
| |
| // For UCB storages, the class id and the format id may differ, |
| // do passing the class id is not sufficient. |
| if( pDestStg->ISA( UCBStorage ) ) |
| pDestStg->SetClass( pImp->m_aClassId, pImp->m_nFormat, |
| pImp->m_aUserTypeName ); |
| else |
| pDestStg->SetClassId( GetClassId() ); |
| pDestStg->SetDirty(); |
| |
| sal_Bool bRet = sal_True; |
| UCBStorageElement_Impl* pElement = pImp->GetChildrenList().First(); |
| while ( pElement && bRet ) |
| { |
| if ( !pElement->m_bIsRemoved ) |
| bRet = CopyStorageElement_Impl( *pElement, pDestStg, pElement->m_aName ); |
| pElement = pImp->m_aChildrenList.Next(); |
| } |
| |
| if( !bRet ) |
| SetError( pDestStg->GetError() ); |
| return sal_Bool( Good() && pDestStg->Good() ); |
| } |
| |
| sal_Bool UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew ) |
| { |
| if( !rElemName.Len() ) |
| return sal_False; |
| |
| if ( pDest == ((BaseStorage*) this) ) |
| { |
| // can't double an element |
| return sal_False; |
| } |
| else |
| { |
| // for copying no optimization is usefull, because in every case the stream data must be copied |
| UCBStorageElement_Impl* pElement = FindElement_Impl( rElemName ); |
| if ( pElement ) |
| return CopyStorageElement_Impl( *pElement, pDest, rNew ); |
| else |
| { |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| return sal_False; |
| } |
| } |
| } |
| |
| sal_Bool UCBStorage::Commit() |
| { |
| // mark this storage for sending it on root commit |
| pImp->m_bCommited = sal_True; |
| if ( pImp->m_bIsRoot ) |
| // the root storage coordinates commiting by sending a Commit command to its content |
| return ( pImp->Commit() != COMMIT_RESULT_FAILURE ); |
| else |
| return sal_True; |
| } |
| |
| sal_Bool UCBStorage::Revert() |
| { |
| return pImp->Revert(); |
| } |
| |
| BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey ) |
| { |
| if( !rEleName.Len() ) |
| return NULL; |
| |
| // try to find the storage element |
| UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| if ( !pElement ) |
| { |
| // element does not exist, check if creation is allowed |
| if( ( nMode & STREAM_NOCREATE ) ) |
| { |
| SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND ); |
| String aName( pImp->m_aURL ); |
| aName += '/'; |
| aName += rEleName; |
| UCBStorageStream* pStream = new UCBStorageStream( aName, nMode, bDirect, pKey, pImp->m_bRepairPackage, pImp->m_xProgressHandler ); |
| pStream->SetError( GetError() ); |
| pStream->pImp->m_aName = rEleName; |
| return pStream; |
| } |
| else |
| { |
| // create a new UCBStorageElement and insert it into the list |
| pElement = new UCBStorageElement_Impl( rEleName ); |
| pElement->m_bIsInserted = sal_True; |
| pImp->m_aChildrenList.Insert( pElement, LIST_APPEND ); |
| } |
| } |
| |
| if ( pElement && !pElement->m_bIsFolder ) |
| { |
| // check if stream is already created |
| if ( pElement->m_xStream.Is() ) |
| { |
| // stream has already been created; if it has no external reference, it may be opened another time |
| if ( pElement->m_xStream->m_pAntiImpl ) |
| { |
| DBG_ERROR("Stream is already open!" ); |
| SetError( SVSTREAM_ACCESS_DENIED ); // ??? |
| return NULL; |
| } |
| else |
| { |
| // check if stream is opened with the same keyword as before |
| // if not, generate a new stream because it could be encrypted vs. decrypted! |
| ByteString aKey; |
| if ( pKey ) |
| aKey = *pKey; |
| if ( pElement->m_xStream->m_aKey == aKey ) |
| { |
| pElement->m_xStream->PrepareCachedForReopen( nMode ); |
| |
| // DBG_ASSERT( bDirect == pElement->m_xStream->m_bDirect, "Wrong DirectMode!" ); |
| return new UCBStorageStream( pElement->m_xStream ); |
| } |
| } |
| } |
| |
| // stream is opened the first time |
| pImp->OpenStream( pElement, nMode, bDirect, pKey ); |
| |
| // if name has been changed before creating the stream: set name! |
| pElement->m_xStream->m_aName = rEleName; |
| return new UCBStorageStream( pElement->m_xStream ); |
| } |
| |
| return NULL; |
| } |
| |
| UCBStorageStream_Impl* UCBStorage_Impl::OpenStream( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect, const ByteString* pKey ) |
| { |
| String aName( m_aURL ); |
| aName += '/'; |
| aName += pElement->m_aOriginalName; |
| pElement->m_xStream = new UCBStorageStream_Impl( aName, nMode, NULL, bDirect, pKey, m_bRepairPackage, m_xProgressHandler ); |
| return pElement->m_xStream; |
| } |
| |
| BaseStorage* UCBStorage::OpenUCBStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect ) |
| { |
| if( !rEleName.Len() ) |
| return NULL; |
| |
| return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True ); |
| } |
| |
| BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect ) |
| { |
| if( !rEleName.Len() ) |
| return NULL; |
| |
| return OpenStorage_Impl( rEleName, nMode, bDirect, sal_False ); |
| } |
| |
| BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, sal_Bool bDirect ) |
| { |
| if( !rEleName.Len() ) |
| return NULL; |
| |
| return OpenStorage_Impl( rEleName, nMode, bDirect, sal_True ); |
| } |
| |
| BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, sal_Bool bDirect, sal_Bool bForceUCBStorage ) |
| { |
| // try to find the storage element |
| UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| if ( !pElement ) |
| { |
| // element does not exist, check if creation is allowed |
| if( ( nMode & STREAM_NOCREATE ) ) |
| { |
| SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND ); |
| String aName( pImp->m_aURL ); |
| aName += '/'; |
| aName += rEleName; // ??? |
| UCBStorage *pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler ); |
| pStorage->pImp->m_bIsRoot = sal_False; |
| pStorage->pImp->m_bListCreated = sal_True; // the storage is pretty new, nothing to read |
| pStorage->SetError( GetError() ); |
| return pStorage; |
| } |
| |
| // create a new UCBStorageElement and insert it into the list |
| // problem: perhaps an OLEStorage should be created ?! |
| // Because nothing is known about the element that should be created, an external parameter is needed ! |
| pElement = new UCBStorageElement_Impl( rEleName ); |
| pElement->m_bIsInserted = sal_True; |
| pImp->m_aChildrenList.Insert( pElement, LIST_APPEND ); |
| } |
| |
| if ( !pElement->m_bIsFolder && ( pElement->m_bIsStorage || !bForceUCBStorage ) ) |
| { |
| // create OLE storages on a stream ( see ctor of SotStorage ) |
| // Such a storage will be created on a UCBStorageStream; it will write into the stream |
| // if it is opened in direct mode or when it is committed. In this case the stream will be |
| // modified and then it MUST be treated as commited. |
| if ( !pElement->m_xStream.Is() ) |
| { |
| BaseStorageStream* pStr = OpenStream( rEleName, nMode, bDirect ); |
| UCBStorageStream* pStream = PTR_CAST( UCBStorageStream, pStr ); |
| if ( !pStream ) |
| { |
| SetError( ( nMode & STREAM_WRITE ) ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND ); |
| return NULL; |
| } |
| |
| pElement->m_xStream = pStream->pImp; |
| delete pStream; |
| } |
| |
| pElement->m_xStream->PrepareCachedForReopen( nMode ); |
| pElement->m_xStream->Init(); |
| |
| pElement->m_bIsStorage = sal_True; |
| return pElement->m_xStream->CreateStorage(); // can only be created in transacted mode |
| } |
| else if ( pElement->m_xStorage.Is() ) |
| { |
| // storage has already been opened; if it has no external reference, it may be opened another time |
| if ( pElement->m_xStorage->m_pAntiImpl ) |
| { |
| DBG_ERROR("Storage is already open!" ); |
| SetError( SVSTREAM_ACCESS_DENIED ); // ??? |
| } |
| else |
| { |
| sal_Bool bIsWritable = (( pElement->m_xStorage->m_nMode & STREAM_WRITE ) != 0); |
| if ( !bIsWritable && (( nMode & STREAM_WRITE ) != 0 )) |
| { |
| String aName( pImp->m_aURL ); |
| aName += '/'; |
| aName += pElement->m_aOriginalName; |
| UCBStorage* pStorage = new UCBStorage( aName, nMode, bDirect, sal_False, pImp->m_bRepairPackage, pImp->m_xProgressHandler ); |
| pElement->m_xStorage = pStorage->pImp; |
| return pStorage; |
| } |
| else |
| { |
| // DBG_ASSERT( bDirect == pElement->m_xStorage->m_bDirect, "Wrong DirectMode!" ); |
| return new UCBStorage( pElement->m_xStorage ); |
| } |
| } |
| } |
| else if ( !pElement->m_xStream.Is() ) |
| { |
| // storage is opened the first time |
| sal_Bool bIsWritable = (( pImp->m_nMode & STREAM_WRITE ) != 0 ); |
| if ( pImp->m_bIsLinked && pImp->m_bIsRoot && bIsWritable ) |
| { |
| // make sure that the root storage object has been created before substorages will be created |
| INetURLObject aFolderObj( pImp->m_aURL ); |
| String aName = aFolderObj.GetName(); |
| aFolderObj.removeSegment(); |
| |
| Content aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ), Reference < XCommandEnvironment >() ); |
| pImp->m_pContent = new Content; |
| sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, pImp->m_aName, *pImp->m_pContent ); |
| if ( !bRet ) |
| { |
| SetError( SVSTREAM_CANNOT_MAKE ); |
| return NULL; |
| } |
| } |
| |
| UCBStorage_Impl* pStor = pImp->OpenStorage( pElement, nMode, bDirect ); |
| if ( pStor ) |
| { |
| if ( pElement->m_bIsInserted ) |
| pStor->m_bListCreated = sal_True; // the storage is pretty new, nothing to read |
| |
| return new UCBStorage( pStor ); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| UCBStorage_Impl* UCBStorage_Impl::OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, sal_Bool bDirect ) |
| { |
| UCBStorage_Impl* pRet = NULL; |
| String aName( m_aURL ); |
| aName += '/'; |
| aName += pElement->m_aOriginalName; // ??? |
| |
| pElement->m_bIsStorage = pElement->m_bIsFolder = sal_True; |
| |
| if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) ) |
| { |
| Content aNewFolder; |
| sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder ); |
| if ( bRet ) |
| pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler ); |
| } |
| else |
| { |
| pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, sal_False, m_bRepairPackage, m_xProgressHandler ); |
| } |
| |
| if ( pRet ) |
| { |
| pRet->m_bIsLinked = m_bIsLinked; |
| pRet->m_bIsRoot = sal_False; |
| |
| // if name has been changed before creating the stream: set name! |
| pRet->m_aName = pElement->m_aOriginalName; |
| pElement->m_xStorage = pRet; |
| } |
| |
| if ( pRet ) |
| pRet->Init(); |
| |
| return pRet; |
| } |
| |
| sal_Bool UCBStorage::IsStorage( const String& rEleName ) const |
| { |
| if( !rEleName.Len() ) |
| return sal_False; |
| |
| const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| return ( pElement && pElement->m_bIsStorage ); |
| } |
| |
| sal_Bool UCBStorage::IsStream( const String& rEleName ) const |
| { |
| if( !rEleName.Len() ) |
| return sal_False; |
| |
| const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| return ( pElement && !pElement->m_bIsStorage ); |
| } |
| |
| sal_Bool UCBStorage::IsContained( const String & rEleName ) const |
| { |
| if( !rEleName.Len() ) |
| return sal_False; |
| const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| return ( pElement != NULL ); |
| } |
| |
| sal_Bool UCBStorage::Remove( const String& rEleName ) |
| { |
| if( !rEleName.Len() ) |
| return sal_False; |
| |
| UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| if ( pElement ) |
| { |
| pElement->m_bIsRemoved = sal_True; |
| } |
| else |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| |
| return ( pElement != NULL ); |
| } |
| |
| sal_Bool UCBStorage::Rename( const String& rEleName, const String& rNewName ) |
| { |
| if( !rEleName.Len()|| !rNewName.Len() ) |
| return sal_False; |
| |
| UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName ); |
| if ( pAlreadyExisting ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; // can't change to a name that is already used |
| } |
| |
| UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName ); |
| if ( pElement ) |
| { |
| pElement->m_aName = rNewName; |
| } |
| else |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| |
| return pElement != NULL; |
| } |
| |
| sal_Bool UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName ) |
| { |
| if( !rEleName.Len() || !rNewName.Len() ) |
| return sal_False; |
| |
| if ( pNewSt == ((BaseStorage*) this) && !FindElement_Impl( rNewName ) ) |
| { |
| return Rename( rEleName, rNewName ); |
| } |
| else |
| { |
| /* |
| if ( PTR_CAST( UCBStorage, pNewSt ) ) |
| { |
| // because the element is moved, not copied, a special optimization is possible : |
| // first copy the UCBStorageElement; flag old element as "Removed" and new as "Inserted", |
| // clear original name/type of the new element |
| // if moved element is open: copy content, but change absolute URL ( and those of all children of the element! ), |
| // clear original name/type of new content, keep the old original stream/storage, but forget its working streams, |
| // close original UCBContent and original stream, only the TempFile and its stream may remain unchanged, but now |
| // belong to the new content |
| // if original and editable stream are identical ( readonly element ), it has to be copied to the editable |
| // stream of the destination object |
| // Not implemented at the moment ( risky?! ), perhaps later |
| } |
| */ |
| // MoveTo is done by first copying to the new destination and then removing the old element |
| sal_Bool bRet = CopyTo( rEleName, pNewSt, rNewName ); |
| if ( bRet ) |
| bRet = Remove( rEleName ); |
| return bRet; |
| } |
| } |
| |
| sal_Bool UCBStorage::ValidateFAT() |
| { |
| // ??? |
| return sal_True; |
| } |
| |
| sal_Bool UCBStorage::Validate( sal_Bool bWrite ) const |
| { |
| // ??? |
| return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) ); |
| } |
| |
| sal_Bool UCBStorage::ValidateMode( StreamMode m ) const |
| { |
| // ??? |
| if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx |
| return sal_True; |
| sal_uInt16 nCurMode = 0xFFFF; |
| if( ( m & 3 ) == STREAM_READ ) |
| { |
| // only SHARE_DENYWRITE or SHARE_DENYALL allowed |
| if( ( ( m & STREAM_SHARE_DENYWRITE ) |
| && ( nCurMode & STREAM_SHARE_DENYWRITE ) ) |
| || ( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) ) |
| return sal_True; |
| } |
| else |
| { |
| // only SHARE_DENYALL allowed |
| // storages open in r/o mode are OK, since only |
| // the commit may fail |
| if( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) |
| return sal_True; |
| } |
| |
| return sal_True; |
| } |
| |
| const SvStream* UCBStorage::GetSvStream() const |
| { |
| // this would cause a complete download of the file |
| // as it looks, this method is NOT used inside of SOT, only exported by class SotStorage - but for what ??? |
| return pImp->m_pSource; |
| } |
| |
| sal_Bool UCBStorage::Equals( const BaseStorage& rStorage ) const |
| { |
| // ??? |
| return ((BaseStorage*)this) == &rStorage; |
| } |
| |
| sal_Bool UCBStorage::IsStorageFile( const String& rFileName ) |
| { |
| String aFileURL = rFileName; |
| INetURLObject aObj( aFileURL ); |
| if ( aObj.GetProtocol() == INET_PROT_NOT_VALID ) |
| { |
| ::utl::LocalFileHelper::ConvertPhysicalNameToURL( rFileName, aFileURL ); |
| aObj.SetURL( aFileURL ); |
| aFileURL = aObj.GetMainURL( INetURLObject::NO_DECODE ); |
| } |
| |
| SvStream * pStm = ::utl::UcbStreamHelper::CreateStream( aFileURL, STREAM_STD_READ ); |
| sal_Bool bRet = UCBStorage::IsStorageFile( pStm ); |
| delete pStm; |
| return bRet; |
| } |
| |
| sal_Bool UCBStorage::IsStorageFile( SvStream* pFile ) |
| { |
| if ( !pFile ) |
| return sal_False; |
| |
| sal_uLong nPos = pFile->Tell(); |
| pFile->Seek( STREAM_SEEK_TO_END ); |
| if ( pFile->Tell() < 4 ) |
| return sal_False; |
| |
| pFile->Seek(0); |
| sal_uInt32 nBytes; |
| *pFile >> nBytes; |
| |
| // search for the magic bytes |
| sal_Bool bRet = ( nBytes == 0x04034b50 ); |
| if ( !bRet ) |
| { |
| // disk spanned file have an additional header in front of the usual one |
| bRet = ( nBytes == 0x08074b50 ); |
| if ( bRet ) |
| { |
| *pFile >> nBytes; |
| bRet = ( nBytes == 0x04034b50 ); |
| } |
| } |
| |
| pFile->Seek( nPos ); |
| return bRet; |
| } |
| |
| sal_Bool UCBStorage::IsDiskSpannedFile( SvStream* pFile ) |
| { |
| if ( !pFile ) |
| return sal_False; |
| |
| sal_uLong nPos = pFile->Tell(); |
| pFile->Seek( STREAM_SEEK_TO_END ); |
| if ( !pFile->Tell() ) |
| return sal_False; |
| |
| pFile->Seek(0); |
| sal_uInt32 nBytes; |
| *pFile >> nBytes; |
| |
| // disk spanned file have an additional header in front of the usual one |
| sal_Bool bRet = ( nBytes == 0x08074b50 ); |
| if ( bRet ) |
| { |
| *pFile >> nBytes; |
| bRet = ( nBytes == 0x04034b50 ); |
| } |
| |
| pFile->Seek( nPos ); |
| return bRet; |
| } |
| |
| String UCBStorage::GetLinkedFile( SvStream &rStream ) |
| { |
| String aString; |
| sal_uLong nPos = rStream.Tell(); |
| rStream.Seek( STREAM_SEEK_TO_END ); |
| if ( !rStream.Tell() ) |
| return aString; |
| |
| rStream.Seek(0); |
| sal_uInt32 nBytes; |
| rStream >> nBytes; |
| if( nBytes == 0x04034b50 ) |
| { |
| ByteString aTmp; |
| rStream.ReadByteString( aTmp ); |
| if ( aTmp.CompareTo( "ContentURL=", 11 ) == COMPARE_EQUAL ) |
| { |
| aTmp.Erase( 0, 11 ); |
| aString = String( aTmp, RTL_TEXTENCODING_UTF8 ); |
| } |
| } |
| |
| rStream.Seek( nPos ); |
| return aString; |
| } |
| |
| String UCBStorage::CreateLinkFile( const String& rName ) |
| { |
| // create a stream to write the link file - use a temp file, because it may be no file content |
| INetURLObject aFolderObj( rName ); |
| String aName = aFolderObj.GetName(); |
| aFolderObj.removeSegment(); |
| String aFolderURL( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ); |
| ::utl::TempFile* pTempFile = new ::utl::TempFile( &aFolderURL ); |
| |
| // get the stream from the temp file |
| SvStream* pStream = pTempFile->GetStream( STREAM_STD_READWRITE | STREAM_TRUNC ); |
| |
| // write header |
| *pStream << ( sal_uInt32 ) 0x04034b50; |
| |
| // assemble a new folder name in the destination folder |
| INetURLObject aObj( rName ); |
| String aTmpName = aObj.GetName(); |
| String aTitle = String::CreateFromAscii( "content." ); |
| aTitle += aTmpName; |
| |
| // create a folder and store its URL |
| Content aFolder( aFolderURL, Reference < XCommandEnvironment >() ); |
| Content aNewFolder; |
| sal_Bool bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTitle, aNewFolder ); |
| if ( !bRet ) |
| { |
| aFolderObj.insertName( aTitle ); |
| if ( ::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) ) |
| { |
| // Hack, because already existing files give the same CommandAbortedException as any other error ! |
| // append a number until the name can be used for a new folder |
| aTitle += '.'; |
| for ( sal_Int32 i=0; !bRet; i++ ) |
| { |
| String aTmp( aTitle ); |
| aTmp += String::CreateFromInt32( i ); |
| bRet = ::utl::UCBContentHelper::MakeFolder( aFolder, aTmp, aNewFolder ); |
| if ( bRet ) |
| aTitle = aTmp; |
| else |
| { |
| aFolderObj.SetName( aTmp ); |
| if ( !::utl::UCBContentHelper::Exists( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ) ) |
| // Hack, because already existing files give the same CommandAbortedException as any other error ! |
| break; |
| } |
| } |
| } |
| } |
| |
| if ( bRet ) |
| { |
| // get the URL |
| aObj.SetName( aTitle ); |
| String aURL = aObj.GetMainURL( INetURLObject::NO_DECODE ); |
| |
| // store it as key/value pair |
| String aLink = String::CreateFromAscii("ContentURL="); |
| aLink += aURL; |
| pStream->WriteByteString( aLink, RTL_TEXTENCODING_UTF8 ); |
| pStream->Flush(); |
| |
| // move the stream to its desired location |
| Content aSource( pTempFile->GetURL(), Reference < XCommandEnvironment >() ); |
| DELETEZ( pTempFile ); |
| aFolder.transferContent( aSource, InsertOperation_MOVE, aName, NameClash::OVERWRITE ); |
| return aURL; |
| } |
| |
| pTempFile->EnableKillingFile( sal_True ); |
| delete pTempFile; |
| return String(); |
| } |
| |
| sal_Bool UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue ) |
| { |
| if ( rName.CompareToAscii("Title") == COMPARE_EQUAL ) |
| return sal_False; |
| |
| if ( rName.CompareToAscii("MediaType") == COMPARE_EQUAL ) |
| { |
| ::rtl::OUString aTmp; |
| rValue >>= aTmp; |
| pImp->m_aContentType = aTmp; |
| } |
| |
| try |
| { |
| if ( pImp->GetContent() ) |
| { |
| pImp->m_pContent->setPropertyValue( rName, rValue ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| |
| return sal_False; |
| } |
| |
| sal_Bool UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue ) |
| { |
| try |
| { |
| if ( pImp->GetContent() ) |
| { |
| rValue = pImp->m_pContent->getPropertyValue( rName ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| |
| return sal_False; |
| } |
| |
| sal_Bool UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue ) |
| { |
| UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName ); |
| if ( !pEle ) |
| return sal_False; |
| |
| if ( !pEle->m_bIsFolder ) |
| { |
| if ( !pEle->m_xStream.Is() ) |
| pImp->OpenStream( pEle, pImp->m_nMode, pImp->m_bDirect ); |
| if ( pEle->m_xStream->m_nError ) |
| { |
| pEle->m_xStream.Clear(); |
| return sal_False; |
| } |
| |
| try |
| { |
| if ( pEle->m_xStream->m_pContent ) |
| { |
| rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| } |
| else |
| { |
| if ( !pEle->m_xStorage.Is() ) |
| pImp->OpenStorage( pEle, pImp->m_nMode, pImp->m_bDirect ); |
| if ( pEle->m_xStorage->m_nError ) |
| { |
| pEle->m_xStorage.Clear(); |
| return sal_False; |
| } |
| |
| try |
| { |
| if ( pEle->m_xStorage->GetContent() ) |
| { |
| rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName ); |
| return sal_True; |
| } |
| } |
| catch ( Exception& ) |
| { |
| } |
| } |
| |
| return sal_False; |
| } |
| |
| UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList() |
| { |
| if ( !pImp->m_pUNOStorageHolderList ) |
| pImp->m_pUNOStorageHolderList = new UNOStorageHolderList; |
| |
| return pImp->m_pUNOStorageHolderList; |
| } |
| |