1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
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>
26 
27 #include <sot/stg.hxx>
28 #include "stgelem.hxx"
29 #include "stgdir.hxx"
30 #include "stgio.hxx"
31 #include "stgole.hxx"
32 
33 static tools::Long nTmpCount = 0;
34 
35 // The internal open mode is StreamMode::READ | StreamMode::TRUNC, which is silly
36 // by itself. It inhibits the checking of sharing modes and is used
37 // during CopyTo() and MoveTo() for opening a stream in read mode
38 // although it may be open in DENYALL mode
39 
40 #define INTERNAL_MODE ( StreamMode::READ | StreamMode::TRUNC )
41 
42 ///////////////////////// class StorageBase
43 
44 
StorageBase()45 StorageBase::StorageBase()
46     : m_bAutoCommit( false )
47 {
48     m_nMode  = StreamMode::READ;
49     m_nError = ERRCODE_NONE;
50 }
51 
~StorageBase()52 StorageBase::~StorageBase()
53 {
54 }
55 
56 // The following three methods are declared as const, since they
57 // may be called from within a const method.
58 
GetError() const59 ErrCode StorageBase::GetError() const
60 {
61     const ErrCode n = m_nError;
62     m_nError = ERRCODE_NONE;
63     return n;
64 }
65 
SetError(ErrCode n) const66 void StorageBase::SetError( ErrCode n ) const
67 {
68     if( !m_nError )
69         m_nError = n;
70 }
71 
ResetError() const72 void StorageBase::ResetError() const
73 {
74     m_nError = ERRCODE_NONE;
75 }
76 
OLEStorageBase(StgIo * p,StgDirEntry * pe,StreamMode & nMode)77 OLEStorageBase::OLEStorageBase( StgIo* p, StgDirEntry* pe, StreamMode& nMode )
78     : nStreamMode( nMode ), pIo( p ), pEntry( pe )
79 {
80     if ( p )
81         p->IncRef();
82     if( pe )
83         pe->m_nRefCnt++;
84 }
85 
~OLEStorageBase()86 OLEStorageBase::~OLEStorageBase()
87 {
88     if( pEntry )
89     {
90         DBG_ASSERT( pEntry->m_nRefCnt, "RefCount under 0" );
91         if( !--pEntry->m_nRefCnt )
92         {
93             if( pEntry->m_bZombie )
94                 delete pEntry;
95             else
96                 pEntry->Close();
97         }
98 
99         pEntry = nullptr;
100     }
101 
102 
103     if( pIo && !pIo->DecRef() )
104     {
105         delete pIo;
106         pIo = nullptr;
107     }
108 }
109 
110 // Validate the instance for I/O
111 
Validate_Impl(bool bWrite) const112 bool OLEStorageBase::Validate_Impl( bool bWrite ) const
113 {
114     return pIo
115         && pIo->m_pTOC
116         && pEntry
117         && !pEntry->m_bInvalid
118         &&  ( !bWrite || !pEntry->m_bDirect || ( nStreamMode & StreamMode::WRITE ) );
119 }
120 
ValidateMode_Impl(StreamMode m,StgDirEntry const * p)121 bool OLEStorageBase::ValidateMode_Impl( StreamMode m, StgDirEntry const * p )
122 {
123     if( m == INTERNAL_MODE )
124         return true;
125     StreamMode nCurMode = ( p && p->m_nRefCnt ) ? p->m_nMode : StreamMode::SHARE_DENYALL;
126     if( ( m & StreamMode::READWRITE ) == StreamMode::READ )
127     {
128         // only SHARE_DENYWRITE or SHARE_DENYALL allowed
129         if( ( ( m & StreamMode::SHARE_DENYWRITE )
130            && ( nCurMode & StreamMode::SHARE_DENYWRITE ) )
131          || ( ( m & StreamMode::SHARE_DENYALL )
132            && ( nCurMode & StreamMode::SHARE_DENYALL ) ) )
133             return true;
134     }
135     else
136     {
137         // only SHARE_DENYALL allowed
138         // storages open in r/o mode are OK, since only
139         // the commit may fail
140         if( ( m & StreamMode::SHARE_DENYALL )
141          && ( nCurMode & StreamMode::SHARE_DENYALL ) )
142             return true;
143     }
144     return false;
145 }
146 
147 
148 //////////////////////// class StorageStream
149 
150 
StorageStream(StgIo * p,StgDirEntry * q,StreamMode m)151 StorageStream::StorageStream( StgIo* p, StgDirEntry* q, StreamMode m )
152              : OLEStorageBase( p, q, m_nMode ), nPos( 0 )
153 {
154     // The dir entry may be 0; this means that the stream is invalid.
155     if( q && p )
156     {
157         if( q->m_nRefCnt == 1 )
158         {
159             q->m_nMode = m;
160             q->OpenStream( *p );
161         }
162     }
163     else
164         m &= ~StreamMode::READWRITE;
165     m_nMode = m;
166 }
167 
~StorageStream()168 StorageStream::~StorageStream()
169 {
170     // Do an auto-commit if the entry is open in direct mode
171     if( m_bAutoCommit )
172         Commit();
173     if( pEntry && pEntry->m_nRefCnt && pEntry->m_bDirect && (m_nMode & StreamMode::WRITE) )
174         pEntry->Commit();
175 }
176 
Equals(const BaseStorageStream & rStream) const177 bool StorageStream::Equals( const BaseStorageStream& rStream ) const
178 {
179     const StorageStream* pOther =  dynamic_cast<const StorageStream*>( &rStream );
180     return pOther && ( pOther->pEntry == pEntry );
181 }
182 
Read(void * pData,sal_Int32 nSize)183 sal_Int32 StorageStream::Read( void* pData, sal_Int32 nSize )
184 {
185     if( Validate() )
186     {
187         pEntry->Seek( nPos );
188         nSize = pEntry->Read( pData, nSize );
189         pIo->MoveError( *this );
190         nPos += nSize;
191     }
192     else
193         nSize = 0;
194     return nSize;
195 }
196 
Write(const void * pData,sal_Int32 nSize)197 sal_Int32 StorageStream::Write( const void* pData, sal_Int32 nSize )
198 {
199     if( Validate( true ) )
200     {
201         pEntry->Seek( nPos );
202         nSize = pEntry->Write( pData, nSize );
203         pIo->MoveError( *this );
204         nPos += nSize;
205     }
206     else
207         nSize = 0;
208     return nSize;
209 }
210 
Seek(sal_uInt64 n)211 sal_uInt64 StorageStream::Seek( sal_uInt64 n )
212 {
213     if( Validate() )
214     {
215         nPos = pEntry->Seek( n );
216         return nPos;
217     }
218     else
219         return n;
220 }
221 
Flush()222 void StorageStream::Flush()
223 {
224     // Flushing means committing, since streams are never transacted
225     Commit();
226 }
227 
SetSize(sal_uInt64 nNewSize)228 bool StorageStream::SetSize( sal_uInt64 nNewSize )
229 {
230     if( Validate( true ) )
231     {
232         bool b = pEntry->SetSize( nNewSize );
233         pIo->MoveError( *this );
234         return b;
235     }
236     else
237         return false;
238 }
239 
GetSize() const240 sal_uInt64 StorageStream::GetSize() const
241 {
242     if( Validate() )
243         return pEntry->GetSize();
244     return 0;
245 }
246 
Commit()247 bool StorageStream::Commit()
248 {
249     if( !Validate() )
250         return false;
251     if( !( m_nMode & StreamMode::WRITE ) )
252     {
253         SetError( SVSTREAM_ACCESS_DENIED );
254         return false;
255     }
256     else
257     {
258         pEntry->Commit();
259         pIo->MoveError( *this );
260         return Good();
261     }
262 }
263 
CopyTo(BaseStorageStream * pDest)264 void StorageStream::CopyTo( BaseStorageStream* pDest )
265 {
266     if( !Validate() || !pDest || !pDest->Validate( true ) || Equals( *pDest ) )
267         return;
268     pEntry->Copy( *pDest );
269     pDest->Commit();
270     pIo->MoveError( *this );
271     SetError( pDest->GetError() );
272 }
273 
Validate(bool bValidate) const274 bool StorageStream::Validate( bool bValidate ) const
275 {
276     bool bRet = Validate_Impl( bValidate );
277     if ( !bRet )
278         SetError( SVSTREAM_ACCESS_DENIED );
279     return bRet;
280 }
281 
ValidateMode(StreamMode nMode) const282 bool StorageStream::ValidateMode( StreamMode nMode ) const
283 {
284     bool bRet = ValidateMode_Impl( nMode );
285     if ( !bRet )
286         SetError( SVSTREAM_ACCESS_DENIED );
287     return bRet;
288 }
289 
290 ///////////////////////// class SvStorageInfo
291 
SvStorageInfo(const StgDirEntry & rE)292 SvStorageInfo::SvStorageInfo( const StgDirEntry& rE )
293 {
294     rE.m_aEntry.GetName( aName );
295     bStorage = rE.m_aEntry.GetType() == STG_STORAGE;
296     bStream  = rE.m_aEntry.GetType() == STG_STREAM;
297     nSize    = bStorage ? 0 : rE.m_aEntry.GetSize();
298 }
299 
300 /////////////////////////// class Storage
301 
IsStorageFile(const OUString & rFileName)302 bool Storage::IsStorageFile( const OUString & rFileName )
303 {
304     StgIo aIo;
305     if( aIo.Open( rFileName, StreamMode::STD_READ ) )
306         return aIo.Load();
307     return false;
308 }
309 
IsStorageFile(SvStream * pStream)310 bool Storage::IsStorageFile( SvStream* pStream )
311 {
312     bool bRet = false;
313 
314     if ( pStream )
315     {
316         StgHeader aHdr;
317         sal_uInt64 nPos = pStream->Tell();
318         bRet = ( aHdr.Load( *pStream ) && aHdr.Check() );
319 
320         // It's not a stream error if it is too small for an OLE storage header
321         if ( pStream->GetErrorCode() == ERRCODE_IO_CANTSEEK )
322             pStream->ResetError();
323         pStream->Seek( nPos );
324     }
325 
326     return bRet;
327 }
328 
329 // Open the storage file. If writing is permitted and the file is not
330 // a storage file, initialize it.
331 
332 
Storage(const OUString & rFile,StreamMode m,bool bDirect)333 Storage::Storage( const OUString& rFile, StreamMode m, bool bDirect )
334     : OLEStorageBase( new StgIo, nullptr, m_nMode )
335     , aName( rFile ), bIsRoot( false )
336 {
337     bool bTemp = false;
338     if( aName.isEmpty() )
339     {
340         // no name = temporary name!
341         aName = utl::TempFile::CreateTempName();
342         bTemp = true;
343     }
344     // the root storage creates the I/O system
345     m_nMode = m;
346     if( pIo->Open( aName, m ) )
347     {
348         Init( ( m & ( StreamMode::TRUNC | StreamMode::NOCREATE ) ) == StreamMode::TRUNC );
349         if( pEntry )
350         {
351             pEntry->m_bDirect = bDirect;
352             pEntry->m_nMode = m;
353             pEntry->m_bTemp = bTemp;
354         }
355     }
356     else
357     {
358         pIo->MoveError( *this );
359         pEntry = nullptr;
360     }
361 }
362 
363 // Create a storage on a given stream.
364 
Storage(SvStream & r,bool bDirect)365 Storage::Storage( SvStream& r, bool bDirect )
366     : OLEStorageBase( new StgIo, nullptr, m_nMode )
367     , bIsRoot( false )
368 {
369     m_nMode = StreamMode::READ;
370     if( r.IsWritable() )
371         m_nMode = StreamMode::READ | StreamMode::WRITE;
372     if( r.GetError() == ERRCODE_NONE )
373     {
374         pIo->SetStrm( &r, false );
375         sal_uInt64 nSize = r.TellEnd();
376         r.Seek( 0 );
377         // Initializing is OK if the stream is empty
378         Init( nSize == 0 );
379         if( pEntry )
380         {
381             pEntry->m_bDirect = bDirect;
382             pEntry->m_nMode = m_nMode;
383         }
384         pIo->MoveError( *this );
385     }
386     else
387     {
388         SetError( r.GetError() );
389         pEntry = nullptr;
390     }
391 }
392 
393 
Storage(UCBStorageStream & rStrm,bool bDirect)394 Storage::Storage( UCBStorageStream& rStrm, bool bDirect )
395        : OLEStorageBase( new StgIo, nullptr, m_nMode ), bIsRoot( false )
396 {
397     m_nMode = StreamMode::READ;
398 
399     if ( rStrm.GetError() != ERRCODE_NONE )
400     {
401         SetError( rStrm.GetError() );
402         pEntry = nullptr;
403         return;
404     }
405 
406     SvStream* pStream = rStrm.GetModifySvStream();
407     if ( !pStream )
408     {
409         OSL_FAIL( "UCBStorageStream can not provide SvStream implementation!" );
410         SetError( SVSTREAM_GENERALERROR );
411         pEntry = nullptr;
412         return;
413     }
414 
415     if( pStream->IsWritable() )
416         m_nMode = StreamMode::READ | StreamMode::WRITE;
417 
418     pIo->SetStrm( &rStrm );
419 
420     sal_uInt64 nSize = pStream->TellEnd();
421     pStream->Seek( 0 );
422     // Initializing is OK if the stream is empty
423     Init( nSize == 0 );
424     if( pEntry )
425     {
426         pEntry->m_bDirect = bDirect;
427         pEntry->m_nMode = m_nMode;
428     }
429 
430     pIo->MoveError( *this );
431 }
432 
433 
434 // Perform common code for both ctors above.
435 
Init(bool bCreate)436 void Storage::Init( bool bCreate )
437 {
438     pEntry = nullptr;
439     bool bHdrLoaded = false;
440     bIsRoot = true;
441 
442     OSL_ENSURE( pIo, "The pointer may not be empty at this point!" );
443     if( pIo->Good() && pIo->GetStrm() )
444     {
445         sal_uInt64 nSize = pIo->GetStrm()->TellEnd();
446         pIo->GetStrm()->Seek( 0 );
447         if( nSize )
448         {
449             bHdrLoaded = pIo->Load();
450             if( !bHdrLoaded && !bCreate  )
451             {
452                 // File is not a storage and not empty; do not destroy!
453                 SetError( SVSTREAM_FILEFORMAT_ERROR );
454                 return;
455             }
456         }
457     }
458     // file is a storage, empty or should be overwritten
459     pIo->ResetError();
460     // we have to set up the data structures, since
461     // the file is empty
462     if( !bHdrLoaded )
463         pIo->Init();
464     if( pIo->Good() && pIo->m_pTOC )
465     {
466         pEntry = pIo->m_pTOC->GetRoot();
467         pEntry->m_nRefCnt++;
468     }
469 }
470 
471 // Internal ctor
472 
Storage(StgIo * p,StgDirEntry * q,StreamMode m)473 Storage::Storage( StgIo* p, StgDirEntry* q, StreamMode m )
474        : OLEStorageBase( p, q, m_nMode ), bIsRoot( false )
475 {
476     if( q )
477         q->m_aEntry.GetName( aName );
478     else
479         m &= ~StreamMode::READWRITE;
480     m_nMode   = m;
481     if( q && q->m_nRefCnt == 1 )
482         q->m_nMode = m;
483 }
484 
~Storage()485 Storage::~Storage()
486 {
487     // Invalidate all open substorages
488     if( m_bAutoCommit )
489         Commit();
490     if( pEntry )
491     {
492         // Do an auto-commit if the entry is open in direct mode
493         if( pEntry->m_nRefCnt && pEntry->m_bDirect && (m_nMode & StreamMode::WRITE) )
494             Commit();
495         if( pEntry->m_nRefCnt == 1 )
496             pEntry->Invalidate(false);
497     }
498     // close the stream is root storage
499     if( bIsRoot )
500         pIo->Close();
501     // remove the file if temporary root storage
502     if( bIsRoot && pEntry && pEntry->m_bTemp )
503     {
504         osl::File::remove( GetName() );
505     }
506 }
507 
GetName() const508 const OUString& Storage::GetName() const
509 {
510     if( !bIsRoot && Validate() )
511         pEntry->m_aEntry.GetName( const_cast<Storage*>(this)->aName );
512     return aName;
513 }
514 
515 // Fill in the info list for this storage
516 
FillInfoList(SvStorageInfoList * pList) const517 void Storage::FillInfoList( SvStorageInfoList* pList ) const
518 {
519     if( !(Validate() && pList) )
520         return;
521 
522     StgIterator aIter( *pEntry );
523     StgDirEntry* p = aIter.First();
524     while( p )
525     {
526         if( !p->m_bInvalid )
527         {
528             SvStorageInfo aInfo( *p );
529             pList->push_back( aInfo );
530         }
531         p = aIter.Next();
532     }
533 }
534 
535 // Open or create a substorage
536 
OpenUCBStorage(const OUString & rName,StreamMode m,bool bDirect)537 BaseStorage* Storage::OpenUCBStorage( const OUString& rName, StreamMode m, bool bDirect )
538 {
539     OSL_FAIL("Not supported!");
540     return OpenStorage( rName, m, bDirect );
541 }
542 
OpenOLEStorage(const OUString & rName,StreamMode m,bool bDirect)543 BaseStorage* Storage::OpenOLEStorage( const OUString& rName, StreamMode m, bool bDirect )
544 {
545     return OpenStorage( rName, m, bDirect );
546 }
547 
OpenStorage(const OUString & rName,StreamMode m,bool bDirect)548 BaseStorage* Storage::OpenStorage( const OUString& rName, StreamMode m, bool bDirect )
549 {
550     if( !Validate() || !ValidateMode( m ) )
551         return new Storage( pIo, nullptr, m );
552     if( bDirect && !pEntry->m_bDirect )
553         bDirect = false;
554 
555     StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
556     if( !p )
557     {
558         if( !( m & StreamMode::NOCREATE ) )
559         {
560             bool bTemp = false;
561             // create a new storage
562             OUString aNewName = rName;
563             if( aNewName.isEmpty() )
564             {
565                 aNewName = "Temp Stg " + OUString::number( ++nTmpCount );
566                 bTemp = true;
567             }
568             p = pIo->m_pTOC->Create( *pEntry, aNewName, STG_STORAGE );
569             if( p )
570                 p->m_bTemp = bTemp;
571         }
572         if( !p )
573             pIo->SetError( ( m & StreamMode::WRITE )
574                              ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
575     }
576     else if( !ValidateMode( m, p ) )
577         p = nullptr;
578     if( p && p->m_aEntry.GetType() != STG_STORAGE )
579     {
580         pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
581         p = nullptr;
582     }
583 
584     // Either direct or transacted mode is supported
585     if( p && pEntry->m_nRefCnt == 1 )
586         p->m_bDirect = bDirect;
587 
588     // Don't check direct conflict if opening readonly
589     if( p && (m & StreamMode::WRITE ))
590     {
591         if( p->m_bDirect != bDirect )
592             SetError( SVSTREAM_ACCESS_DENIED );
593     }
594     Storage* pStg = new Storage( pIo, p, m );
595     pIo->MoveError( *pStg );
596     if( m & StreamMode::WRITE ) pStg->m_bAutoCommit = true;
597     return pStg;
598 }
599 
600 // Open a stream
601 
OpenStream(const OUString & rName,StreamMode m,bool)602 BaseStorageStream* Storage::OpenStream( const OUString& rName, StreamMode m, bool )
603 {
604     if( !Validate() || !ValidateMode( m ) )
605         return new StorageStream( pIo, nullptr, m );
606     StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
607     bool bTemp = false;
608     if( !p )
609     {
610         if( !( m & StreamMode::NOCREATE ) )
611         {
612             // create a new stream
613             // make a name if the stream is temporary (has no name)
614             OUString aNewName( rName );
615             if( aNewName.isEmpty() )
616             {
617                 aNewName = "Temp Strm " + OUString::number( ++nTmpCount );
618                 bTemp = true;
619             }
620             p = pIo->m_pTOC->Create( *pEntry, aNewName, STG_STREAM );
621         }
622         if( !p )
623             pIo->SetError( ( m & StreamMode::WRITE )
624                            ? SVSTREAM_CANNOT_MAKE : SVSTREAM_FILE_NOT_FOUND );
625     }
626     else if( !ValidateMode( m, p ) )
627         p = nullptr;
628     if( p && p->m_aEntry.GetType() != STG_STREAM )
629     {
630         pIo->SetError( SVSTREAM_FILE_NOT_FOUND );
631         p = nullptr;
632     }
633     if( p )
634     {
635         p->m_bTemp = bTemp;
636         p->m_bDirect = pEntry->m_bDirect;
637     }
638     StorageStream* pStm = new StorageStream( pIo, p, m );
639     if( p && !p->m_bDirect )
640         pStm->SetAutoCommit( true );
641     pIo->MoveError( *pStm );
642     return pStm;
643 }
644 
645 // Delete a stream or substorage by setting the temp bit.
646 
Remove(const OUString & rName)647 void Storage::Remove( const OUString& rName )
648 {
649     if( !Validate( true ) )
650         return;
651     StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
652     if( p )
653     {
654         p->Invalidate( true );
655     }
656     else
657     {
658         SetError( SVSTREAM_FILE_NOT_FOUND );
659     }
660 }
661 
662 // Copy one element
663 
CopyTo(const OUString & rElem,BaseStorage * pDest,const OUString & rNew)664 bool Storage::CopyTo( const OUString& rElem, BaseStorage* pDest, const OUString& rNew )
665 {
666     if( !Validate() || !pDest || !pDest->Validate( true ) )
667         return false;
668     StgDirEntry* pElem = StgDirStrm::Find( *pEntry, rElem );
669     if( pElem )
670     {
671         if( pElem->m_aEntry.GetType() == STG_STORAGE )
672         {
673             // copy the entire storage
674             tools::SvRef<BaseStorage> p1 = OpenStorage( rElem, INTERNAL_MODE );
675             tools::SvRef<BaseStorage> p2 = pDest->OpenOLEStorage( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pEntry->m_bDirect );
676 
677             if ( p2 )
678             {
679                 ErrCode nTmpErr = p2->GetError();
680                 if( !nTmpErr )
681                 {
682                     p2->SetClassId( p1->GetClassId() );
683                     p1->CopyTo( p2.get() );
684                     SetError( p1->GetError() );
685 
686                     nTmpErr = p2->GetError();
687                     if( !nTmpErr )
688                         p2->Commit();
689                     else
690                         pDest->SetError( nTmpErr );
691                 }
692                 else
693                     pDest->SetError( nTmpErr );
694             }
695 
696             return Good() && pDest->Good();
697         }
698         else
699         {
700             // stream copy
701             tools::SvRef<BaseStorageStream> p1 = OpenStream( rElem, INTERNAL_MODE );
702             tools::SvRef<BaseStorageStream> p2 = pDest->OpenStream( rNew, StreamMode::WRITE | StreamMode::SHARE_DENYALL, pEntry->m_bDirect );
703 
704             if ( p2 )
705             {
706                 ErrCode nTmpErr = p2->GetError();
707                 if( !nTmpErr )
708                 {
709                     p1->CopyTo( p2.get() );
710                     SetError( p1->GetError() );
711 
712                     nTmpErr = p2->GetError();
713                     if( !nTmpErr )
714                         p2->Commit();
715                     else
716                         pDest->SetError( nTmpErr );
717                 }
718                 else
719                     pDest->SetError( nTmpErr );
720             }
721 
722             return Good() && pDest->Good();
723         }
724     }
725     SetError( SVSTREAM_FILE_NOT_FOUND );
726     return false;
727 }
728 
CopyTo(BaseStorage * pDest) const729 bool Storage::CopyTo( BaseStorage* pDest ) const
730 {
731     if( !Validate() || !pDest || !pDest->Validate( true ) || Equals( *pDest ) )
732     {
733         SetError( SVSTREAM_ACCESS_DENIED );
734         return false;
735     }
736     Storage* pThis = const_cast<Storage*>(this);
737     pDest->SetClassId( GetClassId() );
738     pDest->SetDirty();
739     SvStorageInfoList aList;
740     FillInfoList( &aList );
741     bool bRes = true;
742     for( size_t i = 0; i < aList.size() && bRes; i++ )
743     {
744         SvStorageInfo& rInfo = aList[ i ];
745         bRes = pThis->CopyTo( rInfo.GetName(), pDest, rInfo.GetName() );
746     }
747     if( !bRes )
748         SetError( pDest->GetError() );
749     return Good() && pDest->Good();
750 }
751 
IsStorage(const OUString & rName) const752 bool Storage::IsStorage( const OUString& rName ) const
753 {
754     if( Validate() )
755     {
756         StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
757         if( p )
758             return p->m_aEntry.GetType() == STG_STORAGE;
759     }
760     return false;
761 }
762 
IsStream(const OUString & rName) const763 bool Storage::IsStream( const OUString& rName ) const
764 {
765     if( Validate() )
766     {
767         StgDirEntry* p = StgDirStrm::Find( *pEntry, rName );
768         if( p )
769             return p->m_aEntry.GetType() == STG_STREAM;
770     }
771     return false;
772 }
773 
IsContained(const OUString & rName) const774 bool Storage::IsContained( const OUString& rName ) const
775 {
776     if( Validate() )
777         return StgDirStrm::Find( *pEntry, rName ) != nullptr;
778     else
779         return false;
780 }
781 
782 // Commit all sub-elements within this storage. If this is
783 // the root, commit the FAT, the TOC and the header as well.
784 
Commit()785 bool Storage::Commit()
786 {
787     bool bRes = true;
788     if( !Validate() )
789         return false;
790     if( !( m_nMode & StreamMode::WRITE ) )
791     {
792         SetError( SVSTREAM_ACCESS_DENIED );
793         return false;
794     }
795     else
796     {
797         // Also commit the sub-streams and Storages
798         StgIterator aIter( *pEntry );
799         for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() )
800             bRes = p->Commit();
801         if( bRes && bIsRoot )
802         {
803             bRes = pEntry->Commit();
804             if( bRes )
805                 bRes = pIo->CommitAll();
806         }
807         pIo->MoveError( *this );
808     }
809     return bRes;
810 }
811 
Revert()812 bool Storage::Revert()
813 {
814     return true;
815 }
816 
817 ///////////////////////////// OLE Support
818 
819 // Set the storage type
820 
SetClass(const SvGlobalName & rClass,SotClipboardFormatId nOriginalClipFormat,const OUString & rUserTypeName)821 void Storage::SetClass( const SvGlobalName & rClass,
822                         SotClipboardFormatId nOriginalClipFormat,
823                         const OUString & rUserTypeName )
824 {
825     if( Validate( true ) )
826     {
827         // set the class name in the root entry
828         pEntry->m_aEntry.SetClassId( rClass.GetCLSID() );
829         pEntry->SetDirty();
830         // then create the streams
831         StgCompObjStream aCompObj( *this, true );
832         aCompObj.GetClsId() = rClass.GetCLSID();
833         aCompObj.GetCbFormat() = nOriginalClipFormat;
834         aCompObj.GetUserName() = rUserTypeName;
835         if( !aCompObj.Store() )
836             SetError( aCompObj.GetError() );
837         else
838         {
839             StgOleStream aOle(*this);
840             if( !aOle.Store() )
841                 SetError( aOle.GetError() );
842         }
843     }
844     else
845         SetError( SVSTREAM_ACCESS_DENIED );
846 }
847 
GetClassName()848 SvGlobalName Storage::GetClassName()
849 {
850     StgCompObjStream aCompObj( *this, false );
851     if( aCompObj.Load() )
852         return SvGlobalName( aCompObj.GetClsId() );
853     pIo->ResetError();
854 
855     if ( pEntry )
856         return SvGlobalName( pEntry->m_aEntry.GetClassId() );
857 
858     return SvGlobalName();
859 }
860 
GetFormat()861 SotClipboardFormatId Storage::GetFormat()
862 {
863     StgCompObjStream aCompObj( *this, false );
864     if( aCompObj.Load() )
865         return aCompObj.GetCbFormat();
866     pIo->ResetError();
867     return SotClipboardFormatId::NONE;
868 }
869 
GetUserName()870 OUString Storage::GetUserName()
871 {
872     StgCompObjStream aCompObj( *this, false );
873     if( aCompObj.Load() )
874         return aCompObj.GetUserName();
875     pIo->ResetError();
876     return OUString();
877 }
878 
ValidateFAT()879 bool Storage::ValidateFAT()
880 {
881     FatError nErr = pIo->ValidateFATs();
882     return nErr == FatError::Ok;
883 }
884 
SetDirty()885 void Storage::SetDirty()
886 {
887     if ( pEntry )
888         pEntry->SetDirty();
889 }
890 
SetClassId(const ClsId & rId)891 void Storage::SetClassId( const ClsId& rId )
892 {
893     if ( pEntry )
894         pEntry->m_aEntry.SetClassId( rId );
895 }
896 
GetClassId() const897 const ClsId& Storage::GetClassId() const
898 {
899     if ( pEntry )
900         return pEntry->m_aEntry.GetClassId();
901 
902     static const ClsId aDummyId = {0,0,0,{0,0,0,0,0,0,0,0}};
903     return aDummyId;
904 }
905 
Validate(bool bValidate) const906 bool Storage::Validate( bool bValidate ) const
907 {
908     bool bRet = Validate_Impl( bValidate );
909     if ( !bRet )
910         SetError( SVSTREAM_ACCESS_DENIED );
911     return bRet;
912 }
913 
ValidateMode(StreamMode nMode) const914 bool Storage::ValidateMode( StreamMode nMode ) const
915 {
916     bool bRet = ValidateMode_Impl( nMode );
917     if ( !bRet )
918         SetError( SVSTREAM_ACCESS_DENIED );
919     return bRet;
920 }
921 
ValidateMode(StreamMode nMode,StgDirEntry const * p) const922 bool Storage::ValidateMode( StreamMode nMode, StgDirEntry const * p ) const
923 {
924     bool bRet = ValidateMode_Impl( nMode, p );
925     if ( !bRet )
926         SetError( SVSTREAM_ACCESS_DENIED );
927     return bRet;
928 }
929 
Equals(const BaseStorage & rStorage) const930 bool Storage::Equals( const BaseStorage& rStorage ) const
931 {
932     const Storage* pOther =  dynamic_cast<const Storage*>( &rStorage );
933     return pOther && ( pOther->pEntry == pEntry );
934 }
935 
936 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
937