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

Generated by: LCOV version 1.11