1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sot/storinfo.hxx>
22 #include <osl/file.hxx>
23 #include <unotools/tempfile.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/debug.hxx>
27 #include <sot/stg.hxx>
29 #include "stgelem.hxx"
34 static tools::Long nTmpCount
= 0;
36 // The internal open mode is StreamMode::READ | StreamMode::TRUNC, which is silly
37 // by itself. It inhibits the checking of sharing modes and is used
38 // during CopyTo() and MoveTo() for opening a stream in read mode
39 // although it may be open in DENYALL mode
41 #define INTERNAL_MODE ( StreamMode::READ | StreamMode::TRUNC )
43 ///////////////////////// class StorageBase
46 StorageBase::StorageBase()
47 : m_bAutoCommit( false )
49 m_nMode
= StreamMode::READ
;
50 m_nError
= ERRCODE_NONE
;
53 StorageBase::~StorageBase()
57 // The following three methods are declared as const, since they
58 // may be called from within a const method.
60 ErrCode
StorageBase::GetError() const
62 const ErrCode n
= m_nError
;
63 m_nError
= ERRCODE_NONE
;
67 void StorageBase::SetError( ErrCode n
) const
73 void StorageBase::ResetError() const
75 m_nError
= ERRCODE_NONE
;
78 OLEStorageBase::OLEStorageBase( StgIo
* p
, StgDirEntry
* pe
, StreamMode
& nMode
)
79 : nStreamMode( nMode
), pIo( p
), pEntry( pe
)
87 OLEStorageBase::~OLEStorageBase()
91 DBG_ASSERT( pEntry
->m_nRefCnt
, "RefCount under 0" );
92 if( !--pEntry
->m_nRefCnt
)
94 if( pEntry
->m_bZombie
)
104 if( pIo
&& !pIo
->DecRef() )
111 // Validate the instance for I/O
113 bool OLEStorageBase::Validate_Impl( bool bWrite
) const
118 && !pEntry
->m_bInvalid
119 && ( !bWrite
|| !pEntry
->m_bDirect
|| ( nStreamMode
& StreamMode::WRITE
) );
122 bool OLEStorageBase::ValidateMode_Impl( StreamMode m
, StgDirEntry
const * p
)
124 if( m
== INTERNAL_MODE
)
126 StreamMode nCurMode
= ( p
&& p
->m_nRefCnt
) ? p
->m_nMode
: StreamMode::SHARE_DENYALL
;
127 if( ( m
& StreamMode::READWRITE
) == StreamMode::READ
)
129 // only SHARE_DENYWRITE or SHARE_DENYALL allowed
130 if( ( ( m
& StreamMode::SHARE_DENYWRITE
)
131 && ( nCurMode
& StreamMode::SHARE_DENYWRITE
) )
132 || ( ( m
& StreamMode::SHARE_DENYALL
)
133 && ( nCurMode
& StreamMode::SHARE_DENYALL
) ) )
138 // only SHARE_DENYALL allowed
139 // storages open in r/o mode are OK, since only
140 // the commit may fail
141 if( ( m
& StreamMode::SHARE_DENYALL
)
142 && ( nCurMode
& StreamMode::SHARE_DENYALL
) )
149 //////////////////////// class StorageStream
152 StorageStream::StorageStream( StgIo
* p
, StgDirEntry
* q
, StreamMode m
)
153 : OLEStorageBase( p
, q
, m_nMode
), nPos( 0 )
155 // The dir entry may be 0; this means that the stream is invalid.
158 if( q
->m_nRefCnt
== 1 )
165 m
&= ~StreamMode::READWRITE
;
169 StorageStream::~StorageStream()
171 // Do an auto-commit if the entry is open in direct mode
174 if( pEntry
&& pEntry
->m_nRefCnt
&& pEntry
->m_bDirect
&& (m_nMode
& StreamMode::WRITE
) )
178 bool StorageStream::Equals( const BaseStorageStream
& rStream
) const
180 const StorageStream
* pOther
= dynamic_cast<const StorageStream
*>( &rStream
);
181 return pOther
&& ( pOther
->pEntry
== pEntry
);
184 sal_Int32
StorageStream::Read( void* pData
, sal_Int32 nSize
)
188 pEntry
->Seek( nPos
);
189 nSize
= pEntry
->Read( pData
, nSize
);
190 pIo
->MoveError( *this );
198 sal_Int32
StorageStream::Write( const void* pData
, sal_Int32 nSize
)
200 if( Validate( true ) )
202 pEntry
->Seek( nPos
);
203 nSize
= pEntry
->Write( pData
, nSize
);
204 pIo
->MoveError( *this );
212 sal_uInt64
StorageStream::Seek( sal_uInt64 n
)
216 nPos
= pEntry
->Seek( n
);
223 void StorageStream::Flush()
225 // Flushing means committing, since streams are never transacted
229 bool StorageStream::SetSize( sal_uInt64 nNewSize
)
231 if( Validate( true ) )
233 bool b
= pEntry
->SetSize( nNewSize
);
234 pIo
->MoveError( *this );
241 sal_uInt64
StorageStream::GetSize() const
244 return pEntry
->GetSize();
248 bool StorageStream::Commit()
252 if( !( m_nMode
& StreamMode::WRITE
) )
254 SetError( SVSTREAM_ACCESS_DENIED
);
260 pIo
->MoveError( *this );
265 void StorageStream::CopyTo( BaseStorageStream
* pDest
)
267 if( !Validate() || !pDest
|| !pDest
->Validate( true ) || Equals( *pDest
) )
269 pEntry
->Copy( *pDest
);
271 pIo
->MoveError( *this );
272 SetError( pDest
->GetError() );
275 bool StorageStream::Validate( bool bValidate
) const
277 bool bRet
= Validate_Impl( bValidate
);
279 SetError( SVSTREAM_ACCESS_DENIED
);
283 bool StorageStream::ValidateMode( StreamMode nMode
) const
285 bool bRet
= ValidateMode_Impl( nMode
);
287 SetError( SVSTREAM_ACCESS_DENIED
);
291 ///////////////////////// class SvStorageInfo
293 SvStorageInfo::SvStorageInfo( const StgDirEntry
& rE
)
295 rE
.m_aEntry
.GetName( aName
);
296 bStorage
= rE
.m_aEntry
.GetType() == STG_STORAGE
;
297 bStream
= rE
.m_aEntry
.GetType() == STG_STREAM
;
298 nSize
= bStorage
? 0 : rE
.m_aEntry
.GetSize();
301 /////////////////////////// class Storage
303 bool Storage::IsStorageFile( const OUString
& rFileName
)
306 if( aIo
.Open( rFileName
, StreamMode::STD_READ
) )
311 bool Storage::IsStorageFile( SvStream
* pStream
)
318 sal_uInt64 nPos
= pStream
->Tell();
319 bRet
= ( aHdr
.Load( *pStream
) && aHdr
.Check() );
321 // It's not a stream error if it is too small for an OLE storage header
322 if ( pStream
->GetErrorCode() == ERRCODE_IO_CANTSEEK
)
323 pStream
->ResetError();
324 pStream
->Seek( nPos
);
330 // Open the storage file. If writing is permitted and the file is not
331 // a storage file, initialize it.
334 Storage::Storage( OUString aFile
, StreamMode m
, bool bDirect
)
335 : OLEStorageBase( new StgIo
, nullptr, m_nMode
)
336 , aName(std::move( aFile
)), bIsRoot( false )
339 if( aName
.isEmpty() )
341 // no name = temporary name!
342 aName
= utl::CreateTempName();
345 // the root storage creates the I/O system
347 if( pIo
->Open( aName
, m
) )
349 Init( ( m
& ( StreamMode::TRUNC
| StreamMode::NOCREATE
) ) == StreamMode::TRUNC
);
352 pEntry
->m_bDirect
= bDirect
;
354 pEntry
->m_bTemp
= bTemp
;
359 pIo
->MoveError( *this );
364 // Create a storage on a given stream.
366 Storage::Storage( SvStream
& r
, bool bDirect
)
367 : OLEStorageBase( new StgIo
, nullptr, m_nMode
)
370 m_nMode
= StreamMode::READ
;
372 m_nMode
= StreamMode::READ
| StreamMode::WRITE
;
373 if( r
.GetError() == ERRCODE_NONE
)
375 pIo
->SetStrm( &r
, false );
376 sal_uInt64 nSize
= r
.TellEnd();
378 // Initializing is OK if the stream is empty
382 pEntry
->m_bDirect
= bDirect
;
383 pEntry
->m_nMode
= m_nMode
;
385 pIo
->MoveError( *this );
389 SetError( r
.GetError() );
395 Storage::Storage( UCBStorageStream
& rStrm
, bool bDirect
)
396 : OLEStorageBase( new StgIo
, nullptr, m_nMode
), bIsRoot( false )
398 m_nMode
= StreamMode::READ
;
400 if ( rStrm
.GetError() != ERRCODE_NONE
)
402 SetError( rStrm
.GetError() );
407 SvStream
* pStream
= rStrm
.GetModifySvStream();
410 OSL_FAIL( "UCBStorageStream can not provide SvStream implementation!" );
411 SetError( SVSTREAM_GENERALERROR
);
416 if( pStream
->IsWritable() )
417 m_nMode
= StreamMode::READ
| StreamMode::WRITE
;
419 pIo
->SetStrm( &rStrm
);
421 sal_uInt64 nSize
= pStream
->TellEnd();
423 // Initializing is OK if the stream is empty
427 pEntry
->m_bDirect
= bDirect
;
428 pEntry
->m_nMode
= m_nMode
;
431 pIo
->MoveError( *this );
435 // Perform common code for both ctors above.
437 void Storage::Init( bool bCreate
)
440 bool bHdrLoaded
= false;
443 OSL_ENSURE( pIo
, "The pointer may not be empty at this point!" );
444 if( pIo
->Good() && pIo
->GetStrm() )
446 sal_uInt64 nSize
= pIo
->GetStrm()->TellEnd();
447 pIo
->GetStrm()->Seek( 0 );
450 bHdrLoaded
= pIo
->Load();
451 if( !bHdrLoaded
&& !bCreate
)
453 // File is not a storage and not empty; do not destroy!
454 SetError( SVSTREAM_FILEFORMAT_ERROR
);
459 // file is a storage, empty or should be overwritten
461 // we have to set up the data structures, since
465 if( pIo
->Good() && pIo
->m_pTOC
)
467 pEntry
= pIo
->m_pTOC
->GetRoot();
474 Storage::Storage( StgIo
* p
, StgDirEntry
* q
, StreamMode m
)
475 : OLEStorageBase( p
, q
, m_nMode
), bIsRoot( false )
478 q
->m_aEntry
.GetName( aName
);
480 m
&= ~StreamMode::READWRITE
;
482 if( q
&& q
->m_nRefCnt
== 1 )
488 // Invalidate all open substorages
493 // Do an auto-commit if the entry is open in direct mode
494 if( pEntry
->m_nRefCnt
&& pEntry
->m_bDirect
&& (m_nMode
& StreamMode::WRITE
) )
496 if( pEntry
->m_nRefCnt
== 1 )
497 pEntry
->Invalidate(false);
499 // close the stream is root storage
502 // remove the file if temporary root storage
503 if( bIsRoot
&& pEntry
&& pEntry
->m_bTemp
)
505 osl::File::remove( GetName() );
509 const OUString
& Storage::GetName() const
511 if( !bIsRoot
&& Validate() )
512 pEntry
->m_aEntry
.GetName( const_cast<Storage
*>(this)->aName
);
516 // Fill in the info list for this storage
518 void Storage::FillInfoList( SvStorageInfoList
* pList
) const
520 if( !(Validate() && pList
) )
523 StgIterator
aIter( *pEntry
);
524 StgDirEntry
* p
= aIter
.First();
529 SvStorageInfo
aInfo( *p
);
530 pList
->push_back( aInfo
);
536 // Open or create a substorage
538 BaseStorage
* Storage::OpenUCBStorage( const OUString
& rName
, StreamMode m
, bool bDirect
)
540 OSL_FAIL("Not supported!");
541 return OpenStorage( rName
, m
, bDirect
);
544 BaseStorage
* Storage::OpenOLEStorage( const OUString
& rName
, StreamMode m
, bool bDirect
)
546 return OpenStorage( rName
, m
, bDirect
);
549 BaseStorage
* Storage::OpenStorage( const OUString
& rName
, StreamMode m
, bool bDirect
)
551 if( !Validate() || !ValidateMode( m
) )
552 return new Storage( pIo
, nullptr, m
);
553 if( bDirect
&& !pEntry
->m_bDirect
)
556 StgDirEntry
* p
= StgDirStrm::Find( *pEntry
, rName
);
559 if( !( m
& StreamMode::NOCREATE
) )
562 // create a new storage
563 OUString aNewName
= rName
;
564 if( aNewName
.isEmpty() )
566 aNewName
= "Temp Stg " + OUString::number( ++nTmpCount
);
569 p
= pIo
->m_pTOC
->Create( *pEntry
, aNewName
, STG_STORAGE
);
574 pIo
->SetError( ( m
& StreamMode::WRITE
)
575 ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
577 else if( !ValidateMode( m
, p
) )
579 if( p
&& p
->m_aEntry
.GetType() != STG_STORAGE
)
581 pIo
->SetError( SVSTREAM_FILE_NOT_FOUND
);
582 // coverity[overwrite_var] - ownership is not here, but with StgDirStrm
586 // Either direct or transacted mode is supported
587 if( p
&& pEntry
->m_nRefCnt
== 1 )
588 p
->m_bDirect
= bDirect
;
590 // Don't check direct conflict if opening readonly
591 if( p
&& (m
& StreamMode::WRITE
))
593 if( p
->m_bDirect
!= bDirect
)
594 SetError( SVSTREAM_ACCESS_DENIED
);
596 Storage
* pStg
= new Storage( pIo
, p
, m
);
597 pIo
->MoveError( *pStg
);
598 if( m
& StreamMode::WRITE
) pStg
->m_bAutoCommit
= true;
604 BaseStorageStream
* Storage::OpenStream( const OUString
& rName
, StreamMode m
, bool )
606 if( !Validate() || !ValidateMode( m
) )
607 return new StorageStream( pIo
, nullptr, m
);
608 StgDirEntry
* p
= StgDirStrm::Find( *pEntry
, rName
);
612 if( !( m
& StreamMode::NOCREATE
) )
614 // create a new stream
615 // make a name if the stream is temporary (has no name)
616 OUString
aNewName( rName
);
617 if( aNewName
.isEmpty() )
619 aNewName
= "Temp Strm " + OUString::number( ++nTmpCount
);
622 p
= pIo
->m_pTOC
->Create( *pEntry
, aNewName
, STG_STREAM
);
625 pIo
->SetError( ( m
& StreamMode::WRITE
)
626 ? SVSTREAM_CANNOT_MAKE
: SVSTREAM_FILE_NOT_FOUND
);
628 else if( !ValidateMode( m
, p
) )
630 // coverity[Resource leak : FALSE] - "Create" method is called with STG_STREAM line 620,
631 // so we won't enter into this "if" block here.
632 if( p
&& p
->m_aEntry
.GetType() != STG_STREAM
)
634 pIo
->SetError( SVSTREAM_FILE_NOT_FOUND
);
640 p
->m_bDirect
= pEntry
->m_bDirect
;
642 StorageStream
* pStm
= new StorageStream( pIo
, p
, m
);
643 if( p
&& !p
->m_bDirect
)
644 pStm
->SetAutoCommit( true );
645 pIo
->MoveError( *pStm
);
649 // Delete a stream or substorage by setting the temp bit.
651 void Storage::Remove( const OUString
& rName
)
653 if( !Validate( true ) )
655 StgDirEntry
* p
= StgDirStrm::Find( *pEntry
, rName
);
658 p
->Invalidate( true );
662 SetError( SVSTREAM_FILE_NOT_FOUND
);
668 bool Storage::CopyTo( const OUString
& rElem
, BaseStorage
* pDest
, const OUString
& rNew
)
670 if( !Validate() || !pDest
|| !pDest
->Validate( true ) )
672 StgDirEntry
* pElem
= StgDirStrm::Find( *pEntry
, rElem
);
675 if( pElem
->m_aEntry
.GetType() == STG_STORAGE
)
677 // copy the entire storage
678 tools::SvRef
<BaseStorage
> p1
= OpenStorage( rElem
, INTERNAL_MODE
);
679 tools::SvRef
<BaseStorage
> p2
= pDest
->OpenOLEStorage( rNew
, StreamMode::WRITE
| StreamMode::SHARE_DENYALL
, pEntry
->m_bDirect
);
683 ErrCode nTmpErr
= p2
->GetError();
686 p2
->SetClassId( p1
->GetClassId() );
687 p1
->CopyTo( p2
.get() );
688 SetError( p1
->GetError() );
690 nTmpErr
= p2
->GetError();
694 pDest
->SetError( nTmpErr
);
697 pDest
->SetError( nTmpErr
);
700 return Good() && pDest
->Good();
705 tools::SvRef
<BaseStorageStream
> p1
= OpenStream( rElem
, INTERNAL_MODE
);
706 tools::SvRef
<BaseStorageStream
> p2
= pDest
->OpenStream( rNew
, StreamMode::WRITE
| StreamMode::SHARE_DENYALL
, pEntry
->m_bDirect
);
710 ErrCode nTmpErr
= p2
->GetError();
713 p1
->CopyTo( p2
.get() );
714 SetError( p1
->GetError() );
716 nTmpErr
= p2
->GetError();
720 pDest
->SetError( nTmpErr
);
723 pDest
->SetError( nTmpErr
);
726 return Good() && pDest
->Good();
729 SetError( SVSTREAM_FILE_NOT_FOUND
);
733 bool Storage::CopyTo( BaseStorage
* pDest
) const
735 if( !Validate() || !pDest
|| !pDest
->Validate( true ) || Equals( *pDest
) )
737 SetError( SVSTREAM_ACCESS_DENIED
);
740 Storage
* pThis
= const_cast<Storage
*>(this);
741 pDest
->SetClassId( GetClassId() );
743 SvStorageInfoList aList
;
744 FillInfoList( &aList
);
746 for( size_t i
= 0; i
< aList
.size() && bRes
; i
++ )
748 SvStorageInfo
& rInfo
= aList
[ i
];
749 bRes
= pThis
->CopyTo( rInfo
.GetName(), pDest
, rInfo
.GetName() );
752 SetError( pDest
->GetError() );
753 return Good() && pDest
->Good();
756 bool Storage::IsStorage( const OUString
& rName
) const
760 StgDirEntry
* p
= StgDirStrm::Find( *pEntry
, rName
);
762 return p
->m_aEntry
.GetType() == STG_STORAGE
;
767 bool Storage::IsStream( const OUString
& rName
) const
771 StgDirEntry
* p
= StgDirStrm::Find( *pEntry
, rName
);
773 return p
->m_aEntry
.GetType() == STG_STREAM
;
778 bool Storage::IsContained( const OUString
& rName
) const
781 return StgDirStrm::Find( *pEntry
, rName
) != nullptr;
786 // Commit all sub-elements within this storage. If this is
787 // the root, commit the FAT, the TOC and the header as well.
789 bool Storage::Commit()
794 if( !( m_nMode
& StreamMode::WRITE
) )
796 SetError( SVSTREAM_ACCESS_DENIED
);
801 // Also commit the sub-streams and Storages
802 StgIterator
aIter( *pEntry
);
803 for( StgDirEntry
* p
= aIter
.First(); p
&& bRes
; p
= aIter
.Next() )
805 if( bRes
&& bIsRoot
)
807 bRes
= pEntry
->Commit();
809 bRes
= pIo
->CommitAll();
811 pIo
->MoveError( *this );
816 bool Storage::Revert()
821 ///////////////////////////// OLE Support
823 // Set the storage type
825 void Storage::SetClass( const SvGlobalName
& rClass
,
826 SotClipboardFormatId nOriginalClipFormat
,
827 const OUString
& rUserTypeName
)
829 if( Validate( true ) )
831 // set the class name in the root entry
832 pEntry
->m_aEntry
.SetClassId( rClass
.GetCLSID() );
834 // then create the streams
835 StgCompObjStream
aCompObj( *this, true );
836 aCompObj
.GetClsId() = rClass
.GetCLSID();
837 aCompObj
.GetCbFormat() = nOriginalClipFormat
;
838 aCompObj
.GetUserName() = rUserTypeName
;
839 if( !aCompObj
.Store() )
840 SetError( aCompObj
.GetError() );
843 StgOleStream
aOle(*this);
845 SetError( aOle
.GetError() );
849 SetError( SVSTREAM_ACCESS_DENIED
);
852 SvGlobalName
Storage::GetClassName()
854 StgCompObjStream
aCompObj( *this, false );
855 if( aCompObj
.Load() )
856 return SvGlobalName( aCompObj
.GetClsId() );
860 return SvGlobalName( pEntry
->m_aEntry
.GetClassId() );
862 return SvGlobalName();
865 SotClipboardFormatId
Storage::GetFormat()
867 StgCompObjStream
aCompObj( *this, false );
868 if( aCompObj
.Load() )
869 return aCompObj
.GetCbFormat();
871 return SotClipboardFormatId::NONE
;
874 OUString
Storage::GetUserName()
876 StgCompObjStream
aCompObj( *this, false );
877 if( aCompObj
.Load() )
878 return aCompObj
.GetUserName();
883 bool Storage::ValidateFAT()
885 FatError nErr
= pIo
->ValidateFATs();
886 return nErr
== FatError::Ok
;
889 void Storage::SetDirty()
895 void Storage::SetClassId( const ClsId
& rId
)
898 pEntry
->m_aEntry
.SetClassId( rId
);
901 const ClsId
& Storage::GetClassId() const
904 return pEntry
->m_aEntry
.GetClassId();
906 static const ClsId aDummyId
= {0,0,0,{0,0,0,0,0,0,0,0}};
910 bool Storage::Validate( bool bValidate
) const
912 bool bRet
= Validate_Impl( bValidate
);
914 SetError( SVSTREAM_ACCESS_DENIED
);
918 bool Storage::ValidateMode( StreamMode nMode
) const
920 bool bRet
= ValidateMode_Impl( nMode
);
922 SetError( SVSTREAM_ACCESS_DENIED
);
926 bool Storage::ValidateMode( StreamMode nMode
, StgDirEntry
const * p
) const
928 bool bRet
= ValidateMode_Impl( nMode
, p
);
930 SetError( SVSTREAM_ACCESS_DENIED
);
934 bool Storage::Equals( const BaseStorage
& rStorage
) const
936 const Storage
* pOther
= dynamic_cast<const Storage
*>( &rStorage
);
937 return pOther
&& ( pOther
->pEntry
== pEntry
);
940 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */