| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sot.hxx" |
| |
| #include <sot/storinfo.hxx> |
| #include <osl/file.hxx> |
| #include <tools/tempfile.hxx> |
| #include <tools/ownlist.hxx> |
| #include <tools/string.hxx> |
| #ifndef _TOOLS_FSYS_HXX |
| #include <tools/fsys.hxx> |
| #endif |
| #ifndef _TOOLS_STREAM_HXX |
| #include <tools/stream.hxx> |
| #endif |
| #include <tools/pstm.hxx> |
| #include <tools/debug.hxx> |
| |
| #include "sot/stg.hxx" |
| #include "stgelem.hxx" |
| #include "stgcache.hxx" |
| #include "stgstrms.hxx" |
| #include "stgdir.hxx" |
| #include "stgio.hxx" |
| #include "stgole.hxx" |
| |
| static long nTmpCount = 0; |
| |
| // The internal open mode is STREAM_READ | STREAM_TRUNC, which is silly |
| // by itself. It inhibits the checking of sharing modes and is used |
| // during CopyTo() and MoveTo() for opening a stream in read mode |
| // although it may be open in DENYALL mode |
| |
| #define INTERNAL_MODE ( STREAM_READ | STREAM_TRUNC ) |
| |
| ///////////////////////// class StorageBase ////////////////////////////// |
| |
| TYPEINIT0( StorageBase ); |
| TYPEINIT1( BaseStorageStream, StorageBase ); |
| TYPEINIT1( BaseStorage, StorageBase ); |
| |
| StorageBase::StorageBase() |
| : m_bAutoCommit( sal_False ) |
| { |
| m_nMode = STREAM_READ; |
| m_nError = SVSTREAM_OK; |
| } |
| |
| StorageBase::~StorageBase() |
| { |
| } |
| |
| // The following three methods are declared as const, since they |
| // may be called from within a const method. |
| |
| sal_uLong StorageBase::GetError() const |
| { |
| sal_uLong n = m_nError; |
| ((StorageBase*) this)->m_nError = SVSTREAM_OK; |
| return n; |
| } |
| |
| void StorageBase::SetError( sal_uLong n ) const |
| { |
| if( !m_nError ) |
| ((StorageBase*) this)->m_nError = n; |
| } |
| |
| void StorageBase::ResetError() const |
| { |
| ((StorageBase*) this)->m_nError = SVSTREAM_OK; |
| } |
| |
| // Retrieve the underlying SvStream for info purposes |
| |
| const SvStream* OLEStorageBase::GetSvStream_Impl() const |
| { |
| return pIo ? pIo->GetStrm() : NULL; |
| } |
| |
| OLEStorageBase::OLEStorageBase( StgIo* p, StgDirEntry* pe, StreamMode& nMode ) |
| : nStreamMode( nMode ), pIo( p ), pEntry( pe ) |
| { |
| if ( p ) |
| p->IncRef(); |
| if( pe ) |
| pe->nRefCnt++; |
| } |
| |
| OLEStorageBase::~OLEStorageBase() |
| { |
| if( pEntry ) |
| { |
| DBG_ASSERT( pEntry->nRefCnt, "RefCount unter 0" ); |
| if( !--pEntry->nRefCnt ) |
| { |
| if( pEntry->bZombie ) |
| delete pEntry; |
| else |
| pEntry->Close(); |
| } |
| |
| pEntry = NULL; |
| } |
| |
| |
| if( pIo && !pIo->DecRef() ) |
| { |
| delete pIo; |
| pIo = NULL; |
| } |
| } |
| |
| // Validate the instance for I/O |
| |
| sal_Bool OLEStorageBase::Validate_Impl( sal_Bool bWrite ) const |
| { |
| if( pIo |
| && pIo->pTOC |
| && pEntry |
| && !pEntry->bInvalid |
| && ( !bWrite || !pEntry->bDirect || ( nStreamMode & STREAM_WRITE ) ) ) |
| return sal_True; |
| return sal_False; |
| } |
| |
| sal_Bool OLEStorageBase::ValidateMode_Impl( StreamMode m, StgDirEntry* p ) const |
| { |
| if( m == INTERNAL_MODE ) |
| return sal_True; |
| sal_uInt16 nCurMode = ( p && p->nRefCnt ) ? p->nMode : 0xFFFF; |
| if( ( m & 3 ) == STREAM_READ ) |
| { |
| // only SHARE_DENYWRITE or SHARE_DENYALL allowed |
| if( ( ( m & STREAM_SHARE_DENYWRITE ) |
| && ( nCurMode & STREAM_SHARE_DENYWRITE ) ) |
| || ( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) ) |
| return sal_True; |
| } |
| else |
| { |
| // only SHARE_DENYALL allowed |
| // storages open in r/o mode are OK, since only |
| // the commit may fail |
| if( ( m & STREAM_SHARE_DENYALL ) |
| && ( nCurMode & STREAM_SHARE_DENYALL ) ) |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //////////////////////// class StorageStream ///////////////////////////// |
| |
| TYPEINIT1( StorageStream, BaseStorageStream ); |
| |
| StorageStream::StorageStream( StgIo* p, StgDirEntry* q, StreamMode m ) |
| : OLEStorageBase( p, q, m_nMode ), nPos( 0L ) |
| { |
| // The dir entry may be 0; this means that the stream is invalid. |
| if( q && p ) |
| { |
| if( q->nRefCnt == 1 ) |
| { |
| q->nMode = m; |
| q->OpenStream( *p ); |
| } |
| } |
| else |
| m &= ~STREAM_READWRITE; |
| m_nMode = m; |
| } |
| |
| StorageStream::~StorageStream() |
| { |
| // Do an auto-commit if the entry is open in direct mode |
| if( m_bAutoCommit ) |
| Commit(); |
| if( pEntry && pEntry->nRefCnt && pEntry->bDirect && (m_nMode & STREAM_WRITE) ) |
| pEntry->Commit(); |
| } |
| |
| sal_Bool StorageStream::Equals( const BaseStorageStream& rStream ) const |
| { |
| const StorageStream* pOther = PTR_CAST( StorageStream, &rStream ); |
| return pOther && ( pOther->pEntry == pEntry ); |
| } |
| |
| sal_uLong StorageStream::Read( void* pData, sal_uLong nSize ) |
| { |
| if( Validate() ) |
| { |
| pEntry->Seek( nPos ); |
| nSize = pEntry->Read( pData, (sal_Int32) nSize ); |
| pIo->MoveError( *this ); |
| nPos += nSize; |
| } |
| else |
| nSize = 0L; |
| return nSize; |
| } |
| |
| sal_uLong StorageStream::Write( const void* pData, sal_uLong nSize ) |
| { |
| if( Validate( sal_True ) ) |
| { |
| pEntry->Seek( nPos ); |
| nSize = pEntry->Write( pData, (sal_Int32) nSize ); |
| pIo->MoveError( *this ); |
| nPos += nSize; |
| } |
| else |
| nSize = 0L; |
| return nSize; |
| } |
| |
| sal_uLong StorageStream::Seek( sal_uLong n ) |
| { |
| if( Validate() ) |
| return nPos = pEntry->Seek( n ); |
| else |
| return n; |
| } |
| |
| void StorageStream::Flush() |
| { |
| // Flushing means committing, since streams are never transacted |
| Commit(); |
| } |
| |
| sal_Bool StorageStream::SetSize( sal_uLong nNewSize ) |
| { |
| if( Validate( sal_True ) ) |
| { |
| sal_Bool b = pEntry->SetSize( (sal_Int32) nNewSize ); |
| pIo->MoveError( *this ); |
| return b; |
| } |
| else |
| return sal_False; |
| } |
| |
| sal_Bool StorageStream::Commit() |
| { |
| if( !Validate() ) |
| return sal_False; |
| if( !( m_nMode & STREAM_WRITE ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| else |
| { |
| pEntry->Commit(); |
| pIo->MoveError( *this ); |
| return Good(); |
| } |
| } |
| |
| sal_Bool StorageStream::Revert() |
| { |
| sal_Bool bResult = sal_False; |
| |
| if ( Validate() ) |
| { |
| pEntry->Revert(); |
| pIo->MoveError( *this ); |
| bResult = Good(); |
| } |
| |
| return bResult; |
| } |
| |
| sal_Bool StorageStream::CopyTo( BaseStorageStream* pDest ) |
| { |
| if( !Validate() || !pDest || !pDest->Validate( sal_True ) || Equals( *pDest ) ) |
| return sal_False; |
| pEntry->Copy( *pDest ); |
| pDest->Commit(); |
| pIo->MoveError( *this ); |
| SetError( pDest->GetError() ); |
| return sal_Bool( Good() && pDest->Good() ); |
| } |
| |
| const SvStream* StorageStream::GetSvStream() const |
| { |
| return GetSvStream_Impl(); |
| } |
| |
| sal_Bool StorageStream::Validate( sal_Bool bValidate ) const |
| { |
| sal_Bool bRet = Validate_Impl( bValidate ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| sal_Bool StorageStream::ValidateMode( StreamMode nMode ) const |
| { |
| sal_Bool bRet = ValidateMode_Impl( nMode, NULL ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| sal_Bool StorageStream::ValidateMode( StreamMode nMode, StgDirEntry* p ) const |
| { |
| sal_Bool bRet = ValidateMode_Impl( nMode, p ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| ///////////////////////// class SvStorageInfo ////////////////////////////// |
| |
| SvStorageInfo::SvStorageInfo( const StgDirEntry& rE ) |
| { |
| rE.aEntry.GetName( aName ); |
| bStorage = sal_Bool( rE.aEntry.GetType() == STG_STORAGE ); |
| bStream = sal_Bool( rE.aEntry.GetType() == STG_STREAM ); |
| nSize = bStorage ? 0 : rE.aEntry.GetSize(); |
| } |
| |
| /////////////////////////// class Storage //////////////////////////////// |
| |
| sal_Bool Storage::IsStorageFile( const String & rFileName ) |
| { |
| StgIo aIo; |
| if( aIo.Open( rFileName, STREAM_STD_READ ) ) |
| return aIo.Load(); |
| return sal_False; |
| } |
| |
| sal_Bool Storage::IsStorageFile( SvStream* pStream ) |
| { |
| sal_Bool bRet = sal_False; |
| |
| if ( pStream ) |
| { |
| StgHeader aHdr; |
| sal_uLong nPos = pStream->Tell(); |
| bRet = ( aHdr.Load( *pStream ) && aHdr.Check() ); |
| |
| // It's not a stream error if it is too small for a OLE storage header |
| if ( pStream->GetErrorCode() == ERRCODE_IO_CANTSEEK ) |
| pStream->ResetError(); |
| pStream->Seek( nPos ); |
| } |
| |
| return bRet; |
| } |
| |
| // Open the storage file. If writing is permitted and the file is not |
| // a storage file, initialize it. |
| |
| TYPEINIT1( Storage, BaseStorage ); |
| |
| Storage::Storage( const String& rFile, StreamMode m, sal_Bool bDirect ) |
| : OLEStorageBase( new StgIo, NULL, m_nMode ), aName( rFile ), bIsRoot( sal_False ) |
| { |
| sal_Bool bTemp = sal_False; |
| if( !aName.Len() ) |
| { |
| // no name = temporary name! |
| aName = TempFile::CreateTempName(); |
| bTemp = sal_True; |
| } |
| // the root storage creates the I/O system |
| m_nMode = m; |
| if( pIo->Open( aName, m ) ) |
| { |
| Init( sal_Bool( ( m & ( STREAM_TRUNC | STREAM_NOCREATE ) ) == STREAM_TRUNC ) ); |
| if( pEntry ) |
| { |
| pEntry->bDirect = bDirect; |
| pEntry->nMode = m; |
| pEntry->bTemp = bTemp; |
| } |
| } |
| else |
| { |
| pIo->MoveError( *this ); |
| pEntry = NULL; |
| } |
| } |
| |
| // Create a storage on a given stream. |
| |
| Storage::Storage( SvStream& r, sal_Bool bDirect ) |
| : OLEStorageBase( new StgIo, NULL, m_nMode ), bIsRoot( sal_False ) |
| { |
| m_nMode = STREAM_READ; |
| if( r.IsWritable() ) |
| m_nMode = STREAM_READ | STREAM_WRITE; |
| if( r.GetError() == SVSTREAM_OK ) |
| { |
| pIo->SetStrm( &r, sal_False ); |
| sal_uLong nSize = r.Seek( STREAM_SEEK_TO_END ); |
| r.Seek( 0L ); |
| // Initializing is OK if the stream is empty |
| Init( sal_Bool( nSize == 0 ) ); |
| if( pEntry ) |
| { |
| pEntry->bDirect = bDirect; |
| pEntry->nMode = m_nMode; |
| } |
| pIo->MoveError( *this ); |
| } |
| else |
| { |
| SetError( r.GetError() ); |
| pEntry = NULL; |
| } |
| } |
| |
| |
| Storage::Storage( UCBStorageStream& rStrm, sal_Bool bDirect ) |
| : OLEStorageBase( new StgIo, NULL, m_nMode ), bIsRoot( sal_False ) |
| { |
| m_nMode = STREAM_READ; |
| |
| if ( rStrm.GetError() != SVSTREAM_OK ) |
| { |
| SetError( rStrm.GetError() ); |
| pEntry = NULL; |
| return; |
| } |
| |
| SvStream* pStream = rStrm.GetModifySvStream(); |
| if ( !pStream ) |
| { |
| OSL_ENSURE( sal_False, "UCBStorageStream can not provide SvStream implementation!\n" ); |
| SetError( SVSTREAM_GENERALERROR ); |
| pEntry = NULL; |
| return; |
| } |
| |
| if( pStream->IsWritable() ) |
| m_nMode = STREAM_READ | STREAM_WRITE; |
| |
| pIo->SetStrm( &rStrm ); |
| |
| sal_uLong nSize = pStream->Seek( STREAM_SEEK_TO_END ); |
| pStream->Seek( 0L ); |
| // Initializing is OK if the stream is empty |
| Init( sal_Bool( nSize == 0 ) ); |
| if( pEntry ) |
| { |
| pEntry->bDirect = bDirect; |
| pEntry->nMode = m_nMode; |
| } |
| |
| pIo->MoveError( *this ); |
| } |
| |
| |
| // Perform common code for both ctors above. |
| |
| void Storage::Init( sal_Bool bCreate ) |
| { |
| pEntry = NULL; |
| sal_Bool bHdrLoaded = sal_False; |
| bIsRoot = sal_True; |
| |
| OSL_ENSURE( pIo, "The pointer may not be empty at this point!" ); |
| if( pIo->Good() && pIo->GetStrm() ) |
| { |
| sal_uLong nSize = pIo->GetStrm()->Seek( STREAM_SEEK_TO_END ); |
| pIo->GetStrm()->Seek( 0L ); |
| if( nSize ) |
| { |
| bHdrLoaded = pIo->Load(); |
| if( !bHdrLoaded && !bCreate ) |
| { |
| // File is not a storage and not empty; do not destroy! |
| SetError( SVSTREAM_FILEFORMAT_ERROR ); |
| return; |
| } |
| } |
| } |
| // file is a storage, empty or should be overwritten |
| pIo->ResetError(); |
| // we have to set up the data structures, since |
| // the file is empty |
| if( !bHdrLoaded ) |
| pIo->Init(); |
| if( pIo->Good() && pIo->pTOC ) |
| { |
| pEntry = pIo->pTOC->GetRoot(); |
| pEntry->nRefCnt++; |
| } |
| } |
| |
| // Internal ctor |
| |
| Storage::Storage( StgIo* p, StgDirEntry* q, StreamMode m ) |
| : OLEStorageBase( p, q, m_nMode ), bIsRoot( sal_False ) |
| { |
| if( q ) |
| q->aEntry.GetName( aName ); |
| else |
| m &= ~STREAM_READWRITE; |
| m_nMode = m; |
| if( q && q->nRefCnt == 1 ) |
| q->nMode = m; |
| } |
| |
| Storage::~Storage() |
| { |
| // Invalidate all open substorages |
| if( m_bAutoCommit ) |
| Commit(); |
| if( pEntry ) |
| { |
| // Do an auto-commit if the entry is open in direct mode |
| if( pEntry->nRefCnt && pEntry->bDirect && (m_nMode & STREAM_WRITE) ) |
| Commit(); |
| if( pEntry->nRefCnt == 1 ) |
| pEntry->Invalidate(); |
| } |
| // close the stream is root storage |
| if( bIsRoot ) |
| pIo->Close(); |
| // remove the file if temporary root storage |
| if( bIsRoot && pEntry && pEntry->bTemp ) |
| { |
| osl::File::remove( GetName() ); |
| } |
| } |
| |
| const String& Storage::GetName() const |
| { |
| if( !bIsRoot && Validate() ) |
| pEntry->aEntry.GetName( ((Storage*) this)->aName ); |
| return aName; |
| } |
| |
| // Fill in the info list for this storage |
| |
| void Storage::FillInfoList( SvStorageInfoList* pList ) const |
| { |
| if( Validate() && pList ) |
| { |
| StgIterator aIter( *pEntry ); |
| StgDirEntry* p = aIter.First(); |
| while( p ) |
| { |
| if( !p->bInvalid ) |
| { |
| SvStorageInfo aInfo( *p ); |
| pList->Append( aInfo ); |
| } |
| p = aIter.Next(); |
| } |
| } |
| } |
| |
| // Open or create a substorage |
| |
| BaseStorage* Storage::OpenUCBStorage( const String& rName, StreamMode m, sal_Bool bDirect ) |
| { |
| DBG_ERROR("Not supported!"); |
| /* |
| BaseStorage* pStorage = new Storage( pIo, NULL, m ); |
| SetError( ERRCODE_IO_NOTSUPPORTED ); |
| return pStorage; |
| */ |
| return OpenStorage( rName, m, bDirect ); |
| } |
| |
| BaseStorage* Storage::OpenOLEStorage( const String& rName, StreamMode m, sal_Bool bDirect ) |
| { |
| return OpenStorage( rName, m, bDirect ); |
| } |
| |
| BaseStorage* Storage::OpenStorage( const String& rName, StreamMode m, sal_Bool bDirect ) |
| { |
| if( !Validate() || !ValidateMode( m ) ) |
| return new Storage( pIo, NULL, m ); |
| sal_Bool bSetAutoCommit = sal_False; |
| if( bDirect && !pEntry->bDirect ) |
| { |
| bSetAutoCommit = sal_True; |
| bDirect = sal_False; |
| } |
| |
| StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName ); |
| if( !p ) |
| { |
| if( !( m & STREAM_NOCREATE ) ) |
| { |
| sal_Bool bTemp = sal_False; |
| // create a new storage |
| String aNewName = rName; |
| if( !aNewName.Len() ) |
| { |
| aNewName.AssignAscii( "Temp Stg " ); |
| aNewName.Append( String::CreateFromInt32( ++nTmpCount ) ); |
| bTemp = sal_True; |
| } |
| p = pIo->pTOC->Create( *pEntry, aNewName, STG_STORAGE ); |
| if( p ) |
| p->bTemp = bTemp; |
| } |
| if( !p ) |
| pIo->SetError( ( m & STREAM_WRITE ) |
| ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND ); |
| } |
| else if( !ValidateMode( m, p ) ) |
| p = NULL; |
| if( p && p->aEntry.GetType() != STG_STORAGE ) |
| { |
| pIo->SetError( SVSTREAM_FILE_NOT_FOUND ); |
| p = NULL; |
| } |
| |
| // Either direct or transacted mode is supported |
| if( p && pEntry->nRefCnt == 1 ) |
| p->bDirect = bDirect; |
| |
| // Dont check direct conflict if opening readonly |
| if( p && (m & STREAM_WRITE )) |
| { |
| if( p->bDirect != bDirect ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| } |
| Storage* pStg = new Storage( pIo, p, m ); |
| pIo->MoveError( *pStg ); |
| if( m & STREAM_WRITE ) pStg->m_bAutoCommit = sal_True; |
| return pStg; |
| } |
| |
| // Open a stream |
| |
| BaseStorageStream* Storage::OpenStream( const String& rName, StreamMode m, sal_Bool, |
| const ByteString* |
| #ifdef DBG_UTIL |
| pB |
| #endif |
| ) |
| { |
| DBG_ASSERT(!pB, "Encryption not supported"); |
| |
| if( !Validate() || !ValidateMode( m ) ) |
| return new StorageStream( pIo, NULL, m ); |
| StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName ); |
| sal_Bool bTemp = sal_False; |
| if( !p ) |
| { |
| if( !( m & STREAM_NOCREATE ) ) |
| { |
| // create a new stream |
| // make a name if the stream is temporary (has no name) |
| String aNewName( rName ); |
| if( !aNewName.Len() ) |
| { |
| aNewName.AssignAscii( "Temp Strm " ); |
| aNewName.Append( String::CreateFromInt32( ++nTmpCount ) ); |
| bTemp = sal_True; |
| } |
| p = pIo->pTOC->Create( *pEntry, aNewName, STG_STREAM ); |
| } |
| if( !p ) |
| pIo->SetError( ( m & STREAM_WRITE ) |
| ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND ); |
| } |
| else if( !ValidateMode( m, p ) ) |
| p = NULL; |
| if( p && p->aEntry.GetType() != STG_STREAM ) |
| { |
| pIo->SetError( SVSTREAM_FILE_NOT_FOUND ); |
| p = NULL; |
| } |
| if( p ) |
| { |
| p->bTemp = bTemp; |
| p->bDirect = pEntry->bDirect; |
| } |
| StorageStream* pStm = new StorageStream( pIo, p, m ); |
| if( p && !p->bDirect ) |
| pStm->SetAutoCommit( sal_True ); |
| pIo->MoveError( *pStm ); |
| return pStm; |
| } |
| |
| // Delete a stream or substorage by setting the temp bit. |
| |
| sal_Bool Storage::Remove( const String& rName ) |
| { |
| if( !Validate( sal_True ) ) |
| return sal_False; |
| StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName ); |
| if( p ) |
| { |
| p->Invalidate( sal_True ); |
| return sal_True; |
| } |
| else |
| { |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| return sal_False; |
| } |
| } |
| |
| // Rename a storage element |
| |
| sal_Bool Storage::Rename( const String& rOld, const String& rNew ) |
| { |
| if( Validate( sal_True ) ) |
| { |
| sal_Bool b = pIo->pTOC->Rename( *pEntry, rOld, rNew ); |
| pIo->MoveError( *this ); |
| return b; |
| } |
| else |
| return sal_False; |
| } |
| |
| // Copy one element |
| |
| sal_Bool Storage::CopyTo( const String& rElem, BaseStorage* pDest, const String& rNew ) |
| { |
| if( !Validate() || !pDest || !pDest->Validate( sal_True ) ) |
| return sal_False; |
| StgDirEntry* pElem = pIo->pTOC->Find( *pEntry, rElem ); |
| if( pElem ) |
| { |
| /* |
| this lines are misterious !!! MM |
| if( !pElem->IsContained( pDest->pEntry ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| */ |
| if( pElem->aEntry.GetType() == STG_STORAGE ) |
| { |
| // copy the entire storage |
| BaseStorage* p1 = OpenStorage( rElem, INTERNAL_MODE ); |
| BaseStorage* p2 = pDest->OpenOLEStorage( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pEntry->bDirect ); |
| |
| if ( p2 ) |
| { |
| sal_uLong nTmpErr = p2->GetError(); |
| if( !nTmpErr ) |
| { |
| p2->SetClassId( p1->GetClassId() ); |
| p1->CopyTo( p2 ); |
| SetError( p1->GetError() ); |
| |
| nTmpErr = p2->GetError(); |
| if( !nTmpErr ) |
| p2->Commit(); |
| else |
| pDest->SetError( nTmpErr ); |
| } |
| else |
| pDest->SetError( nTmpErr ); |
| } |
| |
| delete p1; |
| delete p2; |
| return sal_Bool( Good() && pDest->Good() ); |
| } |
| else |
| { |
| // stream copy |
| BaseStorageStream* p1 = OpenStream( rElem, INTERNAL_MODE ); |
| BaseStorageStream* p2 = pDest->OpenStream( rNew, STREAM_WRITE | STREAM_SHARE_DENYALL, pEntry->bDirect ); |
| |
| if ( p2 ) |
| { |
| sal_uLong nTmpErr = p2->GetError(); |
| if( !nTmpErr ) |
| { |
| p1->CopyTo( p2 ); |
| SetError( p1->GetError() ); |
| |
| nTmpErr = p2->GetError(); |
| if( !nTmpErr ) |
| p2->Commit(); |
| else |
| pDest->SetError( nTmpErr ); |
| } |
| else |
| pDest->SetError( nTmpErr ); |
| } |
| |
| delete p1; |
| delete p2; |
| return sal_Bool( Good() && pDest->Good() ); |
| } |
| } |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| return sal_False; |
| } |
| |
| sal_Bool Storage::CopyTo( BaseStorage* pDest ) const |
| { |
| if( !Validate() || !pDest || !pDest->Validate( sal_True ) || Equals( *pDest ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| Storage* pThis = (Storage*) this; |
| /* |
| if( !pThis->pEntry->IsContained( pDest->pEntry ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| */ |
| pDest->SetClassId( GetClassId() ); |
| pDest->SetDirty(); |
| SvStorageInfoList aList; |
| FillInfoList( &aList ); |
| sal_Bool bRes = sal_True; |
| for( sal_uInt16 i = 0; i < aList.Count() && bRes; i++ ) |
| { |
| SvStorageInfo& rInfo = aList.GetObject( i ); |
| bRes = pThis->CopyTo( rInfo.GetName(), pDest, rInfo.GetName() ); |
| } |
| if( !bRes ) |
| SetError( pDest->GetError() ); |
| return sal_Bool( Good() && pDest->Good() ); |
| } |
| |
| // Move one element |
| |
| sal_Bool Storage::MoveTo( const String& rElem, BaseStorage* pODest, const String& rNew ) |
| { |
| if( !Validate() || !pODest || !pODest->Validate( sal_True ) || Equals( *pODest ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| |
| StgDirEntry* pElem = pIo->pTOC->Find( *pEntry, rElem ); |
| if( pElem ) |
| { |
| // Simplest case: both storages share the same file |
| sal_Bool bRes; |
| Storage *pOther = PTR_CAST( Storage, pODest ); |
| if( pOther && pIo == pOther->pIo && rElem == rNew ) |
| { |
| Storage *p = (Storage*) pODest; |
| Storage *pDest = p; |
| // both storages are conventional storages, use implementation dependent code |
| if( !pElem->IsContained( pDest->pEntry ) ) |
| { |
| // cyclic move |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| bRes = pIo->pTOC->Move( *pEntry, *pDest->pEntry, rNew ); |
| if( !bRes ) |
| { |
| pIo->MoveError( *this ); |
| pDest->pIo->MoveError( *pDest ); |
| sal_uLong nErr = GetError(); |
| if( !nErr ) |
| nErr = pDest->GetError(); |
| SetError( nErr ); |
| pDest->SetError( nErr ); |
| } |
| } |
| else |
| { |
| bRes = CopyTo( rElem, pODest, rNew ); |
| if( bRes ) |
| bRes = Remove( rElem ); |
| } |
| if( !bRes ) |
| SetError( pIo->GetError() ); |
| return bRes; |
| } |
| SetError( SVSTREAM_FILE_NOT_FOUND ); |
| return sal_False; |
| } |
| |
| sal_Bool Storage::IsStorage( const String& rName ) const |
| { |
| if( Validate() ) |
| { |
| StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName ); |
| if( p ) |
| return sal_Bool( p->aEntry.GetType() == STG_STORAGE ); |
| } |
| return sal_False; |
| } |
| |
| sal_Bool Storage::IsStream( const String& rName ) const |
| { |
| if( Validate() ) |
| { |
| StgDirEntry* p = pIo->pTOC->Find( *pEntry, rName ); |
| if( p ) |
| return sal_Bool( p->aEntry.GetType() == STG_STREAM ); |
| } |
| return sal_False; |
| } |
| |
| sal_Bool Storage::IsContained( const String& rName ) const |
| { |
| if( Validate() ) |
| return sal_Bool( pIo->pTOC->Find( *pEntry, rName ) != NULL ); |
| else |
| return sal_False; |
| } |
| |
| // Commit all sub-elements within this storage. If this is |
| // the root, commit the FAT, the TOC and the header as well. |
| |
| sal_Bool Storage::Commit() |
| { |
| sal_Bool bRes = sal_True; |
| if( !Validate() ) |
| return sal_False; |
| if( !( m_nMode & STREAM_WRITE ) ) |
| { |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return sal_False; |
| } |
| else |
| { |
| // Also commit the sub-streams and Storages |
| StgIterator aIter( *pEntry ); |
| for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() ) |
| bRes = p->Commit(); |
| if( bRes && bIsRoot ) |
| { |
| bRes = pEntry->Commit(); |
| if( bRes ) |
| bRes = pIo->CommitAll(); |
| } |
| pIo->MoveError( *this ); |
| } |
| return bRes; |
| } |
| |
| sal_Bool Storage::Revert() |
| { |
| return sal_True; |
| } |
| |
| ///////////////////////////// OLE Support //////////////////////////////// |
| |
| // Set the storage type |
| |
| void Storage::SetClass( const SvGlobalName & rClass, |
| sal_uLong nOriginalClipFormat, |
| const String & rUserTypeName ) |
| { |
| if( Validate( sal_True ) ) |
| { |
| // set the class name in the root entry |
| pEntry->aEntry.SetClassId( (const ClsId&) rClass.GetCLSID() ); |
| pEntry->SetDirty(); |
| // then create the streams |
| StgCompObjStream aCompObj( *this, sal_True ); |
| aCompObj.GetClsId() = (const ClsId&) rClass.GetCLSID(); |
| aCompObj.GetCbFormat() = nOriginalClipFormat; |
| aCompObj.GetUserName() = rUserTypeName; |
| if( !aCompObj.Store() ) |
| SetError( aCompObj.GetError() ); |
| else |
| { |
| StgOleStream aOle( *this, STREAM_WRITE ); |
| if( !aOle.Store() ) |
| SetError( aOle.GetError() ); |
| } |
| } |
| else |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| } |
| |
| void Storage::SetConvertClass( const SvGlobalName & rConvertClass, |
| sal_uLong nOriginalClipFormat, |
| const String & rUserTypeName ) |
| { |
| if( Validate( sal_True ) ) |
| { |
| SetClass( rConvertClass, nOriginalClipFormat, rUserTypeName ); |
| // plus the convert flag: |
| StgOleStream aOle( *this, sal_True ); |
| aOle.GetFlags() |= 4; |
| if( !aOle.Store() ) |
| SetError( aOle.GetError() ); |
| } |
| } |
| |
| SvGlobalName Storage::GetClassName() |
| { |
| StgCompObjStream aCompObj( *this, sal_False ); |
| if( aCompObj.Load() ) |
| return SvGlobalName( (const CLSID&) aCompObj.GetClsId() ); |
| pIo->ResetError(); |
| |
| if ( pEntry ) |
| return SvGlobalName( (const CLSID&) pEntry->aEntry.GetClassId() ); |
| |
| return SvGlobalName(); |
| } |
| |
| sal_uLong Storage::GetFormat() |
| { |
| StgCompObjStream aCompObj( *this, sal_False ); |
| if( aCompObj.Load() ) |
| return aCompObj.GetCbFormat(); |
| pIo->ResetError(); |
| return 0; |
| } |
| |
| String Storage::GetUserName() |
| { |
| StgCompObjStream aCompObj( *this, sal_False ); |
| if( aCompObj.Load() ) |
| return aCompObj.GetUserName(); |
| pIo->ResetError(); |
| return String(); |
| } |
| |
| sal_Bool Storage::ShouldConvert() |
| { |
| StgOleStream aOle( *this, sal_False ); |
| if( aOle.Load() ) |
| return sal_Bool( ( aOle.GetFlags() & 4 ) != 0 ); |
| else |
| { |
| pIo->ResetError(); |
| return sal_False; |
| } |
| } |
| |
| sal_Bool Storage::ValidateFAT() |
| { |
| Link aLink = StgIo::GetErrorLink(); |
| ErrCode nErr = pIo->ValidateFATs(); |
| StgIo::SetErrorLink( aLink ); |
| return nErr == ERRCODE_NONE; |
| } |
| |
| void Storage::SetDirty() |
| { |
| if ( pEntry ) |
| pEntry->SetDirty(); |
| } |
| |
| void Storage::SetClassId( const ClsId& rId ) |
| { |
| if ( pEntry ) |
| pEntry->aEntry.SetClassId( rId ); |
| } |
| |
| const ClsId& Storage::GetClassId() const |
| { |
| if ( pEntry ) |
| return pEntry->aEntry.GetClassId(); |
| |
| static ClsId aDummyId = {0,0,0,0,0,0,0,0,0,0,0}; |
| return aDummyId; |
| } |
| |
| const SvStream* Storage::GetSvStream() const |
| { |
| return GetSvStream_Impl(); |
| } |
| |
| sal_Bool Storage::Validate( sal_Bool bValidate ) const |
| { |
| sal_Bool bRet = Validate_Impl( bValidate ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| sal_Bool Storage::ValidateMode( StreamMode nMode ) const |
| { |
| sal_Bool bRet = ValidateMode_Impl( nMode ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| sal_Bool Storage::ValidateMode( StreamMode nMode, StgDirEntry* p ) const |
| { |
| sal_Bool bRet = ValidateMode_Impl( nMode, p ); |
| if ( !bRet ) |
| SetError( SVSTREAM_ACCESS_DENIED ); |
| return bRet; |
| } |
| |
| sal_Bool Storage::Equals( const BaseStorage& rStorage ) const |
| { |
| const Storage* pOther = PTR_CAST( Storage, &rStorage ); |
| return pOther && ( pOther->pEntry == pEntry ); |
| } |
| |
| |