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

Generated by: LCOV version 1.10