LCOV - code coverage report
Current view: top level - sot/source/sdstor - stgdir.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 344 557 61.8 %
Date: 2014-11-03 Functions: 33 38 86.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <string.h>
      22             : 
      23             : #include "sot/stg.hxx"
      24             : #include "stgelem.hxx"
      25             : #include "stgcache.hxx"
      26             : #include "stgstrms.hxx"
      27             : #include "stgdir.hxx"
      28             : #include "stgio.hxx"
      29             : #include <boost/scoped_array.hpp>
      30             : 
      31             : //////////////////////////// class StgDirEntry
      32             : 
      33             : // This class holds the dir entry data and maintains dirty flags for both
      34             : // the entry and the data.
      35             : 
      36             : // Transacted mode for streams: On the first write, a temp stream pTmpStrm
      37             : // is created and operated on. A commit moves pTmpStrm to pCurStrm, which
      38             : // is used for subsequent reads. A new write creates a new copy of pTmpStrm
      39             : // based on pCurStrm. Reverting throws away pTmpStrm.
      40             : // Transacted mode for storages: A copy of the dir ents is kept in aSave.
      41             : // Committing means copying aEntry to aSave. Reverting means to copy aSave
      42             : // to aEntry, delete newly created entries and to reactivate removed entries.
      43             : 
      44             : // Problem der Implementation: Keine Hierarchischen commits. Daher nur
      45             : // insgesamt transaktionsorientert oder direkt.
      46             : 
      47       10165 : StgDirEntry::StgDirEntry( const void* pBuffer, sal_uInt32 nBufferLen, bool * pbOk ) : StgAvlNode()
      48             : {
      49       10165 :     *pbOk = aEntry.Load( pBuffer, nBufferLen );
      50             : 
      51       10165 :     InitMembers();
      52       10165 : }
      53             : 
      54       31813 : StgDirEntry::StgDirEntry( const StgEntry& r ) : StgAvlNode(), aEntry( r )
      55             : {
      56       31813 :     InitMembers();
      57       31813 : }
      58             : 
      59             : // Helper for all ctors
      60             : 
      61       41978 : void StgDirEntry::InitMembers()
      62             : {
      63       41978 :     aSave       = aEntry;
      64             :     pUp         =
      65       41978 :     pDown       = NULL;
      66       41978 :     ppRoot      = NULL;
      67       41978 :     pStgStrm    = NULL;
      68             :     pCurStrm    =
      69       41978 :     pTmpStrm    = NULL;
      70             :     nPos        =
      71             :     nEntry      =
      72       41978 :     nRefCnt     = 0;
      73       41978 :     nMode       = STREAM_READ;
      74       41978 :     bDirect     = true;
      75             :     bInvalid    =
      76             :     bCreated    =
      77             :     bRenamed    =
      78             :     bRemoved    =
      79             :     bTemp       =
      80             :     bDirty      =
      81       41978 :     bZombie     = false;
      82       41978 : }
      83             : 
      84       98624 : StgDirEntry::~StgDirEntry()
      85             : {
      86       41978 :     Close();
      87       41978 :     delete pCurStrm;
      88       41978 :     delete pStgStrm;
      89       41978 :     delete pDown;
      90       56646 : }
      91             : 
      92             : // Comparison function
      93             : 
      94      220840 : short StgDirEntry::Compare( const StgAvlNode* p ) const
      95             : {
      96      220840 :     short nResult = -1;
      97      220840 :     if ( p )
      98             :     {
      99      220840 :         const StgDirEntry* pEntry = static_cast<const StgDirEntry*>(p);
     100      220840 :         nResult = aEntry.Compare( pEntry->aEntry );
     101             :     }
     102      220840 :     return nResult;
     103             : }
     104             : 
     105             : // Enumerate the entry numbers.
     106             : // n is incremented to show the total # of entries.
     107             : // These number are later used as page numbers when storing
     108             : // the TOC tree into the TOC stream. Remember that aSave is
     109             : // stored, not aEntry.
     110             : 
     111        4821 : void StgDirEntry::Enum( sal_Int32& n )
     112             : {
     113        4821 :     sal_Int32 nLeft = STG_FREE, nRight = STG_FREE, nDown = STG_FREE;
     114        4821 :     nEntry = n++;
     115        4821 :     if( pLeft )
     116             :     {
     117         194 :         static_cast<StgDirEntry*>(pLeft)->Enum( n );
     118         194 :         nLeft = static_cast<StgDirEntry*>(pLeft)->nEntry;
     119             :     }
     120        4821 :     if( pRight )
     121             :     {
     122        3430 :         static_cast<StgDirEntry*>(pRight)->Enum( n );
     123        3430 :         nRight = static_cast<StgDirEntry*>(pRight)->nEntry;
     124             :     }
     125        4821 :     if( pDown )
     126             :     {
     127         476 :         pDown->Enum( n ); nDown = pDown->nEntry;
     128             :     }
     129        4821 :     aSave.SetLeaf( STG_LEFT, nLeft );
     130        4821 :     aSave.SetLeaf( STG_RIGHT, nRight );
     131        4821 :     aSave.SetLeaf( STG_CHILD, nDown );
     132        4821 : }
     133             : 
     134             : // Delete all temporary entries before writing the TOC stream.
     135             : // Until now Deltem is never called with bForce True
     136             : 
     137        4849 : void StgDirEntry::DelTemp( bool bForce )
     138             : {
     139        4849 :     if( pLeft )
     140         222 :         static_cast<StgDirEntry*>(pLeft)->DelTemp( false );
     141        4849 :     if( pRight )
     142        3430 :         static_cast<StgDirEntry*>(pRight)->DelTemp( false );
     143        4849 :     if( pDown )
     144             :     {
     145             :         // If the storage is dead, of course all elements are dead, too
     146         476 :         if( bInvalid && aEntry.GetType() == STG_STORAGE )
     147           0 :             bForce = true;
     148         476 :         pDown->DelTemp( bForce );
     149             :     }
     150        9698 :     if( ( bForce || bInvalid )
     151        4877 :      && ( aEntry.GetType() != STG_ROOT ) /* && ( nRefCnt <= 1 ) */ )
     152             :     {
     153          28 :         Close();
     154          28 :         if( pUp )
     155             :         {
     156             :             // this deletes the element if refcnt == 0!
     157          28 :             bool bDel = nRefCnt == 0;
     158          28 :             StgAvlNode::Remove( (StgAvlNode**) &pUp->pDown, this, bDel );
     159          28 :             if( !bDel )
     160             :             {
     161           0 :                 pLeft = pRight = pDown = 0;
     162           0 :                 bInvalid = bZombie = true;
     163             :             }
     164             :         }
     165             :     }
     166        4849 : }
     167             : 
     168             : // Save the tree into the given dir stream
     169             : 
     170        4821 : bool StgDirEntry::Store( StgDirStrm& rStrm )
     171             : {
     172        4821 :     void* pEntry = rStrm.GetEntry( nEntry, true );
     173        4821 :     if( !pEntry )
     174           0 :         return false;
     175             :     // Do not store the current (maybe not commited) entry
     176        4821 :     aSave.Store( pEntry );
     177        4821 :     if( pLeft )
     178         194 :         if( !static_cast<StgDirEntry*>(pLeft)->Store( rStrm ) )
     179           0 :             return false;
     180        4821 :     if( pRight )
     181        3430 :         if( !static_cast<StgDirEntry*>(pRight)->Store( rStrm ) )
     182           0 :             return false;
     183        4821 :     if( pDown )
     184         476 :         if( !pDown->Store( rStrm ) )
     185           0 :             return false;
     186        4821 :     return true;
     187             : }
     188             : 
     189        4849 : bool StgDirEntry::StoreStream( StgIo& rIo )
     190             : {
     191        4849 :     if( aEntry.GetType() == STG_STREAM || aEntry.GetType() == STG_ROOT )
     192             :     {
     193        4715 :         if( bInvalid )
     194             :         {
     195             :             // Delete the stream if needed
     196          28 :             if( !pStgStrm )
     197             :             {
     198           0 :                 OpenStream( rIo );
     199           0 :                 delete pStgStrm, pStgStrm = NULL;
     200             :             }
     201             :             else
     202          28 :                 pStgStrm->SetSize( 0 );
     203             :         }
     204             :         // or write the data stream
     205        4687 :         else if( !Tmp2Strm() )
     206           0 :             return false;
     207             :     }
     208        4849 :     return true;
     209             : }
     210             : 
     211             : // Save all dirty streams
     212             : 
     213        4849 : bool StgDirEntry::StoreStreams( StgIo& rIo )
     214             : {
     215        4849 :     if( !StoreStream( rIo ) )
     216           0 :         return false;
     217        4849 :     if( pLeft )
     218         222 :         if( !static_cast<StgDirEntry*>(pLeft)->StoreStreams( rIo ) )
     219           0 :             return false;
     220        4849 :     if( pRight )
     221        3430 :         if( !static_cast<StgDirEntry*>(pRight)->StoreStreams( rIo ) )
     222           0 :             return false;
     223        4849 :     if( pDown )
     224         476 :         if( !pDown->StoreStreams( rIo ) )
     225           0 :             return false;
     226        4849 :     return true;
     227             : }
     228             : 
     229             : // Revert all directory entries after failure to write the TOC stream
     230             : 
     231           0 : void StgDirEntry::RevertAll()
     232             : {
     233           0 :     aEntry = aSave;
     234           0 :     if( pLeft )
     235           0 :         static_cast<StgDirEntry*>(pLeft)->RevertAll();
     236           0 :     if( pRight )
     237           0 :         static_cast<StgDirEntry*>(pRight)->RevertAll();
     238           0 :     if( pDown )
     239           0 :         pDown->RevertAll();
     240           0 : }
     241             : 
     242             : // Look if any element of the tree is dirty
     243             : 
     244         721 : bool StgDirEntry::IsDirty()
     245             : {
     246         721 :     if( bDirty || bInvalid )
     247         721 :         return true;
     248           0 :     if( pLeft && static_cast<StgDirEntry*>(pLeft)->IsDirty() )
     249           0 :         return true;
     250           0 :     if( pRight && static_cast<StgDirEntry*>(pRight)->IsDirty() )
     251           0 :         return true;
     252           0 :     if( pDown && pDown->IsDirty() )
     253           0 :         return true;
     254           0 :     return false;
     255             : }
     256             : 
     257             : // Set up a stream.
     258             : 
     259       11006 : void StgDirEntry::OpenStream( StgIo& rIo, bool bForceBig )
     260             : {
     261       11006 :     sal_Int32 nThreshold = (sal_uInt16) rIo.aHdr.GetThreshold();
     262       11006 :     delete pStgStrm;
     263       11006 :     if( !bForceBig && aEntry.GetSize() < nThreshold )
     264        9398 :         pStgStrm = new StgSmallStrm( rIo, *this );
     265             :     else
     266        1608 :         pStgStrm = new StgDataStrm( rIo, *this );
     267       11006 :     if( bInvalid && aEntry.GetSize() )
     268             :     {
     269             :         // This entry has invalid data, so delete that data
     270           0 :         SetSize( 0L );
     271             : //      bRemoved = bInvalid = false;
     272             :     }
     273       11006 :     nPos = 0;
     274       11006 : }
     275             : 
     276             : // Close the open stream without committing. If the entry is marked as
     277             : // temporary, delete it.
     278             : // Do not delete pCurStrm here!
     279             : // (TLX:??? Zumindest pStgStrm muss deleted werden.)
     280             : 
     281       54768 : void StgDirEntry::Close()
     282             : {
     283       54768 :     delete pTmpStrm;
     284       54768 :     pTmpStrm = NULL;
     285             : //  nRefCnt  = 0;
     286       54768 :     bInvalid = bTemp;
     287       54768 : }
     288             : 
     289             : // Get the current stream size
     290             : 
     291       25226 : sal_Int32 StgDirEntry::GetSize()
     292             : {
     293             :     sal_Int32 n;
     294       25226 :     if( pTmpStrm )
     295           0 :         n = pTmpStrm->GetSize();
     296       25226 :     else if( pCurStrm )
     297           0 :         n = pCurStrm->GetSize();
     298       25226 :     else n = aEntry.GetSize();
     299       25226 :     return n;
     300             : }
     301             : 
     302             : // Set the stream size. This means also creating a temp stream.
     303             : 
     304        2066 : bool StgDirEntry::SetSize( sal_Int32 nNewSize )
     305             : {
     306        2066 :     if (
     307        4132 :          !( nMode & STREAM_WRITE ) ||
     308        4132 :          (!bDirect && !pTmpStrm && !Strm2Tmp())
     309             :        )
     310             :     {
     311           0 :         return false;
     312             :     }
     313             : 
     314        2066 :     if( nNewSize < nPos )
     315           0 :         nPos = nNewSize;
     316        2066 :     if( pTmpStrm )
     317             :     {
     318        2066 :         pTmpStrm->SetSize( nNewSize );
     319        2066 :         pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
     320        2066 :         return pTmpStrm->GetError() == SVSTREAM_OK;
     321             :     }
     322             :     else
     323             :     {
     324             :         OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     325           0 :         if ( !pStgStrm )
     326           0 :             return false;
     327             : 
     328           0 :         bool bRes = false;
     329           0 :         StgIo& rIo = pStgStrm->GetIo();
     330           0 :         sal_Int32 nThreshold = rIo.aHdr.GetThreshold();
     331             :         // ensure the correct storage stream!
     332           0 :         StgStrm* pOld = NULL;
     333           0 :         sal_uInt16 nOldSize = 0;
     334           0 :         if( nNewSize >= nThreshold && pStgStrm->IsSmallStrm() )
     335             :         {
     336           0 :             pOld = pStgStrm;
     337           0 :             nOldSize = (sal_uInt16) pOld->GetSize();
     338           0 :             pStgStrm = new StgDataStrm( rIo, STG_EOF, 0 );
     339             :         }
     340           0 :         else if( nNewSize < nThreshold && !pStgStrm->IsSmallStrm() )
     341             :         {
     342           0 :             pOld = pStgStrm;
     343           0 :             nOldSize = (sal_uInt16) nNewSize;
     344           0 :             pStgStrm = new StgSmallStrm( rIo, STG_EOF, 0 );
     345             :         }
     346             :         // now set the new size
     347           0 :         if( pStgStrm->SetSize( nNewSize ) )
     348             :         {
     349             :             // did we create a new stream?
     350           0 :             if( pOld )
     351             :             {
     352             :                 // if so, we probably need to copy the old data
     353           0 :                 if( nOldSize )
     354             :                 {
     355           0 :                     boost::scoped_array<sal_uInt8> pBuf(new sal_uInt8[ nOldSize ]);
     356           0 :                     pOld->Pos2Page( 0L );
     357           0 :                     pStgStrm->Pos2Page( 0L );
     358           0 :                     if( pOld->Read( pBuf.get(), nOldSize )
     359           0 :                         && pStgStrm->Write( pBuf.get(), nOldSize ) )
     360           0 :                         bRes = true;
     361             :                 }
     362             :                 else
     363           0 :                     bRes = true;
     364           0 :                 if( bRes )
     365             :                 {
     366           0 :                     pOld->SetSize( 0 );
     367           0 :                     delete pOld;
     368           0 :                     pStgStrm->Pos2Page( nPos );
     369           0 :                     pStgStrm->SetEntry( *this );
     370             :                 }
     371             :                 else
     372             :                 {
     373           0 :                     pStgStrm->SetSize( 0 );
     374           0 :                     delete pStgStrm;
     375           0 :                     pStgStrm = pOld;
     376             :                 }
     377             :             }
     378             :             else
     379             :             {
     380           0 :                 pStgStrm->Pos2Page( nPos );
     381           0 :                 bRes = true;
     382             :             }
     383             :         }
     384           0 :         return bRes;
     385             :     }
     386             : }
     387             : 
     388             : // Seek. On negative values, seek to EOF.
     389             : 
     390     3806854 : sal_Int32 StgDirEntry::Seek( sal_Int32 nNew )
     391             : {
     392     3806854 :     if( pTmpStrm )
     393             :     {
     394       46600 :         if( nNew < 0 )
     395       14822 :             nNew = pTmpStrm->GetSize();
     396       46600 :         nNew = pTmpStrm->Seek( nNew );
     397             :     }
     398     3760254 :     else if( pCurStrm )
     399             :     {
     400         116 :         if( nNew < 0 )
     401           6 :             nNew = pCurStrm->GetSize();
     402         116 :         nNew = pCurStrm->Seek( nNew );
     403             :     }
     404             :     else
     405             :     {
     406             :         OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     407     3760138 :         if ( !pStgStrm )
     408           0 :             return nPos;
     409             : 
     410     3760138 :         sal_Int32 nSize = aEntry.GetSize();
     411             : 
     412     3760138 :         if( nNew < 0 )
     413        4698 :             nNew = nSize;
     414             : 
     415             :         // try to enlarge, the readonly streams should not allow this
     416     3760138 :         if( nNew > nSize )
     417             :         {
     418         888 :             if ( !( nMode & STREAM_WRITE ) || !SetSize( nNew ) )
     419             :             {
     420             :                 SAL_WARN_IF(!(nMode & STREAM_WRITE), "sot",
     421             :                     "Trying to resize readonly stream by seeking, could be a wrong offset: " << nNew);
     422         888 :                 return nPos;
     423             :             }
     424             :             else
     425           0 :                 return Seek( nNew );
     426             :         }
     427     3759250 :         pStgStrm->Pos2Page( nNew );
     428     3759250 :         nNew = pStgStrm->GetPos();
     429             :     }
     430             : 
     431     3805966 :     return nPos = nNew;
     432             : }
     433             : 
     434             : // Read
     435             : 
     436     2183038 : sal_Int32 StgDirEntry::Read( void* p, sal_Int32 nLen )
     437             : {
     438     2183038 :     if( nLen <= 0 )
     439          38 :         return 0;
     440     2183000 :     if( pTmpStrm )
     441           0 :         nLen = pTmpStrm->Read( p, nLen );
     442     2183000 :     else if( pCurStrm )
     443           0 :         nLen = pCurStrm->Read( p, nLen );
     444             :     else
     445             :     {
     446             :         OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     447     2183000 :         if ( !pStgStrm )
     448           0 :             return 0;
     449             : 
     450     2183000 :         nLen = pStgStrm->Read( p, nLen );
     451             :     }
     452             : 
     453     2183000 :     nPos += nLen;
     454     2183000 :     return nLen;
     455             : }
     456             : 
     457             : // Write
     458             : 
     459       21446 : sal_Int32 StgDirEntry::Write( const void* p, sal_Int32 nLen )
     460             : {
     461       21446 :     if( nLen <= 0 || !( nMode & STREAM_WRITE ) )
     462           0 :         return 0;
     463             : 
     464             :     // Was this stream committed internally and reopened in direct mode?
     465       21446 :     if( bDirect && ( pCurStrm || pTmpStrm ) && !Tmp2Strm() )
     466           0 :         return 0;
     467             :     // Is this stream opened in transacted mode? Do we have to make a copy?
     468       21446 :     if( !bDirect && !pTmpStrm && !Strm2Tmp() )
     469           0 :         return 0;
     470             : 
     471             :     OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     472       21446 :     if ( !pStgStrm )
     473           0 :         return 0;
     474             : 
     475       21446 :     if( pTmpStrm )
     476             :     {
     477       21446 :         nLen = pTmpStrm->Write( p, nLen );
     478       21446 :         pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
     479             :     }
     480             :     else
     481             :     {
     482           0 :         sal_Int32 nNew = nPos + nLen;
     483           0 :         if( nNew > pStgStrm->GetSize() )
     484             :         {
     485           0 :             if( !SetSize( nNew ) )
     486           0 :                 return 0L;
     487           0 :             pStgStrm->Pos2Page( nPos );
     488             :         }
     489           0 :         nLen = pStgStrm->Write( p, nLen );
     490             :     }
     491       21446 :     nPos += nLen;
     492       21446 :     return nLen;
     493             : }
     494             : 
     495        1916 : void StgDirEntry::Copy( BaseStorageStream& rDest )
     496             : {
     497        1916 :     sal_Int32 n = GetSize();
     498        1916 :     if( rDest.SetSize( n ) && n )
     499             :     {
     500        1854 :         sal_uLong Pos = rDest.Tell();
     501             :         sal_uInt8 aTempBytes[ 4096 ];
     502        1854 :         void* p = static_cast<void*>( aTempBytes );
     503        1854 :         Seek( 0L );
     504        1854 :         rDest.Seek( 0L );
     505        6106 :         while( n )
     506             :         {
     507        2398 :             sal_Int32 nn = n;
     508        2398 :             if( nn > 4096 )
     509         544 :                 nn = 4096;
     510        2398 :             if( Read( p, nn ) != nn )
     511           0 :                 break;
     512        2398 :             if( sal::static_int_cast<sal_Int32>(rDest.Write( p, nn )) != nn )
     513           0 :                 break;
     514        2398 :             n -= nn;
     515             :         }
     516        1854 :         rDest.Seek( Pos );             // ?! Seems to be undocumented !
     517             :     }
     518        1916 : }
     519             : 
     520             : // Commit this entry
     521             : 
     522       17387 : bool StgDirEntry::Commit()
     523             : {
     524             :     // OSL_ENSURE( nMode & STREAM_WRITE, "Trying to commit readonly stream!" );
     525             : 
     526       17387 :     aSave = aEntry;
     527       17387 :     bool bRes = true;
     528       17387 :     if( aEntry.GetType() == STG_STREAM )
     529             :     {
     530       15914 :         if( pTmpStrm )
     531        3962 :             delete pCurStrm, pCurStrm = pTmpStrm, pTmpStrm = NULL;
     532       15914 :         if( bRemoved )
     533             :             // Delete the stream if needed
     534          28 :             if( pStgStrm )
     535          28 :                 pStgStrm->SetSize( 0 );
     536             :     }
     537        1473 :     else if( aEntry.GetType() == STG_STORAGE && bDirect && bRes )
     538             :     {
     539          64 :         StgIterator aIter( *this );
     540         378 :         for( StgDirEntry* p = aIter.First(); p && bRes; p = aIter.Next() )
     541         314 :             bRes = p->Commit();
     542             :     }
     543       17387 :     return bRes;
     544             : }
     545             : 
     546             : // Revert the entry
     547             : 
     548           0 : bool StgDirEntry::Revert()
     549             : {
     550           0 :     aEntry = aSave;
     551           0 :     switch( aEntry.GetType() )
     552             :     {
     553             :         case STG_STREAM:
     554           0 :             if( pCurStrm )
     555           0 :                 delete pTmpStrm, pTmpStrm = pCurStrm, pCurStrm = NULL;
     556           0 :             break;
     557             :         case STG_STORAGE:
     558             :         {
     559           0 :             bool bSomeRenamed = false;
     560           0 :             StgIterator aOIter( *this );
     561           0 :             StgDirEntry* op = aOIter.First();
     562           0 :             while( op )
     563             :             {
     564           0 :                 op->aEntry = op->aSave;
     565           0 :                 op->bDirty = false;
     566           0 :                 bSomeRenamed = ( bSomeRenamed || op->bRenamed );
     567             :                 // Remove any new entries
     568           0 :                 if( op->bCreated )
     569             :                 {
     570           0 :                     op->bCreated = false;
     571           0 :                     op->Close();
     572           0 :                     op->bInvalid = true;
     573             :                 }
     574             :                 // Reactivate any removed entries
     575           0 :                 else if( op->bRemoved )
     576           0 :                     op->bRemoved = op->bInvalid = op->bTemp = false;
     577           0 :                 op = aOIter.Next();
     578             :             }
     579             :             // Resort all renamed entries
     580           0 :             if( bSomeRenamed )
     581             :             {
     582           0 :                 StgIterator aIter( *this );
     583           0 :                 StgDirEntry* p = aIter.First();
     584           0 :                 while( p )
     585             :                 {
     586           0 :                     if( p->bRenamed )
     587             :                     {
     588             :                         StgAvlNode::Move
     589             :                             ( (StgAvlNode**) &p->pUp->pDown,
     590           0 :                               (StgAvlNode**) &p->pUp->pDown, p );
     591           0 :                         p->bRenamed = false;
     592             :                     }
     593           0 :                     p = aIter.Next();
     594             :                 }
     595             :             }
     596           0 :             DelTemp( false );
     597           0 :             break;
     598             :         }
     599             :         case STG_EMPTY:
     600             :         case STG_LOCKBYTES:
     601             :         case STG_PROPERTY:
     602             :         case STG_ROOT:
     603           0 :          break;
     604             :     }
     605           0 :     return true;
     606             : }
     607             : 
     608             : // Copy the stg stream to the temp stream
     609             : 
     610        3962 : bool StgDirEntry::Strm2Tmp()
     611             : {
     612        3962 :     if( !pTmpStrm )
     613             :     {
     614        3962 :         sal_uLong n = 0;
     615        3962 :         if( pCurStrm )
     616             :         {
     617             :             // It was already commited once
     618          36 :             pTmpStrm = new StgTmpStrm;
     619          36 :             if( pTmpStrm->GetError() == SVSTREAM_OK && pTmpStrm->Copy( *pCurStrm ) )
     620          36 :                 return true;
     621           0 :             n = 1;  // indicates error
     622             :         }
     623             :         else
     624             :         {
     625        3926 :             n = aEntry.GetSize();
     626        3926 :             pTmpStrm = new StgTmpStrm( n );
     627        3926 :             if( pTmpStrm->GetError() == SVSTREAM_OK )
     628             :             {
     629        3926 :                 if( n )
     630             :                 {
     631             :                     OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     632           0 :                     if ( !pStgStrm )
     633           0 :                         return false;
     634             : 
     635             :                     sal_uInt8 aTempBytes[ 4096 ];
     636           0 :                     void* p = static_cast<void*>( aTempBytes );
     637           0 :                     pStgStrm->Pos2Page( 0L );
     638           0 :                     while( n )
     639             :                     {
     640           0 :                         sal_uLong nn = n;
     641           0 :                         if( nn > 4096 )
     642           0 :                             nn = 4096;
     643           0 :                         if( (sal_uLong) pStgStrm->Read( p, nn ) != nn )
     644           0 :                             break;
     645           0 :                         if( pTmpStrm->Write( p, nn ) != nn )
     646           0 :                             break;
     647           0 :                         n -= nn;
     648             :                     }
     649           0 :                     pStgStrm->Pos2Page( nPos );
     650           0 :                     pTmpStrm->Seek( nPos );
     651             :                 }
     652             :             }
     653             :             else
     654           0 :                 n = 1;
     655             :         }
     656             : 
     657        3926 :         if( n )
     658             :         {
     659             :             OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     660           0 :             if ( pStgStrm )
     661           0 :                 pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
     662             : 
     663           0 :             delete pTmpStrm;
     664           0 :             pTmpStrm = NULL;
     665           0 :             return false;
     666             :         }
     667             :     }
     668        3926 :     return true;
     669             : }
     670             : 
     671             : // Copy the temp stream to the stg stream during the final commit
     672             : 
     673        4687 : bool StgDirEntry::Tmp2Strm()
     674             : {
     675             :     // We did commit once, but have not written since then
     676        4687 :     if( !pTmpStrm )
     677        4687 :         pTmpStrm = pCurStrm, pCurStrm = NULL;
     678        4687 :     if( pTmpStrm )
     679             :     {
     680             :         OSL_ENSURE( pStgStrm, "The pointer may not be NULL!" );
     681        3926 :         if ( !pStgStrm )
     682           0 :             return false;
     683        3926 :         sal_uLong n = pTmpStrm->GetSize();
     684             :         StgStrm* pNewStrm;
     685        3926 :         StgIo& rIo = pStgStrm->GetIo();
     686        3926 :         sal_uLong nThreshold = (sal_uLong) rIo.aHdr.GetThreshold();
     687        3926 :         if( n < nThreshold )
     688        3410 :             pNewStrm = new StgSmallStrm( rIo, STG_EOF, 0 );
     689             :         else
     690         516 :             pNewStrm = new StgDataStrm( rIo, STG_EOF, 0 );
     691        3926 :         if( pNewStrm->SetSize( n ) )
     692             :         {
     693             :             sal_uInt8 p[ 4096 ];
     694        3926 :             pTmpStrm->Seek( 0L );
     695       12836 :             while( n )
     696             :             {
     697        4984 :                 sal_uLong nn = n;
     698        4984 :                 if( nn > 4096 )
     699        1120 :                     nn = 4096;
     700        4984 :                 if( pTmpStrm->Read( p, nn ) != nn )
     701           0 :                     break;
     702        4984 :                 if( (sal_uLong) pNewStrm->Write( p, nn ) != nn )
     703           0 :                     break;
     704        4984 :                 n -= nn;
     705             :             }
     706        3926 :             if( n )
     707             :             {
     708           0 :                 pTmpStrm->Seek( nPos );
     709           0 :                 pStgStrm->GetIo().SetError( pTmpStrm->GetError() );
     710           0 :                 delete pNewStrm;
     711           0 :                 return false;
     712             :             }
     713             :             else
     714             :             {
     715        3926 :                 pStgStrm->SetSize( 0L );
     716        3926 :                 delete pStgStrm;
     717        3926 :                 pStgStrm = pNewStrm;
     718        3926 :                 pNewStrm->SetEntry( *this );
     719        3926 :                 pNewStrm->Pos2Page( nPos );
     720        3926 :                 delete pTmpStrm;
     721        3926 :                 delete pCurStrm;
     722        3926 :                 pTmpStrm = pCurStrm = NULL;
     723        3926 :                 aSave = aEntry;
     724             :             }
     725             :         }
     726             :     }
     727        4687 :     return true;
     728             : }
     729             : 
     730             : // Check if the given entry is contained in this entry
     731             : 
     732           0 : bool StgDirEntry::IsContained( StgDirEntry* pStg )
     733             : {
     734           0 :     if( aEntry.GetType() == STG_STORAGE )
     735             :     {
     736           0 :         StgIterator aIter( *this );
     737           0 :         StgDirEntry* p = aIter.First();
     738           0 :         while( p )
     739             :         {
     740           0 :             if( !p->aEntry.Compare( pStg->aEntry ) )
     741           0 :                 return false;
     742           0 :             if( p->aEntry.GetType() == STG_STORAGE )
     743           0 :                 if( !p->IsContained( pStg ) )
     744           0 :                     return false;
     745           0 :             p = aIter.Next();
     746             :         }
     747             :     }
     748           0 :     return true;
     749             : }
     750             : 
     751             : // Invalidate all open entries by setting the RefCount to 0. If the bDel
     752             : // flag is set, also set the invalid flag to indicate deletion during the
     753             : // next dir stream flush.
     754             : 
     755       20942 : void StgDirEntry::Invalidate( bool bDel )
     756             : {
     757             : //  nRefCnt = 0;
     758       20942 :     if( bDel )
     759          28 :         bRemoved = bInvalid = true;
     760       20942 :     switch( aEntry.GetType() )
     761             :     {
     762             :         case STG_STORAGE:
     763             :         case STG_ROOT:
     764             :         {
     765        2840 :             StgIterator aIter( *this );
     766       21998 :             for( StgDirEntry* p = aIter.First(); p; p = aIter.Next() )
     767       19158 :                 p->Invalidate( bDel );
     768        2840 :             break;
     769             :         }
     770             :         default:
     771       18102 :             break;
     772             :     }
     773       20942 : }
     774             : 
     775             : ///////////////////////////// class StgDirStrm
     776             : 
     777             : // This specialized stream is the maintenance stream for the directory tree.
     778             : 
     779        1270 : StgDirStrm::StgDirStrm( StgIo& r )
     780             :           : StgDataStrm( r, r.aHdr.GetTOCStart(), -1 )
     781             :           , pRoot( NULL )
     782        1270 :           , nEntries( 0 )
     783             : {
     784        1270 :     if( r.GetError() )
     785        1272 :         return;
     786        1268 :     nEntries = nPageSize / STGENTRY_SIZE;
     787        1268 :     if( nStart == STG_EOF )
     788             :     {
     789         351 :         StgEntry aRoot;
     790         351 :         aRoot.Init();
     791         351 :         aRoot.SetName( OUString("Root Entry") );
     792         351 :         aRoot.SetType( STG_ROOT );
     793         351 :         pRoot = new StgDirEntry( aRoot );
     794         351 :         pRoot->SetDirty();
     795             :     }
     796             :     else
     797             :     {
     798             :         // temporarily use this instance as owner, so
     799             :         // the TOC pages can be removed.
     800         917 :         pEntry = (StgDirEntry*) this; // just for a bit pattern
     801         917 :         SetupEntry( 0, pRoot );
     802         917 :         pEntry = NULL;
     803             :     }
     804             : }
     805             : 
     806        3810 : StgDirStrm::~StgDirStrm()
     807             : {
     808        1270 :     delete pRoot;
     809        2540 : }
     810             : 
     811             : // Recursively parse the directory tree during reading the TOC stream
     812             : 
     813       31382 : void StgDirStrm::SetupEntry( sal_Int32 n, StgDirEntry* pUpper )
     814             : {
     815       31382 :     void* p = ( n == STG_FREE ) ? NULL : GetEntry( n );
     816       31382 :     if( p )
     817             :     {
     818       10165 :         bool bOk(false);
     819       10165 :         StgDirEntry* pCur = new StgDirEntry( p, STGENTRY_SIZE, &bOk );
     820             : 
     821       10165 :         if( !bOk )
     822             :         {
     823           6 :             delete pCur;
     824           6 :             rIo.SetError( SVSTREAM_GENERALERROR );
     825             :             // an error occurred
     826          14 :             return;
     827             :         }
     828             : 
     829             :         // better it is
     830       10159 :         if( !pUpper )
     831         913 :             pCur->aEntry.SetType( STG_ROOT );
     832             : 
     833       10159 :         sal_Int32 nLeft = pCur->aEntry.GetLeaf( STG_LEFT );
     834       10159 :         sal_Int32 nRight = pCur->aEntry.GetLeaf( STG_RIGHT );
     835             :         // substorage?
     836       10159 :         sal_Int32 nLeaf = STG_FREE;
     837       10159 :         if( pCur->aEntry.GetType() == STG_STORAGE || pCur->aEntry.GetType() == STG_ROOT )
     838             :         {
     839        1601 :             nLeaf = pCur->aEntry.GetLeaf( STG_CHILD );
     840        1601 :             if (nLeaf != STG_FREE && nLeaf == n)
     841             :             {
     842           0 :                 delete pCur;
     843           0 :                 rIo.SetError( SVSTREAM_GENERALERROR );
     844           0 :                 return;
     845             :             }
     846             :         }
     847             : 
     848       10159 :         if( nLeaf != 0 && nLeft != 0 && nRight != 0 )
     849             :         {
     850             :             //fdo#41642 Do we need to check full chain upwards for loops ?
     851       10157 :             if (pUpper)
     852             :             {
     853        9244 :                 if (pUpper->aEntry.GetLeaf(STG_CHILD) == nLeaf)
     854             :                 {
     855             :                     OSL_FAIL("Leaf node of upper StgDirEntry is same as current StgDirEntry's leaf node. Circular entry chain, discarding link");
     856           0 :                     delete pCur;
     857           0 :                     return;
     858             :                 }
     859             : 
     860        9244 :                 StgDirEntry *pUpperUpper = pUpper->pUp;
     861        9244 :                 if (pUpperUpper && pUpperUpper->aEntry.GetLeaf(STG_CHILD) == nLeaf)
     862             :                 {
     863             :                     OSL_FAIL("Leaf node of upper-upper StgDirEntry is same as current StgDirEntry's leaf node. Circular entry chain, discarding link");
     864           2 :                     delete pCur;
     865           2 :                     return;
     866             :                 }
     867             :             }
     868             : 
     869       10155 :             if( StgAvlNode::Insert
     870       10155 :                 ( (StgAvlNode**) ( pUpper ? &pUpper->pDown : &pRoot ), pCur ) )
     871             :             {
     872       10155 :                 pCur->pUp    = pUpper;
     873       10155 :                 pCur->ppRoot = &pRoot;
     874             :             }
     875             :             else
     876             :             {
     877             :                 // bnc#682484: There are some really broken docs out there
     878             :                 // that contain duplicate entries in 'Directory' section
     879             :                 // so don't set the error flag here and just skip those
     880             :                 // (was: rIo.SetError( SVSTREAM_CANNOT_MAKE );)
     881           0 :                 delete pCur;
     882           0 :                 return;
     883             :             }
     884       10155 :             SetupEntry( nLeft, pUpper );
     885       10155 :             SetupEntry( nRight, pUpper );
     886       10155 :             SetupEntry( nLeaf, pCur );
     887             :         }
     888             :         else
     889             :         {
     890           2 :             delete pCur;
     891             :         }
     892             :     }
     893             : }
     894             : 
     895             : // Extend or shrink the directory stream.
     896             : 
     897         721 : bool StgDirStrm::SetSize( sal_Int32 nBytes )
     898             : {
     899             :     // Always allocate full pages
     900         721 :     if ( nBytes < 0 )
     901           0 :         nBytes = 0;
     902             : 
     903         721 :     nBytes = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
     904         721 :     return StgStrm::SetSize( nBytes );
     905             : }
     906             : 
     907             : // Save the TOC stream into a new substream after saving all data streams
     908             : 
     909         721 : bool StgDirStrm::Store()
     910             : {
     911         721 :     if( !pRoot || !pRoot->IsDirty() )
     912           0 :         return true;
     913         721 :     if( !pRoot->StoreStreams( rIo ) )
     914           0 :         return false;
     915             :     // After writing all streams, the data FAT stream has changed,
     916             :     // so we have to commit the root again
     917         721 :     pRoot->Commit();
     918             :     // We want a completely new stream, so fake an empty stream
     919         721 :     sal_Int32 nOldStart = nStart;       // save for later deletion
     920         721 :     sal_Int32 nOldSize  = nSize;
     921         721 :     nStart = nPage = STG_EOF;
     922         721 :     nSize  = nPos = 0;
     923         721 :     nOffset = 0;
     924             :     // Delete all temporary entries
     925         721 :     pRoot->DelTemp( false );
     926             :     // set the entry numbers
     927         721 :     sal_Int32 n = 0;
     928         721 :     pRoot->Enum( n );
     929         721 :     if( !SetSize( n * STGENTRY_SIZE ) )
     930             :     {
     931           0 :         nStart = nOldStart; nSize = nOldSize;
     932           0 :         pRoot->RevertAll();
     933           0 :         return false;
     934             :     }
     935             :     // set up the cache elements for the new stream
     936         721 :     if( !Copy( STG_FREE, nSize ) )
     937             :     {
     938           0 :         pRoot->RevertAll();
     939           0 :         return false;
     940             :     }
     941             :     // Write the data to the new stream
     942         721 :     if( !pRoot->Store( *this ) )
     943             :     {
     944           0 :         pRoot->RevertAll();
     945           0 :         return false;
     946             :     }
     947             :     // fill any remaining entries with empty data
     948         721 :     sal_Int32 ne = nSize / STGENTRY_SIZE;
     949         721 :     StgEntry aEmpty;
     950         721 :     aEmpty.Init();
     951        3057 :     while( n < ne )
     952             :     {
     953        1615 :         void* p = GetEntry( n++, true );
     954        1615 :         if( !p )
     955             :         {
     956           0 :             pRoot->RevertAll();
     957           0 :             return false;
     958             :         }
     959        1615 :         aEmpty.Store( p );
     960             :     }
     961             :     // Now we can release the old stream
     962         721 :     pFat->FreePages( nOldStart, true );
     963         721 :     rIo.aHdr.SetTOCStart( nStart );
     964         721 :     return true;
     965             : }
     966             : 
     967             : // Get a dir entry.
     968             : 
     969       16605 : void* StgDirStrm::GetEntry( sal_Int32 n, bool bDirty )
     970             : {
     971       16603 :     return n < 0 || n >= nSize / STGENTRY_SIZE
     972       33206 :         ? NULL : GetPtr( n * STGENTRY_SIZE, true, bDirty );
     973             : }
     974             : 
     975             : // Find a dir entry.
     976             : 
     977       28610 : StgDirEntry* StgDirStrm::Find( StgDirEntry& rStg, const OUString& rName )
     978             : {
     979       28610 :     if( rStg.pDown )
     980             :     {
     981       27310 :         StgEntry aEntry;
     982       27310 :         aEntry.Init();
     983       27310 :         if( !aEntry.SetName( rName ) )
     984             :         {
     985           0 :             rIo.SetError( SVSTREAM_GENERALERROR );
     986           0 :             return NULL;
     987             :         }
     988             :         // Look in the directory attached to the entry
     989       54620 :         StgDirEntry aTest( aEntry );
     990       54620 :         return static_cast<StgDirEntry*>( rStg.pDown->Find( &aTest ) );
     991             :     }
     992             :     else
     993        1300 :         return NULL;
     994             : }
     995             : 
     996             : // Create a new entry.
     997             : 
     998        4152 : StgDirEntry* StgDirStrm::Create( StgDirEntry& rStg, const OUString& rName, StgEntryType eType )
     999             : {
    1000        4152 :     StgEntry aEntry;
    1001        4152 :     aEntry.Init();
    1002        4152 :     aEntry.SetType( eType );
    1003        4152 :     if( !aEntry.SetName( rName ) )
    1004             :     {
    1005           0 :         rIo.SetError( SVSTREAM_GENERALERROR );
    1006           0 :         return NULL;
    1007             :     }
    1008        4152 :     StgDirEntry* pRes = Find( rStg, rName );
    1009        4152 :     if( pRes )
    1010             :     {
    1011           0 :         if( !pRes->bInvalid )
    1012             :         {
    1013           0 :             rIo.SetError( SVSTREAM_CANNOT_MAKE );
    1014           0 :             return NULL;
    1015             :         }
    1016             :         pRes->bInvalid =
    1017             :         pRes->bRemoved =
    1018           0 :         pRes->bTemp    = false;
    1019             :         pRes->bCreated =
    1020           0 :         pRes->bDirty   = true;
    1021             :     }
    1022             :     else
    1023             :     {
    1024        4152 :         pRes = new StgDirEntry( aEntry );
    1025        4152 :         if( StgAvlNode::Insert( (StgAvlNode**) &rStg.pDown, pRes ) )
    1026             :         {
    1027        4152 :             pRes->pUp    = &rStg;
    1028        4152 :             pRes->ppRoot = &pRoot;
    1029             :             pRes->bCreated =
    1030        4152 :             pRes->bDirty = true;
    1031             :         }
    1032             :         else
    1033             :         {
    1034           0 :             rIo.SetError( SVSTREAM_CANNOT_MAKE );
    1035           0 :             delete pRes; pRes = NULL;
    1036             :         }
    1037             :     }
    1038        4152 :     return pRes;
    1039             : }
    1040             : 
    1041             : // Rename the given entry.
    1042             : 
    1043           0 : bool StgDirStrm::Rename( StgDirEntry& rStg, const OUString& rOld, const OUString& rNew )
    1044             : {
    1045           0 :     StgDirEntry* p = Find( rStg, rOld );
    1046           0 :     if( p )
    1047             :     {
    1048             : 
    1049           0 :         if( !StgAvlNode::Remove( (StgAvlNode**) &rStg.pDown, p, false ) )
    1050           0 :             return false;
    1051           0 :         p->aEntry.SetName( rNew );
    1052           0 :         if( !StgAvlNode::Insert( (StgAvlNode**) &rStg.pDown, p ) )
    1053           0 :             return false;
    1054           0 :         p->bRenamed = p->bDirty   = true;
    1055           0 :         return true;
    1056             :     }
    1057             :     else
    1058             :     {
    1059           0 :         rIo.SetError( SVSTREAM_FILE_NOT_FOUND );
    1060           0 :         return false;
    1061             :     }
    1062             : }
    1063             : 
    1064             : // Move the given entry to a different storage.
    1065             : 
    1066           0 : bool StgDirStrm::Move( StgDirEntry& rStg1, StgDirEntry& rStg2, const OUString& rName )
    1067             : {
    1068           0 :     StgDirEntry* p = Find( rStg1, rName );
    1069           0 :     if( p )
    1070             :     {
    1071           0 :         if( !StgAvlNode::Move
    1072           0 :             ( (StgAvlNode**) &rStg1.pDown, (StgAvlNode**) &rStg2.pDown, p ) )
    1073           0 :             return false;
    1074           0 :         p->bDirty = true;
    1075           0 :         return true;
    1076             :     }
    1077             :     else
    1078             :     {
    1079           0 :         rIo.SetError( SVSTREAM_FILE_NOT_FOUND );
    1080           0 :         return false;
    1081             :     }
    1082             : }
    1083             : 
    1084             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10