summaryrefslogtreecommitdiffstats
path: root/sot/source/sdstor/stg.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sot/source/sdstor/stg.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sot/source/sdstor/stg.cxx')
-rw-r--r--sot/source/sdstor/stg.cxx939
1 files changed, 939 insertions, 0 deletions
diff --git a/sot/source/sdstor/stg.cxx b/sot/source/sdstor/stg.cxx
new file mode 100644
index 000000000..08af34309
--- /dev/null
+++ b/sot/source/sdstor/stg.cxx
@@ -0,0 +1,939 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <sot/storinfo.hxx>
+#include <osl/file.hxx>
+#include <unotools/tempfile.hxx>
+#include <tools/stream.hxx>
+#include <tools/debug.hxx>
+
+#include <sot/stg.hxx>
+#include <utility>
+#include "stgelem.hxx"
+#include "stgdir.hxx"
+#include "stgio.hxx"
+#include "stgole.hxx"
+
+static tools::Long nTmpCount = 0;
+
+// The internal open mode is StreamMode::READ | StreamMode::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 ( StreamMode::READ | StreamMode::TRUNC )
+
+///////////////////////// class StorageBase
+
+
+StorageBase::StorageBase()
+ : m_bAutoCommit( false )
+{
+ m_nMode = StreamMode::READ;
+ m_nError = ERRCODE_NONE;
+}
+
+StorageBase::~StorageBase()
+{
+}
+
+// The following three methods are declared as const, since they
+// may be called from within a const method.
+
+ErrCode StorageBase::GetError() const
+{
+ const ErrCode n = m_nError;
+ m_nError = ERRCODE_NONE;
+ return n;
+}
+
+void StorageBase::SetError( ErrCode n ) const
+{
+ if( !m_nError )
+ m_nError = n;
+}
+
+void StorageBase::ResetError() const
+{
+ m_nError = ERRCODE_NONE;
+}
+
+OLEStorageBase::OLEStorageBase( StgIo* p, StgDirEntry* pe, StreamMode& nMode )
+ : nStreamMode( nMode ), pIo( p ), pEntry( pe )
+{
+ if ( p )
+ p->IncRef();
+ if( pe )
+ pe->m_nRefCnt++;
+}
+
+OLEStorageBase::~OLEStorageBase()
+{
+ if( pEntry )
+ {
+ DBG_ASSERT( pEntry->m_nRefCnt, "RefCount under 0" );
+ if( !--pEntry->m_nRefCnt )
+ {
+ if( pEntry->m_bZombie )
+ delete pEntry;
+ else
+ pEntry->Close();
+ }
+
+ pEntry = nullptr;
+ }
+
+
+ if( pIo && !pIo->DecRef() )
+ {
+ delete pIo;
+ pIo = nullptr;
+ }
+}
+
+// Validate the instance for I/O
+
+bool OLEStorageBase::Validate_Impl( bool bWrite ) const
+{
+ return pIo
+ && pIo->m_pTOC
+ && pEntry
+ && !pEntry->m_bInvalid
+ && ( !bWrite || !pEntry->m_bDirect || ( nStreamMode & StreamMode::WRITE ) );
+}
+
+bool OLEStorageBase::ValidateMode_Impl( StreamMode m, StgDirEntry const * p )
+{
+ if( m == INTERNAL_MODE )
+ return true;
+ StreamMode nCurMode = ( p && p->m_nRefCnt ) ? p->m_nMode : StreamMode::SHARE_DENYALL;
+ if( ( m & StreamMode::READWRITE ) == StreamMode::READ )
+ {
+ // only SHARE_DENYWRITE or SHARE_DENYALL allowed
+ if( ( ( m & StreamMode::SHARE_DENYWRITE )
+ && ( nCurMode & StreamMode::SHARE_DENYWRITE ) )
+ || ( ( m & StreamMode::SHARE_DENYALL )
+ && ( nCurMode & StreamMode::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 & StreamMode::SHARE_DENYALL )
+ && ( nCurMode & StreamMode::SHARE_DENYALL ) )
+ return true;
+ }
+ return false;
+}
+
+
+//////////////////////// class StorageStream
+
+
+StorageStream::StorageStream( StgIo* p, StgDirEntry* q, StreamMode m )
+ : OLEStorageBase( p, q, m_nMode ), nPos( 0 )
+{
+ // The dir entry may be 0; this means that the stream is invalid.
+ if( q && p )
+ {
+ if( q->m_nRefCnt == 1 )
+ {
+ q->m_nMode = m;
+ q->OpenStream( *p );
+ }
+ }
+ else
+ m &= ~StreamMode::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->m_nRefCnt && pEntry->m_bDirect && (m_nMode & StreamMode::WRITE) )
+ pEntry->Commit();
+}
+
+bool StorageStream::Equals( const BaseStorageStream& rStream ) const
+{
+ const StorageStream* pOther = dynamic_cast<const StorageStream*>( &rStream );
+ return pOther && ( pOther->pEntry == pEntry );
+}
+
+sal_Int32 StorageStream::Read( void* pData, sal_Int32 nSize )
+{
+ if( Validate() )
+ {
+ pEntry->Seek( nPos );
+ nSize = pEntry->Read( pData, nSize );
+ pIo->MoveError( *this );
+ nPos += nSize;
+ }
+ else
+ nSize = 0;
+ return nSize;
+}
+
+sal_Int32 StorageStream::Write( const void* pData, sal_Int32 nSize )
+{
+ if( Validate( true ) )
+ {
+ pEntry->Seek( nPos );
+ nSize = pEntry->Write( pData, nSize );
+ pIo->MoveError( *this );
+ nPos += nSize;
+ }
+ else
+ nSize = 0;
+ return nSize;
+}
+
+sal_uInt64 StorageStream::Seek( sal_uInt64 n )
+{
+ if( Validate() )
+ {
+ nPos = pEntry->Seek( n );
+ return nPos;
+ }
+ else
+ return n;
+}
+
+void StorageStream::Flush()
+{
+ // Flushing means committing, since streams are never transacted
+ Commit();
+}
+
+bool StorageStream::SetSize( sal_uInt64 nNewSize )
+{
+ if( Validate( true ) )
+ {
+ bool b = pEntry->SetSize( nNewSize );
+ pIo->MoveError( *this );
+ return b;
+ }
+ else
+ return false;
+}
+
+sal_uInt64 StorageStream::GetSize() const
+{
+ if( Validate() )
+ return pEntry->GetSize();
+ return 0;
+}
+
+bool StorageStream::Commit()
+{
+ if( !Validate() )
+ return false;
+ if( !( m_nMode & StreamMode::WRITE ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return false;
+ }
+ else
+ {
+ pEntry->Commit();
+ pIo->MoveError( *this );
+ return Good();
+ }
+}
+
+void StorageStream::CopyTo( BaseStorageStream* pDest )
+{
+ if( !Validate() || !pDest || !pDest->Validate( true ) || Equals( *pDest ) )
+ return;
+ pEntry->Copy( *pDest );
+ pDest->Commit();
+ pIo->MoveError( *this );
+ SetError( pDest->GetError() );
+}
+
+bool StorageStream::Validate( bool bValidate ) const
+{
+ bool bRet = Validate_Impl( bValidate );
+ if ( !bRet )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return bRet;
+}
+
+bool StorageStream::ValidateMode( StreamMode nMode ) const
+{
+ bool bRet = ValidateMode_Impl( nMode );
+ if ( !bRet )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return bRet;
+}
+
+///////////////////////// class SvStorageInfo
+
+SvStorageInfo::SvStorageInfo( const StgDirEntry& rE )
+{
+ rE.m_aEntry.GetName( aName );
+ bStorage = rE.m_aEntry.GetType() == STG_STORAGE;
+ bStream = rE.m_aEntry.GetType() == STG_STREAM;
+ nSize = bStorage ? 0 : rE.m_aEntry.GetSize();
+}
+
+/////////////////////////// class Storage
+
+bool Storage::IsStorageFile( const OUString & rFileName )
+{
+ StgIo aIo;
+ if( aIo.Open( rFileName, StreamMode::STD_READ ) )
+ return aIo.Load();
+ return false;
+}
+
+bool Storage::IsStorageFile( SvStream* pStream )
+{
+ bool bRet = false;
+
+ if ( pStream )
+ {
+ StgHeader aHdr;
+ sal_uInt64 nPos = pStream->Tell();
+ bRet = ( aHdr.Load( *pStream ) && aHdr.Check() );
+
+ // It's not a stream error if it is too small for an 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.
+
+
+Storage::Storage( OUString aFile, StreamMode m, bool bDirect )
+ : OLEStorageBase( new StgIo, nullptr, m_nMode )
+ , aName(std::move( aFile )), bIsRoot( false )
+{
+ bool bTemp = false;
+ if( aName.isEmpty() )
+ {
+ // no name = temporary name!
+ aName = utl::TempFile::CreateTempName();
+ bTemp = true;
+ }
+ // the root storage creates the I/O system
+ m_nMode = m;
+ if( pIo->Open( aName, m ) )
+ {
+ Init( ( m & ( StreamMode::TRUNC | StreamMode::NOCREATE ) ) == StreamMode::TRUNC );
+ if( pEntry )
+ {
+ pEntry->m_bDirect = bDirect;
+ pEntry->m_nMode = m;
+ pEntry->m_bTemp = bTemp;
+ }
+ }
+ else
+ {
+ pIo->MoveError( *this );
+ pEntry = nullptr;
+ }
+}
+
+// Create a storage on a given stream.
+
+Storage::Storage( SvStream& r, bool bDirect )
+ : OLEStorageBase( new StgIo, nullptr, m_nMode )
+ , bIsRoot( false )
+{
+ m_nMode = StreamMode::READ;
+ if( r.IsWritable() )
+ m_nMode = StreamMode::READ | StreamMode::WRITE;
+ if( r.GetError() == ERRCODE_NONE )
+ {
+ pIo->SetStrm( &r, false );
+ sal_uInt64 nSize = r.TellEnd();
+ r.Seek( 0 );
+ // Initializing is OK if the stream is empty
+ Init( nSize == 0 );
+ if( pEntry )
+ {
+ pEntry->m_bDirect = bDirect;
+ pEntry->m_nMode = m_nMode;
+ }
+ pIo->MoveError( *this );
+ }
+ else
+ {
+ SetError( r.GetError() );
+ pEntry = nullptr;
+ }
+}
+
+
+Storage::Storage( UCBStorageStream& rStrm, bool bDirect )
+ : OLEStorageBase( new StgIo, nullptr, m_nMode ), bIsRoot( false )
+{
+ m_nMode = StreamMode::READ;
+
+ if ( rStrm.GetError() != ERRCODE_NONE )
+ {
+ SetError( rStrm.GetError() );
+ pEntry = nullptr;
+ return;
+ }
+
+ SvStream* pStream = rStrm.GetModifySvStream();
+ if ( !pStream )
+ {
+ OSL_FAIL( "UCBStorageStream can not provide SvStream implementation!" );
+ SetError( SVSTREAM_GENERALERROR );
+ pEntry = nullptr;
+ return;
+ }
+
+ if( pStream->IsWritable() )
+ m_nMode = StreamMode::READ | StreamMode::WRITE;
+
+ pIo->SetStrm( &rStrm );
+
+ sal_uInt64 nSize = pStream->TellEnd();
+ pStream->Seek( 0 );
+ // Initializing is OK if the stream is empty
+ Init( nSize == 0 );
+ if( pEntry )
+ {
+ pEntry->m_bDirect = bDirect;
+ pEntry->m_nMode = m_nMode;
+ }
+
+ pIo->MoveError( *this );
+}
+
+
+// Perform common code for both ctors above.
+
+void Storage::Init( bool bCreate )
+{
+ pEntry = nullptr;
+ bool bHdrLoaded = false;
+ bIsRoot = true;
+
+ OSL_ENSURE( pIo, "The pointer may not be empty at this point!" );
+ if( pIo->Good() && pIo->GetStrm() )
+ {
+ sal_uInt64 nSize = pIo->GetStrm()->TellEnd();
+ pIo->GetStrm()->Seek( 0 );
+ 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->m_pTOC )
+ {
+ pEntry = pIo->m_pTOC->GetRoot();
+ pEntry->m_nRefCnt++;
+ }
+}
+
+// Internal ctor
+
+Storage::Storage( StgIo* p, StgDirEntry* q, StreamMode m )
+ : OLEStorageBase( p, q, m_nMode ), bIsRoot( false )
+{
+ if( q )
+ q->m_aEntry.GetName( aName );
+ else
+ m &= ~StreamMode::READWRITE;
+ m_nMode = m;
+ if( q && q->m_nRefCnt == 1 )
+ q->m_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->m_nRefCnt && pEntry->m_bDirect && (m_nMode & StreamMode::WRITE) )
+ Commit();
+ if( pEntry->m_nRefCnt == 1 )
+ pEntry->Invalidate(false);
+ }
+ // close the stream is root storage
+ if( bIsRoot )
+ pIo->Close();
+ // remove the file if temporary root storage
+ if( bIsRoot && pEntry && pEntry->m_bTemp )
+ {
+ osl::File::remove( GetName() );
+ }
+}
+
+const OUString& Storage::GetName() const
+{
+ if( !bIsRoot && Validate() )
+ pEntry->m_aEntry.GetName( const_cast<Storage*>(this)->aName );
+ return aName;
+}
+
+// Fill in the info list for this storage
+
+void Storage::FillInfoList( SvStorageInfoList* pList ) const
+{
+ if( !(Validate() && pList) )
+ return;
+
+ StgIterator aIter( *pEntry );
+ StgDirEntry* p = aIter.First();
+ while( p )
+ {
+ if( !p->m_bInvalid )
+ {
+ SvStorageInfo aInfo( *p );
+ pList->push_back( aInfo );
+ }
+ p = aIter.Next();
+ }
+}
+
+// Open or create a substorage
+
+BaseStorage* Storage::OpenUCBStorage( const OUString& rName, StreamMode m, bool bDirect )
+{
+ OSL_FAIL("Not supported!");
+ return OpenStorage( rName, m, bDirect );
+}
+
+BaseStorage* Storage::OpenOLEStorage( const OUString& rName, StreamMode m, bool bDirect )
+{
+ return OpenStorage( rName, m, bDirect );
+}
+
+BaseStorage* Storage::OpenStorage( const OUString& rName, StreamMode m, bool bDirect )
+{
+ if( !Validate() || !ValidateMode( m ) )
+ return new Storage( pIo, nullptr, m );
+ if( bDirect && !pEntry->m_bDirect )
+ bDirect = false;
+
+ StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
+ if( !p )
+ {
+ if( !( m & StreamMode::NOCREATE ) )
+ {
+ bool bTemp = false;
+ // create a new storage
+ OUString aNewName = rName;
+ if( aNewName.isEmpty() )
+ {
+ aNewName = "Temp Stg " + OUString::number( ++nTmpCount );
+ bTemp = true;
+ }
+ p = pIo->m_pTOC->Create( *pEntry, aNewName, STG_STORAGE );
+ if( p )
+ p->m_bTemp = bTemp;
+ }
+ if( !p )
+ pIo->SetError( ( m & StreamMode::WRITE )
+ ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
+ }
+ else if( !ValidateMode( m, p ) )
+ p = nullptr;
+ if( p && p->m_aEntry.GetType() != STG_STORAGE )
+ {
+ pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
+ p = nullptr;
+ }
+
+ // Either direct or transacted mode is supported
+ if( p && pEntry->m_nRefCnt == 1 )
+ p->m_bDirect = bDirect;
+
+ // Don't check direct conflict if opening readonly
+ if( p && (m & StreamMode::WRITE ))
+ {
+ if( p->m_bDirect != bDirect )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ }
+ Storage* pStg = new Storage( pIo, p, m );
+ pIo->MoveError( *pStg );
+ if( m & StreamMode::WRITE ) pStg->m_bAutoCommit = true;
+ return pStg;
+}
+
+// Open a stream
+
+BaseStorageStream* Storage::OpenStream( const OUString& rName, StreamMode m, bool )
+{
+ if( !Validate() || !ValidateMode( m ) )
+ return new StorageStream( pIo, nullptr, m );
+ StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
+ bool bTemp = false;
+ if( !p )
+ {
+ if( !( m & StreamMode::NOCREATE ) )
+ {
+ // create a new stream
+ // make a name if the stream is temporary (has no name)
+ OUString aNewName( rName );
+ if( aNewName.isEmpty() )
+ {
+ aNewName = "Temp Strm " + OUString::number( ++nTmpCount );
+ bTemp = true;
+ }
+ p = pIo->m_pTOC->Create( *pEntry, aNewName, STG_STREAM );
+ }
+ if( !p )
+ pIo->SetError( ( m & StreamMode::WRITE )
+ ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
+ }
+ else if( !ValidateMode( m, p ) )
+ p = nullptr;
+ // coverity[Resource leak : FALSE] - "Create" method is called with STG_STREAM line 620,
+ // so we won't enter into this "if" block here.
+ if( p && p->m_aEntry.GetType() != STG_STREAM )
+ {
+ pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
+ p = nullptr;
+ }
+ if( p )
+ {
+ p->m_bTemp = bTemp;
+ p->m_bDirect = pEntry->m_bDirect;
+ }
+ StorageStream* pStm = new StorageStream( pIo, p, m );
+ if( p && !p->m_bDirect )
+ pStm->SetAutoCommit( true );
+ pIo->MoveError( *pStm );
+ return pStm;
+}
+
+// Delete a stream or substorage by setting the temp bit.
+
+void Storage::Remove( const OUString& rName )
+{
+ if( !Validate( true ) )
+ return;
+ StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
+ if( p )
+ {
+ p->Invalidate( true );
+ }
+ else
+ {
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+ }
+}
+
+// Copy one element
+
+bool Storage::CopyTo( const OUString& rElem, BaseStorage* pDest, const OUString& rNew )
+{
+ if( !Validate() || !pDest || !pDest->Validate( true ) )
+ return false;
+ StgDirEntry* pElem = StgDirStrm::Find( *pEntry, rElem );
+ if( pElem )
+ {
+ if( pElem->m_aEntry.GetType() == STG_STORAGE )
+ {
+ // copy the entire storage
+ tools::SvRef<BaseStorage> p1 = OpenStorage( rElem, INTERNAL_MODE );
+ tools::SvRef<BaseStorage> p2 = pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pEntry->m_bDirect );
+
+ if ( p2 )
+ {
+ ErrCode nTmpErr = p2->GetError();
+ if( !nTmpErr )
+ {
+ p2->SetClassId( p1->GetClassId() );
+ p1->CopyTo( p2.get() );
+ SetError( p1->GetError() );
+
+ nTmpErr = p2->GetError();
+ if( !nTmpErr )
+ p2->Commit();
+ else
+ pDest->SetError( nTmpErr );
+ }
+ else
+ pDest->SetError( nTmpErr );
+ }
+
+ return Good() && pDest->Good();
+ }
+ else
+ {
+ // stream copy
+ tools::SvRef<BaseStorageStream> p1 = OpenStream( rElem, INTERNAL_MODE );
+ tools::SvRef<BaseStorageStream> p2 = pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pEntry->m_bDirect );
+
+ if ( p2 )
+ {
+ ErrCode nTmpErr = p2->GetError();
+ if( !nTmpErr )
+ {
+ p1->CopyTo( p2.get() );
+ SetError( p1->GetError() );
+
+ nTmpErr = p2->GetError();
+ if( !nTmpErr )
+ p2->Commit();
+ else
+ pDest->SetError( nTmpErr );
+ }
+ else
+ pDest->SetError( nTmpErr );
+ }
+
+ return Good() && pDest->Good();
+ }
+ }
+ SetError( SVSTREAM_FILE_NOT_FOUND );
+ return false;
+}
+
+bool Storage::CopyTo( BaseStorage* pDest ) const
+{
+ if( !Validate() || !pDest || !pDest->Validate( true ) || Equals( *pDest ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return false;
+ }
+ Storage* pThis = const_cast<Storage*>(this);
+ pDest->SetClassId( GetClassId() );
+ pDest->SetDirty();
+ SvStorageInfoList aList;
+ FillInfoList( &aList );
+ bool bRes = true;
+ for( size_t i = 0; i < aList.size() && bRes; i++ )
+ {
+ SvStorageInfo& rInfo = aList[ i ];
+ bRes = pThis->CopyTo( rInfo.GetName(), pDest, rInfo.GetName() );
+ }
+ if( !bRes )
+ SetError( pDest->GetError() );
+ return Good() && pDest->Good();
+}
+
+bool Storage::IsStorage( const OUString& rName ) const
+{
+ if( Validate() )
+ {
+ StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
+ if( p )
+ return p->m_aEntry.GetType() == STG_STORAGE;
+ }
+ return false;
+}
+
+bool Storage::IsStream( const OUString& rName ) const
+{
+ if( Validate() )
+ {
+ StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
+ if( p )
+ return p->m_aEntry.GetType() == STG_STREAM;
+ }
+ return false;
+}
+
+bool Storage::IsContained( const OUString& rName ) const
+{
+ if( Validate() )
+ return StgDirStrm::Find( *pEntry, rName ) != nullptr;
+ else
+ return false;
+}
+
+// Commit all sub-elements within this storage. If this is
+// the root, commit the FAT, the TOC and the header as well.
+
+bool Storage::Commit()
+{
+ bool bRes = true;
+ if( !Validate() )
+ return false;
+ if( !( m_nMode & StreamMode::WRITE ) )
+ {
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return 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;
+}
+
+bool Storage::Revert()
+{
+ return true;
+}
+
+///////////////////////////// OLE Support
+
+// Set the storage type
+
+void Storage::SetClass( const SvGlobalName & rClass,
+ SotClipboardFormatId nOriginalClipFormat,
+ const OUString & rUserTypeName )
+{
+ if( Validate( true ) )
+ {
+ // set the class name in the root entry
+ pEntry->m_aEntry.SetClassId( rClass.GetCLSID() );
+ pEntry->SetDirty();
+ // then create the streams
+ StgCompObjStream aCompObj( *this, true );
+ aCompObj.GetClsId() = rClass.GetCLSID();
+ aCompObj.GetCbFormat() = nOriginalClipFormat;
+ aCompObj.GetUserName() = rUserTypeName;
+ if( !aCompObj.Store() )
+ SetError( aCompObj.GetError() );
+ else
+ {
+ StgOleStream aOle(*this);
+ if( !aOle.Store() )
+ SetError( aOle.GetError() );
+ }
+ }
+ else
+ SetError( SVSTREAM_ACCESS_DENIED );
+}
+
+SvGlobalName Storage::GetClassName()
+{
+ StgCompObjStream aCompObj( *this, false );
+ if( aCompObj.Load() )
+ return SvGlobalName( aCompObj.GetClsId() );
+ pIo->ResetError();
+
+ if ( pEntry )
+ return SvGlobalName( pEntry->m_aEntry.GetClassId() );
+
+ return SvGlobalName();
+}
+
+SotClipboardFormatId Storage::GetFormat()
+{
+ StgCompObjStream aCompObj( *this, false );
+ if( aCompObj.Load() )
+ return aCompObj.GetCbFormat();
+ pIo->ResetError();
+ return SotClipboardFormatId::NONE;
+}
+
+OUString Storage::GetUserName()
+{
+ StgCompObjStream aCompObj( *this, false );
+ if( aCompObj.Load() )
+ return aCompObj.GetUserName();
+ pIo->ResetError();
+ return OUString();
+}
+
+bool Storage::ValidateFAT()
+{
+ FatError nErr = pIo->ValidateFATs();
+ return nErr == FatError::Ok;
+}
+
+void Storage::SetDirty()
+{
+ if ( pEntry )
+ pEntry->SetDirty();
+}
+
+void Storage::SetClassId( const ClsId& rId )
+{
+ if ( pEntry )
+ pEntry->m_aEntry.SetClassId( rId );
+}
+
+const ClsId& Storage::GetClassId() const
+{
+ if ( pEntry )
+ return pEntry->m_aEntry.GetClassId();
+
+ static const ClsId aDummyId = {0,0,0,{0,0,0,0,0,0,0,0}};
+ return aDummyId;
+}
+
+bool Storage::Validate( bool bValidate ) const
+{
+ bool bRet = Validate_Impl( bValidate );
+ if ( !bRet )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return bRet;
+}
+
+bool Storage::ValidateMode( StreamMode nMode ) const
+{
+ bool bRet = ValidateMode_Impl( nMode );
+ if ( !bRet )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return bRet;
+}
+
+bool Storage::ValidateMode( StreamMode nMode, StgDirEntry const * p ) const
+{
+ bool bRet = ValidateMode_Impl( nMode, p );
+ if ( !bRet )
+ SetError( SVSTREAM_ACCESS_DENIED );
+ return bRet;
+}
+
+bool Storage::Equals( const BaseStorage& rStorage ) const
+{
+ const Storage* pOther = dynamic_cast<const Storage*>( &rStorage );
+ return pOther && ( pOther->pEntry == pEntry );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */