LibreOffice Module sot (master) 1
stgdir.cxx
Go to the documentation of this file.
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/stg.hxx>
22#include "stgelem.hxx"
23#include "stgstrms.hxx"
24#include "stgdir.hxx"
25#include "stgio.hxx"
26
27#include <osl/diagnose.h>
28#include <sal/log.hxx>
29
30#include <memory>
31
33
34// This class holds the dir entry data and maintains dirty flags for both
35// the entry and the data.
36
37// Transacted mode for streams: On the first write, a temp stream pTmpStrm
38// is created and operated on. A commit moves pTmpStrm to pCurStrm, which
39// is used for subsequent reads. A new write creates a new copy of pTmpStrm
40// based on pCurStrm. Reverting throws away pTmpStrm.
41// Transacted mode for storages: A copy of the dir ents is kept in aSave.
42// Committing means copying aEntry to aSave. Reverting means to copy aSave
43// to aEntry, delete newly created entries and to reactivate removed entries.
44
45// Problem of implementation: No hierarchical commits. Therefore only
46// overall transaction-oriented or direct.
47
48StgDirEntry::StgDirEntry( const void* pBuffer, sal_uInt32 nBufferLen, sal_uInt64 nUnderlyingStreamSize, bool * pbOk )
49{
50 *pbOk = m_aEntry.Load( pBuffer, nBufferLen, nUnderlyingStreamSize );
51
53}
54
55StgDirEntry::StgDirEntry( const StgEntry& r ) : m_aEntry( r )
56{
58}
59
60// Helper for all ctors
61
63{
65 m_pUp =
66 m_pDown = nullptr;
67 m_pStgStrm = nullptr;
69 m_pTmpStrm = nullptr;
70 m_nPos =
71 m_nEntry =
72 m_nRefCnt = 0;
73 m_nMode = StreamMode::READ;
74 m_bDirect = true;
77 m_bTemp =
78 m_bDirty =
79 m_bZombie = false;
80}
81
83{
84 Close();
85 delete m_pCurStrm;
86 delete m_pStgStrm;
87 delete m_pDown;
88}
89
90// Comparison function
91
92sal_Int32 StgDirEntry::Compare( const StgAvlNode* p ) const
93{
94 sal_Int32 nResult = -1;
95 if ( p )
96 {
97 const StgDirEntry* pEntry = static_cast<const StgDirEntry*>(p);
98 nResult = m_aEntry.Compare( pEntry->m_aEntry );
99 }
100 return nResult;
101}
102
103// Enumerate the entry numbers.
104// n is incremented to show the total # of entries.
105// These number are later used as page numbers when storing
106// the TOC tree into the TOC stream. Remember that aSave is
107// stored, not aEntry.
108
109void StgDirEntry::Enum( sal_Int32& n )
110{
111 sal_Int32 nLeft = STG_FREE, nRight = STG_FREE, nDown = STG_FREE;
112 m_nEntry = n++;
113 if( m_pLeft )
114 {
115 static_cast<StgDirEntry*>(m_pLeft)->Enum( n );
116 nLeft = static_cast<StgDirEntry*>(m_pLeft)->m_nEntry;
117 }
118 if( m_pRight )
119 {
120 static_cast<StgDirEntry*>(m_pRight)->Enum( n );
121 nRight = static_cast<StgDirEntry*>(m_pRight)->m_nEntry;
122 }
123 if( m_pDown )
124 {
125 m_pDown->Enum( n ); nDown = m_pDown->m_nEntry;
126 }
127 m_aSave.SetLeaf( STG_LEFT, nLeft );
128 m_aSave.SetLeaf( STG_RIGHT, nRight );
129 m_aSave.SetLeaf( STG_CHILD, nDown );
130}
131
132// Delete all temporary entries before writing the TOC stream.
133// Until now Deltemp is never called with bForce True
134
135void StgDirEntry::DelTemp( bool bForce )
136{
137 if( m_pLeft )
138 static_cast<StgDirEntry*>(m_pLeft)->DelTemp( false );
139 if( m_pRight )
140 static_cast<StgDirEntry*>(m_pRight)->DelTemp( false );
141 if( m_pDown )
142 {
143 // If the storage is dead, of course all elements are dead, too
145 bForce = true;
146 m_pDown->DelTemp( bForce );
147 }
148 if( !( bForce || m_bInvalid ) || ( m_aEntry.GetType() == STG_ROOT ) )
149 return;
150
151 Close();
152 if( m_pUp )
153 {
154 // this deletes the element if refcnt == 0!
155 bool bDel = m_nRefCnt == 0;
156 StgAvlNode::Remove( reinterpret_cast<StgAvlNode**>(&m_pUp->m_pDown), this, bDel );
157 if( !bDel )
158 {
159 m_pLeft = m_pRight = m_pDown = nullptr;
160 m_bInvalid = m_bZombie = true;
161 }
162 }
163}
164
165// Save the tree into the given dir stream
166
168{
169 void* pEntry = rStrm.GetEntry( m_nEntry, true );
170 if( !pEntry )
171 return false;
172 // Do not store the current (maybe not committed) entry
173 m_aSave.Store( pEntry );
174 if( m_pLeft )
175 if( !static_cast<StgDirEntry*>(m_pLeft)->Store( rStrm ) )
176 return false;
177 if( m_pRight )
178 if( !static_cast<StgDirEntry*>(m_pRight)->Store( rStrm ) )
179 return false;
180 if( m_pDown && !m_pDown->Store( rStrm ) )
181 return false;
182 return true;
183}
184
186{
188 {
189 if( m_bInvalid )
190 {
191 // Delete the stream if needed
192 if( !m_pStgStrm )
193 {
194 OpenStream( rIo );
195 delete m_pStgStrm;
196 m_pStgStrm = nullptr;
197 }
198 else
199 m_pStgStrm->SetSize( 0 );
200 }
201 // or write the data stream
202 else if( !Tmp2Strm() )
203 return false;
204 }
205 return true;
206}
207
208// Save all dirty streams
209
211{
212 if( !StoreStream( rIo ) )
213 return false;
214 if( m_pLeft )
215 if( !static_cast<StgDirEntry*>(m_pLeft)->StoreStreams( rIo ) )
216 return false;
217 if( m_pRight )
218 if( !static_cast<StgDirEntry*>(m_pRight)->StoreStreams( rIo ) )
219 return false;
220 if( m_pDown )
221 if( !m_pDown->StoreStreams( rIo ) )
222 return false;
223 return true;
224}
225
226// Revert all directory entries after failure to write the TOC stream
227
229{
231 if( m_pLeft )
232 static_cast<StgDirEntry*>(m_pLeft)->RevertAll();
233 if( m_pRight )
234 static_cast<StgDirEntry*>(m_pRight)->RevertAll();
235 if( m_pDown )
237}
238
239// Look if any element of the tree is dirty
240
242{
243 if( m_bDirty || m_bInvalid )
244 return true;
245 if( m_pLeft && static_cast<StgDirEntry*>(m_pLeft)->IsDirty() )
246 return true;
247 if( m_pRight && static_cast<StgDirEntry*>(m_pRight)->IsDirty() )
248 return true;
249 if( m_pDown && m_pDown->IsDirty() )
250 return true;
251 return false;
252}
253
254// Set up a stream.
255
257{
258 sal_Int32 nThreshold = static_cast<sal_uInt16>(rIo.m_aHdr.GetThreshold());
259 delete m_pStgStrm;
260 if( m_aEntry.GetSize() < nThreshold )
261 m_pStgStrm = new StgSmallStrm( rIo, *this );
262 else
263 m_pStgStrm = new StgDataStrm( rIo, *this );
264 if( m_bInvalid && m_aEntry.GetSize() )
265 {
266 // This entry has invalid data, so delete that data
267 SetSize( 0 );
268// bRemoved = bInvalid = false;
269 }
270 m_nPos = 0;
271}
272
273// Close the open stream without committing. If the entry is marked as
274// temporary, delete it.
275// Do not delete pCurStrm here!
276// (TLX:??? At least pStgStrm must be deleted.)
277
279{
280 delete m_pTmpStrm;
281 m_pTmpStrm = nullptr;
282// nRefCnt = 0;
284}
285
286// Get the current stream size
287
288sal_Int32 StgDirEntry::GetSize() const
289{
290 sal_Int32 n;
291 if( m_pTmpStrm )
292 n = m_pTmpStrm->GetSize();
293 else if( m_pCurStrm )
294 n = m_pCurStrm->GetSize();
295 else n = m_aEntry.GetSize();
296 return n;
297}
298
299// Set the stream size. This means also creating a temp stream.
300
301bool StgDirEntry::SetSize( sal_Int32 nNewSize )
302{
303 if (
304 !( m_nMode & StreamMode::WRITE ) ||
305 (!m_bDirect && !m_pTmpStrm && !Strm2Tmp())
306 )
307 {
308 return false;
309 }
310
311 if( nNewSize < m_nPos )
312 m_nPos = nNewSize;
313 if( m_pTmpStrm )
314 {
315 m_pTmpStrm->SetSize( nNewSize );
317 return m_pTmpStrm->GetError() == ERRCODE_NONE;
318 }
319 else
320 {
321 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
322 if ( !m_pStgStrm )
323 return false;
324
325 bool bRes = false;
326 StgIo& rIo = m_pStgStrm->GetIo();
327 sal_Int32 nThreshold = rIo.m_aHdr.GetThreshold();
328 // ensure the correct storage stream!
329 StgStrm* pOld = nullptr;
330 sal_uInt16 nOldSize = 0;
331 if( nNewSize >= nThreshold && m_pStgStrm->IsSmallStrm() )
332 {
333 pOld = m_pStgStrm;
334 nOldSize = static_cast<sal_uInt16>(pOld->GetSize());
335 m_pStgStrm = new StgDataStrm( rIo, STG_EOF, 0 );
336 }
337 else if( nNewSize < nThreshold && !m_pStgStrm->IsSmallStrm() )
338 {
339 pOld = m_pStgStrm;
340 nOldSize = static_cast<sal_uInt16>(nNewSize);
341 m_pStgStrm = new StgSmallStrm( rIo, STG_EOF );
342 }
343 // now set the new size
344 if( m_pStgStrm->SetSize( nNewSize ) )
345 {
346 // did we create a new stream?
347 if( pOld )
348 {
349 // if so, we probably need to copy the old data
350 if( nOldSize )
351 {
352 std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ nOldSize ]);
353 pOld->Pos2Page( 0 );
354 m_pStgStrm->Pos2Page( 0 );
355 if( pOld->Read( pBuf.get(), nOldSize )
356 && m_pStgStrm->Write( pBuf.get(), nOldSize ) )
357 bRes = true;
358 }
359 else
360 bRes = true;
361 if( bRes )
362 {
363 pOld->SetSize( 0 );
364 delete pOld;
366 m_pStgStrm->SetEntry( *this );
367 }
368 else
369 {
370 m_pStgStrm->SetSize( 0 );
371 delete m_pStgStrm;
372 m_pStgStrm = pOld;
373 }
374 }
375 else
376 {
378 bRes = true;
379 }
380 }
381 return bRes;
382 }
383}
384
385// Seek. On negative values, seek to EOF.
386
387sal_Int32 StgDirEntry::Seek( sal_Int32 nNew )
388{
389 if( m_pTmpStrm )
390 {
391 if( nNew < 0 )
392 nNew = m_pTmpStrm->GetSize();
393 nNew = m_pTmpStrm->Seek( nNew );
394 }
395 else if( m_pCurStrm )
396 {
397 if( nNew < 0 )
398 nNew = m_pCurStrm->GetSize();
399 nNew = m_pCurStrm->Seek( nNew );
400 }
401 else
402 {
403 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
404 if ( !m_pStgStrm )
405 return m_nPos;
406
407 sal_Int32 nSize = m_aEntry.GetSize();
408
409 if( nNew < 0 )
410 nNew = nSize;
411
412 // try to enlarge, readonly streams do not allow this
413 if( nNew > nSize )
414 {
415 if ( !( m_nMode & StreamMode::WRITE ) || !SetSize( nNew ) )
416 {
417 return m_nPos;
418 }
419 else
420 return Seek( nNew );
421 }
422 m_pStgStrm->Pos2Page( nNew );
423 nNew = m_pStgStrm->GetPos();
424 }
425
426 m_nPos = nNew;
427 return m_nPos;
428}
429
430// Read
431
432sal_Int32 StgDirEntry::Read( void* p, sal_Int32 nLen )
433{
434 if( nLen <= 0 )
435 return 0;
436 if( m_pTmpStrm )
437 nLen = m_pTmpStrm->ReadBytes( p, nLen );
438 else if( m_pCurStrm )
439 nLen = m_pCurStrm->ReadBytes( p, nLen );
440 else
441 {
442 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
443 if ( !m_pStgStrm )
444 return 0;
445
446 nLen = m_pStgStrm->Read( p, nLen );
447 }
448
449 m_nPos += nLen;
450 return nLen;
451}
452
453// Write
454
455sal_Int32 StgDirEntry::Write( const void* p, sal_Int32 nLen )
456{
457 if( nLen <= 0 || !( m_nMode & StreamMode::WRITE ) )
458 return 0;
459
460 // Was this stream committed internally and reopened in direct mode?
461 if( m_bDirect && ( m_pCurStrm || m_pTmpStrm ) && !Tmp2Strm() )
462 return 0;
463 // Is this stream opened in transacted mode? Do we have to make a copy?
464 if( !m_bDirect && !m_pTmpStrm && !Strm2Tmp() )
465 return 0;
466
467 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
468 if ( !m_pStgStrm )
469 return 0;
470
471 if( m_pTmpStrm )
472 {
473 nLen = m_pTmpStrm->WriteBytes( p, nLen );
475 }
476 else
477 {
478 sal_Int32 nNew = m_nPos + nLen;
479 if( nNew > m_pStgStrm->GetSize() )
480 {
481 if( !SetSize( nNew ) )
482 return 0;
484 }
485 nLen = m_pStgStrm->Write( p, nLen );
486 }
487 m_nPos += nLen;
488 return nLen;
489}
490
492{
493 sal_Int32 n = GetSize();
494 if( !(rDest.SetSize( n ) && n) )
495 return;
496
497 sal_uInt64 Pos = rDest.Tell();
498 sal_uInt8 aTempBytes[ 4096 ];
499 void* p = static_cast<void*>( aTempBytes );
500 Seek( 0 );
501 rDest.Seek( 0 );
502 while( n )
503 {
504 sal_Int32 nn = n;
505 if( nn > 4096 )
506 nn = 4096;
507 if( Read( p, nn ) != nn )
508 break;
509 if( sal::static_int_cast<sal_Int32>(rDest.Write( p, nn )) != nn )
510 break;
511 n -= nn;
512 }
513 rDest.Seek( Pos ); // ?! Seems to be undocumented !
514}
515
516// Commit this entry
517
519{
520 // OSL_ENSURE( nMode & StreamMode::WRITE, "Trying to commit readonly stream!" );
521
523 bool bRes = true;
524 if( m_aEntry.GetType() == STG_STREAM )
525 {
526 if( m_pTmpStrm )
527 {
528 delete m_pCurStrm;
530 m_pTmpStrm = nullptr;
531 }
532 if( m_bRemoved )
533 // Delete the stream if needed
534 if( m_pStgStrm )
535 m_pStgStrm->SetSize( 0 );
536 }
537 else if( m_aEntry.GetType() == STG_STORAGE && m_bDirect && bRes )
538 {
539 StgIterator aIter( *this );
540 for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() )
541 bRes = p->Commit();
542 }
543 return bRes;
544}
545
546// Copy the stg stream to the temp stream
547
549{
550 if( !m_pTmpStrm )
551 {
552 sal_uInt64 n = 0;
553 if( m_pCurStrm )
554 {
555 // It was already committed once
558 return true;
559 n = 1; // indicates error
560 }
561 else
562 {
563 n = m_aEntry.GetSize();
564 m_pTmpStrm = new StgTmpStrm( n );
566 {
567 if( n )
568 {
569 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
570 if ( !m_pStgStrm )
571 return false;
572
573 sal_uInt8 aTempBytes[ 4096 ];
574 void* p = static_cast<void*>( aTempBytes );
575 m_pStgStrm->Pos2Page( 0 );
576 while( n )
577 {
578 sal_uInt64 nn = n;
579 if( nn > 4096 )
580 nn = 4096;
581 if( static_cast<sal_uInt64>(m_pStgStrm->Read( p, nn )) != nn )
582 break;
583 if (m_pTmpStrm->WriteBytes( p, nn ) != nn)
584 break;
585 n -= nn;
586 }
589 }
590 }
591 else
592 n = 1;
593 }
594
595 if( n )
596 {
597 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
598 if ( m_pStgStrm )
600
601 delete m_pTmpStrm;
602 m_pTmpStrm = nullptr;
603 return false;
604 }
605 }
606 return true;
607}
608
609// Copy the temp stream to the stg stream during the final commit
610
612{
613 // We did commit once, but have not written since then
614 if( !m_pTmpStrm )
615 {
617 m_pCurStrm = nullptr;
618 }
619 if( m_pTmpStrm )
620 {
621 OSL_ENSURE( m_pStgStrm, "The pointer may not be NULL!" );
622 if ( !m_pStgStrm )
623 return false;
624 sal_uInt64 n = m_pTmpStrm->GetSize();
625 std::unique_ptr<StgStrm> pNewStrm;
626 StgIo& rIo = m_pStgStrm->GetIo();
627 sal_uInt64 nThreshold = rIo.m_aHdr.GetThreshold();
628 if( n < nThreshold )
629 pNewStrm.reset(new StgSmallStrm( rIo, STG_EOF ));
630 else
631 pNewStrm.reset(new StgDataStrm( rIo, STG_EOF ));
632 if( pNewStrm->SetSize( n ) )
633 {
634 sal_uInt8 p[ 4096 ];
635 m_pTmpStrm->Seek( 0 );
636 while( n )
637 {
638 sal_uInt64 nn = n;
639 if( nn > 4096 )
640 nn = 4096;
641 if (m_pTmpStrm->ReadBytes( p, nn ) != nn)
642 break;
643 if( static_cast<sal_uInt64>(pNewStrm->Write( p, nn )) != nn )
644 break;
645 n -= nn;
646 }
647 if( n )
648 {
651 return false;
652 }
653 else
654 {
655 m_pStgStrm->SetSize( 0 );
656 delete m_pStgStrm;
657 m_pStgStrm = pNewStrm.release();
658 m_pStgStrm->SetEntry(*this);
660 delete m_pTmpStrm;
661 delete m_pCurStrm;
662 m_pTmpStrm = m_pCurStrm = nullptr;
664 }
665 }
666 }
667 return true;
668}
669
670// Invalidate all open entries by setting the RefCount to 0. If the bDel
671// flag is set, also set the invalid flag to indicate deletion during the
672// next dir stream flush.
673
674void StgDirEntry::Invalidate( bool bDel )
675{
676// nRefCnt = 0;
677 if( bDel )
678 m_bRemoved = m_bInvalid = true;
679 switch( m_aEntry.GetType() )
680 {
681 case STG_STORAGE:
682 case STG_ROOT:
683 {
684 StgIterator aIter( *this );
685 for( StgDirEntry* p = aIter.First(); p; p = aIter.Next() )
686 p->Invalidate( bDel );
687 break;
688 }
689 default:
690 break;
691 }
692}
693
695
696// This specialized stream is the maintenance stream for the directory tree.
697
699 : StgDataStrm( r, r.m_aHdr.GetTOCStart(), -1 )
700 , m_pRoot( nullptr )
701{
702 if( r.GetError() )
703 return;
704 if( m_nStart == STG_EOF )
705 {
706 StgEntry aRoot;
707 aRoot.Init();
708 static constexpr OUStringLiteral sRootEntry = u"Root Entry";
709 aRoot.SetName( sRootEntry );
710 aRoot.SetType( STG_ROOT );
711 m_pRoot = new StgDirEntry( std::move(aRoot) );
712 m_pRoot->SetDirty();
713 }
714 else
715 {
716 // temporarily use this instance as owner, so
717 // the TOC pages can be removed.
718 m_pEntry = reinterpret_cast<StgDirEntry*>(this); // just for a bit pattern
719 SetupEntry( 0, m_pRoot );
720 m_pEntry = nullptr;
721 }
722}
723
725{
726 delete m_pRoot;
727}
728
729// Recursively parse the directory tree during reading the TOC stream
730
731void StgDirStrm::SetupEntry( sal_Int32 n, StgDirEntry* pUpper )
732{
733 void* p = ( n == STG_FREE ) ? nullptr : GetEntry( n, false );
734 if( !p )
735 return;
736
737 SvStream *pUnderlyingStream = m_rIo.GetStrm();
738 sal_uInt64 nUnderlyingStreamSize = pUnderlyingStream->TellEnd();
739
740 bool bOk(false);
741 std::unique_ptr<StgDirEntry> pCur(new StgDirEntry( p, STGENTRY_SIZE, nUnderlyingStreamSize, &bOk ));
742
743 if( !bOk )
744 {
746 // an error occurred
747 return;
748 }
749
750 // better it is
751 if( !pUpper )
752 pCur->m_aEntry.SetType( STG_ROOT );
753
754 sal_Int32 nLeft = pCur->m_aEntry.GetLeaf( STG_LEFT );
755 sal_Int32 nRight = pCur->m_aEntry.GetLeaf( STG_RIGHT );
756 // substorage?
757 sal_Int32 nLeaf = STG_FREE;
758 if( pCur->m_aEntry.GetType() == STG_STORAGE || pCur->m_aEntry.GetType() == STG_ROOT )
759 {
760 nLeaf = pCur->m_aEntry.GetLeaf( STG_CHILD );
761 if (nLeaf != STG_FREE && nLeaf == n)
762 {
764 return;
765 }
766 }
767
768 if( !(nLeaf != 0 && nLeft != 0 && nRight != 0) )
769 return;
770
771 //fdo#41642
772 StgDirEntry *pUp = pUpper;
773 while (pUp)
774 {
775 if (pUp->m_aEntry.GetLeaf(STG_CHILD) == nLeaf)
776 {
777 SAL_WARN("sot", "Leaf node of upper StgDirEntry is same as current StgDirEntry's leaf node. Circular entry chain, discarding link");
778 return;
779 }
780 pUp = pUp->m_pUp;
781 }
782
784 ( reinterpret_cast<StgAvlNode**>( pUpper ? &pUpper->m_pDown : &m_pRoot ), pCur.get() ) )
785 {
786 pCur->m_pUp = pUpper;
787 }
788 else
789 {
790 // bnc#682484: There are some really broken docs out there
791 // that contain duplicate entries in 'Directory' section
792 // so don't set the error flag here and just skip those
793 // (was: rIo.SetError( SVSTREAM_CANNOT_MAKE );)
794 return;
795 }
796 SetupEntry( nLeft, pUpper );
797 SetupEntry( nRight, pUpper );
798 SetupEntry( nLeaf, pCur.release() );
799}
800
801// Extend or shrink the directory stream.
802
803bool StgDirStrm::SetSize( sal_Int32 nBytes )
804{
805 // Always allocate full pages
806 if ( nBytes < 0 )
807 nBytes = 0;
808
809 nBytes = ( ( nBytes + m_nPageSize - 1 ) / m_nPageSize ) * m_nPageSize;
810 return StgStrm::SetSize( nBytes );
811}
812
813// Save the TOC stream into a new substream after saving all data streams
814
816{
817 if( !m_pRoot || !m_pRoot->IsDirty() )
818 return true;
819 if( !m_pRoot->StoreStreams( m_rIo ) )
820 return false;
821 // After writing all streams, the data FAT stream has changed,
822 // so we have to commit the root again
823 m_pRoot->Commit();
824 // We want a completely new stream, so fake an empty stream
825 sal_Int32 nOldStart = m_nStart; // save for later deletion
826 sal_Int32 nOldSize = m_nSize;
828 m_nSize = 0;
829 SetPos(0, true);
830 m_nOffset = 0;
831 // Delete all temporary entries
832 m_pRoot->DelTemp( false );
833 // set the entry numbers
834 sal_Int32 n = 0;
835 m_pRoot->Enum( n );
836 if( !SetSize( n * STGENTRY_SIZE ) )
837 {
838 m_nStart = nOldStart; m_nSize = nOldSize;
840 return false;
841 }
842 // set up the cache elements for the new stream
843 if( !Copy( STG_FREE, m_nSize ) )
844 {
846 return false;
847 }
848 // Write the data to the new stream
849 if( !m_pRoot->Store( *this ) )
850 {
852 return false;
853 }
854 // fill any remaining entries with empty data
855 sal_Int32 ne = m_nSize / STGENTRY_SIZE;
856 StgEntry aEmpty;
857 aEmpty.Init();
858 while( n < ne )
859 {
860 void* p = GetEntry( n++, true );
861 if( !p )
862 {
864 return false;
865 }
866 aEmpty.Store( p );
867 }
868 // Now we can release the old stream
869 m_pFat->FreePages( nOldStart, true );
871 return true;
872}
873
874// Get a dir entry.
875
876void* StgDirStrm::GetEntry( sal_Int32 n, bool bDirty )
877{
878 return n < 0 || n >= m_nSize / STGENTRY_SIZE
879 ? nullptr : GetPtr( n * STGENTRY_SIZE, bDirty );
880}
881
882// Find a dir entry.
883
884StgDirEntry* StgDirStrm::Find( StgDirEntry& rStg, const OUString& rName )
885{
886 if( rStg.m_pDown )
887 {
888 StgEntry aEntry;
889 aEntry.Init();
890 aEntry.SetName( rName );
891 // Look in the directory attached to the entry
892 StgDirEntry aTest( std::move(aEntry) );
893 return static_cast<StgDirEntry*>( rStg.m_pDown->Find( &aTest ) );
894 }
895 else
896 return nullptr;
897}
898
899// Create a new entry.
900
901StgDirEntry* StgDirStrm::Create( StgDirEntry& rStg, const OUString& rName, StgEntryType eType )
902{
903 StgEntry aEntry;
904 aEntry.Init();
905 aEntry.SetType( eType );
906 aEntry.SetName( rName );
907 StgDirEntry* pRes = Find( rStg, rName );
908 if( pRes )
909 {
910 if( !pRes->m_bInvalid )
911 {
913 return nullptr;
914 }
915 pRes->m_bInvalid =
916 pRes->m_bRemoved =
917 pRes->m_bTemp = false;
918 pRes->m_bDirty = true;
919 return pRes;
920 }
921 else
922 {
923 std::unique_ptr<StgDirEntry> pNewRes(new StgDirEntry( std::move(aEntry) ));
924 if( StgAvlNode::Insert( reinterpret_cast<StgAvlNode**>(&rStg.m_pDown), pNewRes.get() ) )
925 {
926 pNewRes->m_pUp = &rStg;
927 pNewRes->m_bDirty = true;
928 }
929 else
930 {
932 pNewRes.reset();
933 }
934 return pNewRes.release();
935 }
936}
937
938/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual sal_uInt64 Tell()=0
virtual sal_uInt64 Seek(sal_uInt64 nPos)=0
virtual sal_Int32 Write(const void *pData, sal_Int32 nSize)=0
virtual bool SetSize(sal_uInt64 nNewSize)=0
static bool Remove(StgAvlNode **, StgAvlNode *, bool bDel)
Definition: stgavl.cxx:340
StgAvlNode * Find(StgAvlNode const *)
Definition: stgavl.cxx:36
static bool Insert(StgAvlNode **, StgAvlNode *)
Definition: stgavl.cxx:285
StgAvlNode * m_pLeft
Definition: stgavl.hxx:43
StgAvlNode * m_pRight
Definition: stgavl.hxx:43
SvStream * GetStrm()
Definition: stgcache.hxx:70
ErrCode const & GetError() const
Definition: stgcache.hxx:74
void SetError(ErrCode)
Definition: stgcache.cxx:401
void * GetPtr(sal_Int32 nPos, bool bDirty)
Definition: stgstrms.cxx:898
void Enum(sal_Int32 &)
Definition: stgdir.cxx:109
void RevertAll()
Definition: stgdir.cxx:228
bool m_bInvalid
Definition: stgdir.hxx:59
sal_Int32 m_nRefCnt
Definition: stgdir.hxx:54
void DelTemp(bool)
Definition: stgdir.cxx:135
void InitMembers()
Definition: stgdir.cxx:62
bool StoreStream(StgIo &)
Definition: stgdir.cxx:185
bool m_bDirect
Definition: stgdir.hxx:57
bool IsDirty()
Definition: stgdir.cxx:241
void Copy(BaseStorageStream &)
Definition: stgdir.cxx:491
bool m_bRemoved
Definition: stgdir.hxx:44
bool m_bZombie
Definition: stgdir.hxx:58
StreamMode m_nMode
Definition: stgdir.hxx:55
bool Store(StgDirStrm &)
Definition: stgdir.cxx:167
StgEntry m_aSave
Definition: stgdir.hxx:35
sal_Int32 Write(const void *, sal_Int32)
Definition: stgdir.cxx:455
bool m_bTemp
Definition: stgdir.hxx:56
void Close()
Definition: stgdir.cxx:278
StgEntry m_aEntry
Definition: stgdir.hxx:53
virtual ~StgDirEntry() override
Definition: stgdir.cxx:82
StgDirEntry * m_pDown
Definition: stgdir.hxx:37
bool SetSize(sal_Int32)
Definition: stgdir.cxx:301
StgTmpStrm * m_pCurStrm
Definition: stgdir.hxx:40
StgStrm * m_pStgStrm
Definition: stgdir.hxx:38
sal_Int32 Read(void *, sal_Int32)
Definition: stgdir.cxx:432
virtual sal_Int32 Compare(const StgAvlNode *) const override
Definition: stgdir.cxx:92
bool m_bDirty
Definition: stgdir.hxx:43
StgDirEntry(const void *pBuffer, sal_uInt32 nBufferLen, sal_uInt64 nUnderlyingStreamSize, bool *pbOk)
Definition: stgdir.cxx:48
StgTmpStrm * m_pTmpStrm
Definition: stgdir.hxx:39
StgDirEntry * m_pUp
Definition: stgdir.hxx:36
bool Commit()
Definition: stgdir.cxx:518
void Invalidate(bool)
Definition: stgdir.cxx:674
sal_Int32 m_nEntry
Definition: stgdir.hxx:41
sal_Int32 GetSize() const
Definition: stgdir.cxx:288
bool StoreStreams(StgIo &)
Definition: stgdir.cxx:210
bool Strm2Tmp()
Definition: stgdir.cxx:548
void SetDirty()
Definition: stgdir.hxx:70
sal_Int32 Seek(sal_Int32)
Definition: stgdir.cxx:387
sal_Int32 m_nPos
Definition: stgdir.hxx:42
void OpenStream(StgIo &)
Definition: stgdir.cxx:256
bool Tmp2Strm()
Definition: stgdir.cxx:611
bool Store()
Definition: stgdir.cxx:815
StgDirEntry * Create(StgDirEntry &, const OUString &, StgEntryType)
Definition: stgdir.cxx:901
void * GetEntry(sal_Int32 n, bool)
Definition: stgdir.cxx:876
StgDirStrm(StgIo &)
Definition: stgdir.cxx:698
void SetupEntry(sal_Int32, StgDirEntry *)
Definition: stgdir.cxx:731
virtual bool SetSize(sal_Int32) override
Definition: stgdir.cxx:803
virtual ~StgDirStrm() override
Definition: stgdir.cxx:724
static StgDirEntry * Find(StgDirEntry &, const OUString &)
Definition: stgdir.cxx:884
StgDirEntry * m_pRoot
Definition: stgdir.hxx:88
sal_Int32 Compare(const StgEntry &) const
Definition: stgelem.cxx:375
sal_Int32 GetSize() const
Definition: stgelem.hxx:130
void Store(void *)
Definition: stgelem.cxx:462
void SetLeaf(StgEntryRef, sal_Int32)
Definition: stgelem.cxx:349
sal_Int32 GetLeaf(StgEntryRef) const
Definition: stgelem.cxx:336
void SetName(const OUString &)
Definition: stgelem.cxx:315
StgEntryType GetType() const
Definition: stgelem.hxx:127
void Init()
Definition: stgelem.cxx:285
bool Load(const void *pBuffer, sal_uInt32 nBufSize, sal_uInt64 nUnderlyingStreamSize)
Definition: stgelem.cxx:386
void SetType(StgEntryType t)
Definition: stgelem.hxx:129
void SetTOCStart(sal_Int32 n)
Definition: stgelem.cxx:229
sal_Int32 GetThreshold() const
Definition: stgelem.hxx:71
Definition: stgio.hxx:42
StgHeader m_aHdr
Definition: stgio.hxx:48
StgDirEntry * Next()
Definition: stgdir.hxx:106
StgDirEntry * First()
Definition: stgdir.hxx:105
void SetEntry(StgDirEntry &)
Definition: stgstrms.cxx:341
virtual sal_Int32 Read(void *, sal_Int32)
Definition: stgstrms.hxx:95
sal_Int32 m_nPage
Definition: stgstrms.hxx:74
virtual sal_Int32 Write(const void *, sal_Int32)
Definition: stgstrms.hxx:96
void SetPos(sal_Int32 nPos, bool bValid)
Definition: stgstrms.hxx:81
virtual bool SetSize(sal_Int32)
Definition: stgstrms.cxx:528
sal_Int32 GetPos() const
Definition: stgstrms.hxx:86
sal_Int32 m_nStart
Definition: stgstrms.hxx:72
sal_Int32 GetSize() const
Definition: stgstrms.hxx:88
short m_nPageSize
Definition: stgstrms.hxx:76
StgIo & GetIo()
Definition: stgstrms.hxx:85
short m_nOffset
Definition: stgstrms.hxx:75
StgIo & m_rIo
Definition: stgstrms.hxx:69
sal_Int32 m_nSize
Definition: stgstrms.hxx:73
virtual bool IsSmallStrm() const
Definition: stgstrms.hxx:97
StgDirEntry * m_pEntry
Definition: stgstrms.hxx:71
std::unique_ptr< StgFAT > m_pFat
Definition: stgstrms.hxx:70
bool Copy(sal_Int32 nFrom, sal_Int32 nBytes)
Definition: stgstrms.cxx:496
virtual bool Pos2Page(sal_Int32 nBytePos)
Definition: stgstrms.cxx:396
virtual void SetSize(sal_uInt64) override
Definition: stgstrms.cxx:1220
bool Copy(StgTmpStrm &)
Definition: stgstrms.cxx:1170
sal_uInt64 GetSize() const
Definition: stgstrms.cxx:1208
virtual sal_uInt64 TellEnd()
std::size_t WriteBytes(const void *pData, std::size_t nSize)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
ErrCode GetError() const
float u
#define SVSTREAM_GENERALERROR
#define ERRCODE_NONE
#define SVSTREAM_CANNOT_MAKE
DocumentType eType
void * p
sal_Int64 n
#define SAL_WARN(area, stream)
void SvStream & rStrm
#define STG_FREE
Definition: stgelem.hxx:139
StgEntryType
Definition: stgelem.hxx:85
@ STG_STORAGE
Definition: stgelem.hxx:87
@ STG_STREAM
Definition: stgelem.hxx:88
@ STG_ROOT
Definition: stgelem.hxx:89
@ STG_RIGHT
Definition: stgelem.hxx:94
@ STG_CHILD
Definition: stgelem.hxx:95
@ STG_LEFT
Definition: stgelem.hxx:93
#define STGENTRY_SIZE
Definition: stgelem.hxx:99
#define STG_EOF
Definition: stgelem.hxx:140
unsigned char sal_uInt8