summaryrefslogtreecommitdiff
path: root/sot/source/sdstor/ucbstorage.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sot/source/sdstor/ucbstorage.cxx')
-rw-r--r--sot/source/sdstor/ucbstorage.cxx3577
1 files changed, 3577 insertions, 0 deletions
diff --git a/sot/source/sdstor/ucbstorage.cxx b/sot/source/sdstor/ucbstorage.cxx
new file mode 100644
index 000000000000..51d297dd4e31
--- /dev/null
+++ b/sot/source/sdstor/ucbstorage.cxx
@@ -0,0 +1,3577 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_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 "stg.hxx"
+#include "storinfo.hxx"
+#include <sot/storage.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include "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 ULONG GetData( void* pData, ULONG nSize );
+ virtual ULONG PutData( const void* pData, ULONG nSize );
+ virtual ULONG SeekPos( ULONG nPos );
+ virtual void SetSize( 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 )
+ BOOL m_bSourceRead; // Source still contains useful information
+ BOOL m_bModified; // only modified streams will be sent to the original content
+ BOOL m_bCommited; // sending the streams is coordinated by the root storage of the package
+ 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
+ BOOL m_bIsOLEStorage;// an OLEStorage on a UCBStorageStream makes this an Autocommit-stream
+
+ UCBStorageStream_Impl( const String&, StreamMode, UCBStorageStream*, BOOL, const ByteString* pKey=0, BOOL bRepair = FALSE, Reference< XProgressHandler > xProgress = Reference< XProgressHandler >() );
+
+ void Free();
+ BOOL Init();
+ BOOL Clear();
+ sal_Int16 Commit(); // if modified and commited: transfer an XInputStream to the content
+ BOOL Revert(); // discard all changes
+ BaseStorage* CreateStorage();// create an OLE Storage on the UCBStorageStream
+ ULONG GetSize();
+
+ ULONG ReadSourceWriteTemporary( ULONG aLength ); // read aLength from source and copy to temporary,
+ // no seeking is produced
+ ULONG ReadSourceWriteTemporary(); // read source till the end and copy to temporary,
+
+ 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 )
+ BOOL m_bModified; // only modified elements will be sent to the original content
+ BOOL m_bCommited; // sending the streams is coordinated by the root storage of the package
+ 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
+ BOOL m_bIsRoot; // marks this storage as root storages that manages all oommits and reverts
+ BOOL m_bDirty; // ???
+ BOOL m_bIsLinked;
+ BOOL m_bListCreated;
+ ULONG m_nFormat;
+ String m_aUserTypeName;
+ SvGlobalName m_aClassId;
+
+ UCBStorageElementList_Impl m_aChildrenList;
+
+ BOOL m_bRepairPackage;
+ Reference< XProgressHandler > m_xProgressHandler;
+
+ UNOStorageHolderList* m_pUNOStorageHolderList;
+ UCBStorage_Impl( const ::ucbhelper::Content&, const String&, StreamMode, UCBStorage*, BOOL, BOOL, BOOL = FALSE, Reference< XProgressHandler > = Reference< XProgressHandler >() );
+ UCBStorage_Impl( const String&, StreamMode, UCBStorage*, BOOL, BOOL, BOOL = FALSE, Reference< XProgressHandler > = Reference< XProgressHandler >() );
+ UCBStorage_Impl( SvStream&, UCBStorage*, BOOL );
+ void Init();
+ sal_Int16 Commit();
+ BOOL Revert();
+ BOOL Insert( ::ucbhelper::Content *pContent );
+ UCBStorage_Impl* OpenStorage( UCBStorageElement_Impl* pElement, StreamMode nMode, BOOL bDirect );
+ UCBStorageStream_Impl* OpenStream( UCBStorageElement_Impl*, StreamMode, 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
+ ULONG m_nSize;
+ BOOL m_bIsFolder; // Only TRUE when it is a UCBStorage !
+ BOOL m_bIsStorage; // Also TRUE when it is an OLEStorage !
+ BOOL m_bIsRemoved; // element will be removed on commit
+ 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,
+ BOOL bIsFolder = FALSE, ULONG nSize = 0 )
+ : m_aName( rName )
+ , m_aOriginalName( rName )
+ , m_nSize( nSize )
+ , m_bIsFolder( bIsFolder )
+ , m_bIsStorage( bIsFolder )
+ , m_bIsRemoved( FALSE )
+ , m_bIsInserted( FALSE )
+ {
+ }
+
+ ::ucbhelper::Content* GetContent();
+ BOOL IsModified();
+ String GetContentType();
+ void SetContentType( const String& );
+ String GetOriginalContentType();
+ 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();
+}
+
+BOOL UCBStorageElement_Impl::IsModified()
+{
+ 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, BOOL bDirect, const ByteString* pKey, 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( FALSE )
+ , m_bCommited( FALSE )
+ , m_bDirect( bDirect )
+ , m_bIsOLEStorage( 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(RTL_CONSTASCII_USTRINGPARAM("?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(RTL_CONSTASCII_USTRINGPARAM("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, 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;
+}
+
+BOOL UCBStorageStream_Impl::Init()
+{
+ if( m_nRepresentMode == xinputstream )
+ {
+ DBG_ERROR( "XInputStream misuse!" );
+ SetError( ERRCODE_IO_ACCESSDENIED );
+ return 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 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 = FALSE;
+ }
+ catch( Exception& )
+ {
+ // something is really wrong
+ m_bSourceRead = 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 = FALSE;
+ //SetError( SVSTREAM_CANNOT_MAKE );
+ }
+ }
+
+ DBG_ASSERT( m_rSource.is() || !m_bSourceRead, "Unreadable source stream!" );
+
+ return sal_True;
+}
+
+ULONG UCBStorageStream_Impl::ReadSourceWriteTemporary()
+{
+ // read source stream till the end and copy all the data to
+ // the current position of the temporary stream
+
+ ULONG aResult = 0;
+
+ if( m_bSourceRead )
+ {
+ Sequence<sal_Int8> aData(32000);
+
+ try
+ {
+ 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( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#else
+ catch( Exception & )
+ {
+#endif
+ }
+ }
+
+ m_bSourceRead = FALSE;
+
+ return aResult;
+
+}
+
+ULONG UCBStorageStream_Impl::ReadSourceWriteTemporary( ULONG aLength )
+{
+ // read aLength bite from the source stream and copy them to the current
+ // position of the temporary stream
+
+ ULONG aResult = 0;
+
+ if( m_bSourceRead )
+ {
+ Sequence<sal_Int8> aData(32000);
+
+ try
+ {
+
+ ULONG aReaded = 32000;
+
+ for( ULONG pInd = 0; pInd < aLength && aReaded == 32000 ; pInd += 32000 )
+ {
+ ULONG aToCopy = min( aLength - pInd, 32000 );
+ aReaded = m_rSource->readBytes( aData, aToCopy );
+ aResult += m_pStream->Write( aData.getArray(), aReaded );
+ }
+
+ if( aResult < aLength )
+ m_bSourceRead = FALSE;
+ }
+#if OSL_DEBUG_LEVEL > 1
+ catch( Exception & e )
+ {
+ OSL_ENSURE( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#else
+ catch( Exception & )
+ {
+#endif
+ }
+ }
+
+ return aResult;
+}
+
+ULONG UCBStorageStream_Impl::CopySourceToTemporary()
+{
+ // current position of the temporary stream is not changed
+ ULONG aResult = 0;
+
+ if( m_bSourceRead )
+ {
+ ULONG aPos = m_pStream->Tell();
+ m_pStream->Seek( STREAM_SEEK_TO_END );
+ aResult = ReadSourceWriteTemporary();
+ m_pStream->Seek( aPos );
+ }
+
+ return aResult;
+
+}
+
+// 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
+ULONG UCBStorageStream_Impl::GetData( void* pData, ULONG nSize )
+{
+ 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
+
+ ULONG aToRead = nSize - aResult;
+ pData = (void*)( (char*)pData + aResult );
+
+ try
+ {
+ Sequence<sal_Int8> aData( aToRead );
+ 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( FALSE, ::rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
+#else
+ catch( Exception & )
+ {
+#endif
+ }
+
+ if( aResult < nSize )
+ m_bSourceRead = FALSE;
+ }
+
+ return aResult;
+}
+
+ULONG UCBStorageStream_Impl::PutData( const void* pData, ULONG nSize )
+{
+ if ( !(m_nMode & STREAM_WRITE) )
+ {
+ SetError( ERRCODE_IO_ACCESSDENIED );
+ return 0; // ?mav?
+ }
+
+ if( !nSize || !Init() )
+ return 0;
+
+ ULONG aResult = m_pStream->Write( pData, nSize );
+
+ m_bModified = aResult > 0;
+
+ return aResult;
+
+}
+
+ULONG UCBStorageStream_Impl::SeekPos( ULONG nPos )
+{
+ if( !Init() )
+ return 0;
+
+ 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 = 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( ULONG nSize )
+{
+ if ( !(m_nMode & STREAM_WRITE) )
+ {
+ SetError( ERRCODE_IO_ACCESSDENIED );
+ return;
+ }
+
+ if( !Init() )
+ return;
+
+ m_bModified = TRUE;
+
+ if( m_bSourceRead )
+ {
+ 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 = FALSE;
+}
+
+void UCBStorageStream_Impl::FlushData()
+{
+ if( m_pStream )
+ {
+ CopySourceToTemporary();
+ m_pStream->Flush();
+ }
+
+ m_bCommited = 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();
+}
+
+ULONG UCBStorageStream_Impl::GetSize()
+{
+ if( !Init() )
+ return 0;
+
+ ULONG nPos = m_pStream->Tell();
+ m_pStream->Seek( STREAM_SEEK_TO_END );
+ ReadSourceWriteTemporary();
+ 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(RTL_CONSTASCII_USTRINGPARAM("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 = FALSE;
+ m_bSourceRead = 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 = FALSE;
+ return COMMIT_RESULT_SUCCESS;
+ }
+ }
+
+ return COMMIT_RESULT_NOTHING_TO_DO;
+}
+
+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 FALSE; // ???
+ }
+
+ Free();
+ if ( m_aTempURL.Len() )
+ {
+ ::utl::UCBContentHelper::Kill( m_aTempURL );
+ m_aTempURL.Erase();
+ }
+
+ m_bSourceRead = 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 = FALSE;
+ else
+ {
+ m_nMode &= ~STREAM_TRUNC;
+ m_bSourceRead = TRUE;
+ }
+ }
+ else
+ SetError( SVSTREAM_CANNOT_MAKE );
+ }
+ catch ( ContentCreationException& )
+ {
+ SetError( ERRCODE_IO_GENERAL );
+ }
+ catch ( RuntimeException& )
+ {
+ SetError( ERRCODE_IO_GENERAL );
+ }
+ catch ( Exception& )
+ {
+ }
+
+ m_bModified = FALSE;
+ m_aName = m_aOriginalName;
+ m_aContentType = m_aOriginalContentType;
+ return ( GetError() == ERRCODE_NONE );
+}
+
+BOOL UCBStorageStream_Impl::Clear()
+{
+ 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, 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, BOOL bDirect, const ByteString* pKey, 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();
+}
+
+ULONG UCBStorageStream::Read( void * pData, ULONG nSize )
+{
+ //return pImp->m_pStream->Read( pData, nSize );
+ return pImp->GetData( pData, nSize );
+}
+
+ULONG UCBStorageStream::Write( const void* pData, ULONG nSize )
+{
+/*
+ // mba: does occur in writer !
+ if ( pImp->m_bCommited )
+ {
+ DBG_ERROR("Writing while commit is in progress!" );
+ return 0;
+ }
+*/
+ // pImp->m_bModified = TRUE;
+ //return pImp->m_pStream->Write( pData, nSize );
+ return pImp->PutData( pData, nSize );
+}
+
+ULONG UCBStorageStream::Seek( ULONG nPos )
+{
+ //return pImp->m_pStream->Seek( nPos );
+ return pImp->Seek( nPos );
+}
+
+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();
+}
+
+BOOL UCBStorageStream::SetSize( ULONG nNewSize )
+{
+/*
+ if ( pImp->m_bCommited )
+ {
+ DBG_ERROR("Changing stream size while commit is in progress!" );
+ return FALSE;
+ }
+*/
+ // pImp->m_bModified = TRUE;
+ //return pImp->m_pStream->SetStreamSize( nNewSize );
+ pImp->SetSize( nNewSize );
+ return !pImp->GetError();
+}
+
+BOOL UCBStorageStream::Validate( BOOL bWrite ) const
+{
+ return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
+}
+
+BOOL UCBStorageStream::ValidateMode( StreamMode m ) const
+{
+ // ???
+ if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
+ return TRUE;
+ USHORT 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 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 TRUE;
+ }
+
+ return 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();
+}
+
+BOOL UCBStorageStream::Equals( const BaseStorageStream& rStream ) const
+{
+ // ???
+ return ((BaseStorageStream*) this ) == &rStream;
+}
+
+BOOL UCBStorageStream::Commit()
+{
+ // mark this stream for sending it on root commit
+ pImp->FlushData();
+ return TRUE;
+}
+
+BOOL UCBStorageStream::Revert()
+{
+ return pImp->Revert();
+}
+
+BOOL UCBStorageStream::CopyTo( BaseStorageStream* pDestStm )
+{
+ if( !pImp->Init() )
+ return FALSE;
+
+ UCBStorageStream* pStg = PTR_CAST( UCBStorageStream, pDestStm );
+ if ( pStg )
+ pStg->pImp->m_aContentType = pImp->m_aContentType;
+
+ pDestStm->SetSize( 0 );
+ Seek( STREAM_SEEK_TO_END );
+ INT32 n = Tell();
+ if( n < 0 )
+ return FALSE;
+
+ if( pDestStm->SetSize( n ) && n )
+ {
+ BYTE* p = new BYTE[ 4096 ];
+ Seek( 0L );
+ pDestStm->Seek( 0L );
+ while( n )
+ {
+ 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 TRUE;
+}
+
+BOOL UCBStorageStream::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
+{
+ if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
+ return 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 TRUE;
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+
+ return FALSE;
+}
+
+BOOL UCBStorageStream::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
+{
+ try
+ {
+ if ( pImp->m_pContent )
+ {
+ rValue = pImp->m_pContent->getPropertyValue( rName );
+ return TRUE;
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+
+ return FALSE;
+}
+
+UCBStorage::UCBStorage( SvStream& rStrm, 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, 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, BOOL bDirect, 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, BOOL bDirect, BOOL bIsRoot, 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, BOOL bDirect, 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, BOOL bDirect, BOOL bIsRoot, 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( FALSE )
+ , m_bCommited( FALSE )
+ , m_bDirect( bDirect )
+ , m_bIsRoot( bIsRoot )
+ , m_bDirty( FALSE )
+ , m_bIsLinked( TRUE )
+ , m_bListCreated( 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( TRUE );
+ m_aName = m_aOriginalName = aName = m_pTempFile->GetURL();
+ }
+
+ m_aURL = rName;
+}
+
+UCBStorage_Impl::UCBStorage_Impl( const String& rName, StreamMode nMode, UCBStorage* pStorage, BOOL bDirect, BOOL bIsRoot, 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( FALSE )
+ , m_bCommited( FALSE )
+ , m_bDirect( bDirect )
+ , m_bIsRoot( bIsRoot )
+ , m_bDirty( FALSE )
+ , m_bIsLinked( FALSE )
+ , m_bListCreated( 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( 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 = TRUE;
+ }
+}
+
+UCBStorage_Impl::UCBStorage_Impl( SvStream& rStream, UCBStorage* pStorage, BOOL bDirect )
+ : m_pAntiImpl( pStorage )
+ , m_pContent( NULL )
+ , m_pTempFile( new ::utl::TempFile )
+ , m_pSource( &rStream )
+ , m_nError( 0 )
+ , m_bModified( FALSE )
+ , m_bCommited( FALSE )
+ , m_bDirect( bDirect )
+ , m_bIsRoot( TRUE )
+ , m_bDirty( FALSE )
+ , m_bIsLinked( FALSE )
+ , m_bListCreated( FALSE )
+ , m_nFormat( 0 )
+ , m_aClassId( SvGlobalName() )
+ , m_bRepairPackage( 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( 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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("?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 = TRUE;
+
+ // create cursor for access to children
+ Sequence< ::rtl::OUString > aProps(4);
+ ::rtl::OUString* pProps = aProps.getArray();
+ pProps[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Title"));
+ pProps[1] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsFolder"));
+ pProps[2] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
+ pProps[3] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("META-INF")) )
+ continue;
+ }
+ else
+ {
+ aContentType = xRow->getString(3);
+ }
+
+ BOOL bIsFolder( xRow->getBoolean(2) );
+ sal_Int64 nSize = xRow->getLong(4);
+ UCBStorageElement_Impl* pElement = new UCBStorageElement_Impl( aTitle, bIsFolder, (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(RTL_CONSTASCII_USTRINGPARAM("MediaType")) );
+ if ( ( aAny >>= aMediaType ) && ( aMediaType.compareToAscii("application/vnd.sun.star.oleobject") == 0 ) )
+ pElement->m_bIsStorage = 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 = 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 )
+{
+ BOOL bFound = 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.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("FullPath")) )
+ {
+ rtl::OUString aTmp;
+ if ( ( rAny.Value >>= aTmp ) && aTmp == rPath )
+ bFound = TRUE;
+ if ( aType.getLength() )
+ break;
+ }
+ else if ( rAny.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
+ aProps[0].Value <<= (::rtl::OUString ) m_aContentType;
+ aProps[1].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("MediaType"));
+ aProps[0].Value <<= (::rtl::OUString ) pElement->GetContentType();
+ aProps[1].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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;
+}
+
+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
+ BOOL bRet = 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 = 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();
+ BOOL bDeleteContent = FALSE;
+ if ( !pContent && pElement->IsModified() )
+ {
+ // if the element has never been opened, no content has been created until now
+ bDeleteContent = 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(RTL_CONSTASCII_USTRINGPARAM("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 <<= (BOOL) 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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("MediaType")), aType );
+
+ if ( m_bIsLinked )
+ {
+ // write a manifest file
+ // first create a subfolder "META-inf"
+ Content aNewSubFolder;
+ 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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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();
+ BOOL bRet = 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 = FALSE;
+ }
+
+ pInnerElement = pNext;
+ }
+ }
+
+ m_bCommited = FALSE;
+ }
+
+ return nRet;
+}
+
+BOOL UCBStorage_Impl::Revert()
+{
+ UCBStorageElement_Impl* pElement = m_aChildrenList.First();
+ BOOL bRet = TRUE;
+ while ( pElement && bRet )
+ {
+ pElement->m_bIsRemoved = 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 = FALSE;
+ }
+
+ pElement = m_aChildrenList.Next();
+ }
+
+ return bRet;
+}
+
+const String& UCBStorage::GetName() const
+{
+ return pImp->m_aName; // pImp->m_aURL ?!
+}
+
+BOOL UCBStorage::IsRoot() const
+{
+ return pImp->m_bIsRoot;
+}
+
+void UCBStorage::SetDirty()
+{
+ pImp->m_bDirty = TRUE;
+}
+
+void UCBStorage::SetClass( const SvGlobalName & rClass, 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*/, ULONG /*nOriginalClipFormat*/, const String & /*rUserTypeName*/ )
+{
+ // ???
+}
+
+BOOL UCBStorage::ShouldConvert()
+{
+ // ???
+ return FALSE;
+}
+
+SvGlobalName UCBStorage::GetClassName()
+{
+ return pImp->m_aClassId;
+}
+
+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 ?!
+ 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();
+ }
+}
+
+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;
+ BOOL bDeleteStream = 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 = 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
+ BOOL bDeleteStorage = 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 = TRUE;
+ }
+
+ UCBStorage* pUCBDest = PTR_CAST( UCBStorage, pDest );
+ UCBStorage* pUCBCopy = PTR_CAST( UCBStorage, pStorage );
+
+ 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 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;
+}
+
+BOOL UCBStorage::CopyTo( BaseStorage* pDestStg ) const
+{
+ DBG_ASSERT( pDestStg != ((BaseStorage*)this), "Self-Copying is not possible!" );
+ if ( pDestStg == ((BaseStorage*)this) )
+ return 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();
+
+ BOOL bRet = 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 BOOL( Good() && pDestStg->Good() );
+}
+
+BOOL UCBStorage::CopyTo( const String& rElemName, BaseStorage* pDest, const String& rNew )
+{
+ if( !rElemName.Len() )
+ return FALSE;
+
+ if ( pDest == ((BaseStorage*) this) )
+ {
+ // can't double an element
+ return 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 FALSE;
+ }
+ }
+}
+
+BOOL UCBStorage::Commit()
+{
+ // mark this storage for sending it on root commit
+ pImp->m_bCommited = 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 TRUE;
+}
+
+BOOL UCBStorage::Revert()
+{
+ return pImp->Revert();
+}
+
+BaseStorageStream* UCBStorage::OpenStream( const String& rEleName, StreamMode nMode, 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 = 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, 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, BOOL bDirect )
+{
+ if( !rEleName.Len() )
+ return NULL;
+
+ return OpenStorage_Impl( rEleName, nMode, bDirect, TRUE );
+}
+
+BaseStorage* UCBStorage::OpenOLEStorage( const String& rEleName, StreamMode nMode, BOOL bDirect )
+{
+ if( !rEleName.Len() )
+ return NULL;
+
+ return OpenStorage_Impl( rEleName, nMode, bDirect, FALSE );
+}
+
+BaseStorage* UCBStorage::OpenStorage( const String& rEleName, StreamMode nMode, BOOL bDirect )
+{
+ if( !rEleName.Len() )
+ return NULL;
+
+ return OpenStorage_Impl( rEleName, nMode, bDirect, TRUE );
+}
+
+BaseStorage* UCBStorage::OpenStorage_Impl( const String& rEleName, StreamMode nMode, BOOL bDirect, 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, FALSE, pImp->m_bRepairPackage, pImp->m_xProgressHandler );
+ pStorage->pImp->m_bIsRoot = 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 = 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 = 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
+ {
+ 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, 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
+ 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;
+ 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, BOOL bDirect )
+{
+ UCBStorage_Impl* pRet = NULL;
+ String aName( m_aURL );
+ aName += '/';
+ aName += pElement->m_aOriginalName; // ???
+
+ pElement->m_bIsStorage = pElement->m_bIsFolder = TRUE;
+
+ if ( m_bIsLinked && !::utl::UCBContentHelper::Exists( aName ) )
+ {
+ Content aNewFolder;
+ BOOL bRet = ::utl::UCBContentHelper::MakeFolder( *m_pContent, pElement->m_aOriginalName, aNewFolder );
+ if ( bRet )
+ pRet = new UCBStorage_Impl( aNewFolder, aName, nMode, NULL, bDirect, FALSE, m_bRepairPackage, m_xProgressHandler );
+ }
+ else
+ {
+ pRet = new UCBStorage_Impl( aName, nMode, NULL, bDirect, FALSE, m_bRepairPackage, m_xProgressHandler );
+ }
+
+ if ( pRet )
+ {
+ pRet->m_bIsLinked = m_bIsLinked;
+ pRet->m_bIsRoot = 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;
+}
+
+BOOL UCBStorage::IsStorage( const String& rEleName ) const
+{
+ if( !rEleName.Len() )
+ return FALSE;
+
+ const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
+ return ( pElement && pElement->m_bIsStorage );
+}
+
+BOOL UCBStorage::IsStream( const String& rEleName ) const
+{
+ if( !rEleName.Len() )
+ return FALSE;
+
+ const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
+ return ( pElement && !pElement->m_bIsStorage );
+}
+
+BOOL UCBStorage::IsContained( const String & rEleName ) const
+{
+ if( !rEleName.Len() )
+ return FALSE;
+ const UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
+ return ( pElement != NULL );
+}
+
+BOOL UCBStorage::Remove( const String& rEleName )
+{
+ if( !rEleName.Len() )
+ return FALSE;
+
+ UCBStorageElement_Impl *pElement = FindElement_Impl( rEleName );
+ if ( pElement )
+ {
+ pElement->m_bIsRemoved = TRUE;
+ }
+ else
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+
+ return ( pElement != NULL );
+}
+
+BOOL UCBStorage::Rename( const String& rEleName, const String& rNewName )
+{
+ if( !rEleName.Len()|| !rNewName.Len() )
+ return FALSE;
+
+ UCBStorageElement_Impl *pAlreadyExisting = FindElement_Impl( rNewName );
+ if ( pAlreadyExisting )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return 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;
+}
+
+BOOL UCBStorage::MoveTo( const String& rEleName, BaseStorage* pNewSt, const String& rNewName )
+{
+ if( !rEleName.Len() || !rNewName.Len() )
+ return 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
+ BOOL bRet = CopyTo( rEleName, pNewSt, rNewName );
+ if ( bRet )
+ bRet = Remove( rEleName );
+ return bRet;
+ }
+}
+
+BOOL UCBStorage::ValidateFAT()
+{
+ // ???
+ return TRUE;
+}
+
+BOOL UCBStorage::Validate( BOOL bWrite ) const
+{
+ // ???
+ return ( !bWrite || ( pImp->m_nMode & STREAM_WRITE ) );
+}
+
+BOOL UCBStorage::ValidateMode( StreamMode m ) const
+{
+ // ???
+ if( m == ( STREAM_READ | STREAM_TRUNC ) ) // from stg.cxx
+ return TRUE;
+ USHORT 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 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 TRUE;
+ }
+
+ return 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;
+}
+
+BOOL UCBStorage::Equals( const BaseStorage& rStorage ) const
+{
+ // ???
+ return ((BaseStorage*)this) == &rStorage;
+}
+
+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 );
+ BOOL bRet = UCBStorage::IsStorageFile( pStm );
+ delete pStm;
+ return bRet;
+}
+
+BOOL UCBStorage::IsStorageFile( SvStream* pFile )
+{
+ if ( !pFile )
+ return FALSE;
+
+ ULONG nPos = pFile->Tell();
+ pFile->Seek( STREAM_SEEK_TO_END );
+ if ( pFile->Tell() < 4 )
+ return FALSE;
+
+ pFile->Seek(0);
+ UINT32 nBytes;
+ *pFile >> nBytes;
+
+ // search for the magic bytes
+ 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;
+}
+
+BOOL UCBStorage::IsDiskSpannedFile( SvStream* pFile )
+{
+ if ( !pFile )
+ return FALSE;
+
+ ULONG nPos = pFile->Tell();
+ pFile->Seek( STREAM_SEEK_TO_END );
+ if ( !pFile->Tell() )
+ return FALSE;
+
+ pFile->Seek(0);
+ UINT32 nBytes;
+ *pFile >> nBytes;
+
+ // disk spanned file have an additional header in front of the usual one
+ BOOL bRet = ( nBytes == 0x08074b50 );
+ if ( bRet )
+ {
+ *pFile >> nBytes;
+ bRet = ( nBytes == 0x04034b50 );
+ }
+
+ pFile->Seek( nPos );
+ return bRet;
+}
+
+String UCBStorage::GetLinkedFile( SvStream &rStream )
+{
+ String aString;
+ ULONG nPos = rStream.Tell();
+ rStream.Seek( STREAM_SEEK_TO_END );
+ if ( !rStream.Tell() )
+ return aString;
+
+ rStream.Seek(0);
+ 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 << ( 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;
+ 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( TRUE );
+ delete pTempFile;
+ return String();
+}
+
+BOOL UCBStorage::SetProperty( const String& rName, const ::com::sun::star::uno::Any& rValue )
+{
+ if ( rName.CompareToAscii("Title") == COMPARE_EQUAL )
+ return 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 TRUE;
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+
+ return FALSE;
+}
+
+BOOL UCBStorage::GetProperty( const String& rName, ::com::sun::star::uno::Any& rValue )
+{
+ try
+ {
+ if ( pImp->GetContent() )
+ {
+ rValue = pImp->m_pContent->getPropertyValue( rName );
+ return TRUE;
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+
+ return FALSE;
+}
+
+BOOL UCBStorage::GetProperty( const String& rEleName, const String& rName, ::com::sun::star::uno::Any& rValue )
+{
+ UCBStorageElement_Impl *pEle = FindElement_Impl( rEleName );
+ if ( !pEle )
+ return 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 FALSE;
+ }
+
+ try
+ {
+ if ( pEle->m_xStream->m_pContent )
+ {
+ rValue = pEle->m_xStream->m_pContent->getPropertyValue( rName );
+ return 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 FALSE;
+ }
+
+ try
+ {
+ if ( pEle->m_xStorage->GetContent() )
+ {
+ rValue = pEle->m_xStorage->m_pContent->getPropertyValue( rName );
+ return TRUE;
+ }
+ }
+ catch ( Exception& )
+ {
+ }
+ }
+
+ return FALSE;
+}
+
+UNOStorageHolderList* UCBStorage::GetUNOStorageHolderList()
+{
+ if ( !pImp->m_pUNOStorageHolderList )
+ pImp->m_pUNOStorageHolderList = new UNOStorageHolderList;
+
+ return pImp->m_pUNOStorageHolderList;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */