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