LCOV - code coverage report
Current view: top level - sot/source/sdstor - stgstrms.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 493 708 69.6 %
Date: 2012-08-25 Functions: 42 46 91.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 292 610 47.9 %

           Branch data     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                 :            : #include <algorithm>
      21                 :            : 
      22                 :            : #include <string.h>     // memcpy()
      23                 :            : #include <sal/log.hxx>
      24                 :            : #include <osl/file.hxx>
      25                 :            : #include <tools/tempfile.hxx>
      26                 :            : 
      27                 :            : #include "sot/stg.hxx"
      28                 :            : #include "stgelem.hxx"
      29                 :            : #include "stgcache.hxx"
      30                 :            : #include "stgstrms.hxx"
      31                 :            : #include "stgdir.hxx"
      32                 :            : #include "stgio.hxx"
      33                 :            : 
      34                 :            : #define __HUGE
      35                 :            : 
      36                 :            : ///////////////////////////// class StgFAT ///////////////////////////////
      37                 :            : 
      38                 :            : // The FAT class performs FAT operations on an underlying storage stream.
      39                 :            : // This stream is either the master FAT stream (m == sal_True ) or a normal
      40                 :            : // storage stream, which then holds the FAT for small data allocations.
      41                 :            : 
      42                 :       5600 : StgFAT::StgFAT( StgStrm& r, sal_Bool m ) : rStrm( r )
      43                 :            : {
      44                 :       5600 :     bPhys   = m;
      45                 :       5600 :     nPageSize = rStrm.GetIo().GetPhysPageSize();
      46                 :       5600 :     nEntries  = nPageSize >> 2;
      47                 :       5600 :     nOffset   = 0;
      48                 :       5600 :     nMaxPage  = 0;
      49                 :       5600 :     nLimit    = 0;
      50                 :       5600 : }
      51                 :            : 
      52                 :            : // Retrieve the physical page for a given byte offset.
      53                 :            : 
      54                 :     119933 : StgPage* StgFAT::GetPhysPage( sal_Int32 nByteOff )
      55                 :            : {
      56                 :     119933 :     StgPage* pPg = NULL;
      57                 :            :     // Position within the underlying stream
      58                 :            :     // use the Pos2Page() method of the stream
      59         [ +  - ]:     119933 :     if( rStrm.Pos2Page( nByteOff ) )
      60                 :            :     {
      61                 :     119933 :         nOffset = rStrm.GetOffset();
      62                 :     119933 :         sal_Int32 nPhysPage = rStrm.GetPage();
      63                 :            :         // get the physical page (must be present)
      64                 :     119933 :         pPg = rStrm.GetIo().Get( nPhysPage, sal_True );
      65                 :            :     }
      66                 :     119933 :     return pPg;
      67                 :            : }
      68                 :            : 
      69                 :            : // Get the follow page for a certain FAT page.
      70                 :            : 
      71                 :     111233 : sal_Int32 StgFAT::GetNextPage( sal_Int32 nPg )
      72                 :            : {
      73         [ +  - ]:     111233 :     if( nPg >= 0 )
      74                 :            :     {
      75                 :     111233 :       StgPage* pPg = GetPhysPage( nPg << 2 );
      76         [ +  - ]:     111233 :         nPg = pPg ? pPg->GetPage( nOffset >> 2 ) : STG_EOF;
      77                 :            :     }
      78                 :     111233 :     return nPg;
      79                 :            : }
      80                 :            : 
      81                 :            : // Find the best fit block for the given size. Return
      82                 :            : // the starting block and its size or STG_EOF and 0.
      83                 :            : // nLastPage is a stopper which tells the current
      84                 :            : // underlying stream size. It is treated as a recommendation
      85                 :            : // to abort the search to inhibit excessive file growth.
      86                 :            : 
      87                 :       3263 : sal_Int32 StgFAT::FindBlock( sal_Int32& nPgs )
      88                 :            : {
      89                 :       3263 :     sal_Int32 nMinStart = STG_EOF, nMinLen = 0;
      90                 :       3263 :     sal_Int32 nMaxStart = STG_EOF, nMaxLen = 0x7FFFFFFFL;
      91                 :       3263 :     sal_Int32 nTmpStart = STG_EOF, nTmpLen = 0;
      92                 :       3263 :     sal_Int32 nPages    = rStrm.GetSize() >> 2;
      93                 :       3263 :     sal_Bool bFound     = sal_False;
      94                 :       3263 :     StgPage* pPg = NULL;
      95                 :       3263 :     short nEntry = 0;
      96         [ +  + ]:     259203 :     for( sal_Int32 i = 0; i < nPages; i++, nEntry++ )
      97                 :            :     {
      98         [ +  + ]:     258825 :         if( !( nEntry % nEntries ) )
      99                 :            :         {
     100                 :            :             // load the next page for that stream
     101                 :       3943 :             nEntry = 0;
     102                 :       3943 :             pPg = GetPhysPage( i << 2 );
     103         [ -  + ]:       3943 :             if( !pPg )
     104                 :          0 :                 return STG_EOF;
     105                 :            :         }
     106                 :     258825 :         sal_Int32 nCur = pPg->GetPage( nEntry );
     107         [ +  + ]:     258825 :         if( nCur == STG_FREE )
     108                 :            :         {
     109                 :            :             // count the size of this area
     110         [ +  + ]:      17260 :             if( nTmpLen )
     111                 :      14303 :                 nTmpLen++;
     112                 :            :             else
     113                 :            :                 nTmpStart = i,
     114                 :       2957 :                 nTmpLen   = 1;
     115 [ +  + ][ +  + ]:      17260 :             if( nTmpLen == nPgs
                 [ +  - ]
     116                 :            :              // If we already did find a block, stop when reaching the limit
     117                 :            :              || ( bFound && ( nEntry >= nLimit ) ) )
     118                 :       2885 :                 break;
     119                 :            :         }
     120         [ +  + ]:     241565 :         else if( nTmpLen )
     121                 :            :         {
     122 [ -  + ][ #  # ]:          9 :             if( nTmpLen > nPgs && nTmpLen < nMaxLen )
     123                 :            :                 // block > requested size
     124                 :          0 :                 nMaxLen = nTmpLen, nMaxStart = nTmpStart, bFound = sal_True;
     125         [ +  - ]:          9 :             else if( nTmpLen >= nMinLen )
     126                 :            :             {
     127                 :            :                 // block < requested size
     128                 :          9 :                 nMinLen = nTmpLen, nMinStart = nTmpStart;
     129                 :          9 :                 bFound = sal_True;
     130         [ -  + ]:          9 :                 if( nTmpLen == nPgs )
     131                 :          0 :                     break;
     132                 :            :             }
     133                 :          9 :             nTmpStart = STG_EOF;
     134                 :          9 :             nTmpLen   = 0;
     135                 :            :         }
     136                 :            :     }
     137                 :            :     // Determine which block to use.
     138         [ +  + ]:       3263 :     if( nTmpLen )
     139                 :            :     {
     140 [ -  + ][ #  # ]:       2948 :         if( nTmpLen > nPgs  && nTmpLen < nMaxLen )
     141                 :            :             // block > requested size
     142                 :          0 :             nMaxLen = nTmpLen, nMaxStart = nTmpStart;
     143         [ +  - ]:       2948 :         else if( nTmpLen >= nMinLen )
     144                 :            :             // block < requested size
     145                 :       2948 :             nMinLen = nTmpLen, nMinStart = nTmpStart;
     146                 :            :     }
     147 [ +  + ][ -  + ]:       3263 :     if( nMinStart != STG_EOF && nMaxStart != STG_EOF )
     148                 :            :     {
     149                 :            :         // two areas found; return the best fit area
     150                 :          0 :         sal_Int32 nMinDiff = nPgs - nMinLen;
     151                 :          0 :         sal_Int32 nMaxDiff = nMaxLen - nPgs;
     152         [ #  # ]:          0 :         if( nMinDiff > nMaxDiff )
     153                 :          0 :             nMinStart = STG_EOF;
     154                 :            :     }
     155         [ +  + ]:       3263 :     if( nMinStart != STG_EOF )
     156                 :            :     {
     157                 :       2948 :         nPgs = nMinLen; return nMinStart;
     158                 :            :     }
     159                 :            :     else
     160                 :            :     {
     161                 :       3263 :         return nMaxStart;
     162                 :            :     }
     163                 :            : }
     164                 :            : 
     165                 :            : // Set up the consecutive chain for a given block.
     166                 :            : 
     167                 :       2948 : sal_Bool StgFAT::MakeChain( sal_Int32 nStart, sal_Int32 nPgs )
     168                 :            : {
     169                 :       2948 :     sal_Int32 nPos = nStart << 2;
     170                 :       2948 :     StgPage* pPg = GetPhysPage( nPos );
     171 [ -  + ][ +  - ]:       2948 :     if( !pPg || !nPgs )
     172                 :          0 :         return sal_False;
     173         [ +  + ]:      17251 :     while( --nPgs )
     174                 :            :     {
     175         [ -  + ]:      14303 :         if( nOffset >= nPageSize )
     176                 :            :         {
     177                 :          0 :             pPg = GetPhysPage( nPos );
     178         [ #  # ]:          0 :             if( !pPg )
     179                 :          0 :                 return sal_False;
     180                 :            :         }
     181                 :      14303 :         pPg->SetPage( nOffset >> 2, ++nStart );
     182                 :      14303 :         nOffset += 4;
     183                 :      14303 :         nPos += 4;
     184                 :            :     }
     185         [ -  + ]:       2948 :     if( nOffset >= nPageSize )
     186                 :            :     {
     187                 :          0 :         pPg = GetPhysPage( nPos );
     188         [ #  # ]:          0 :         if( !pPg )
     189                 :          0 :             return sal_False;
     190                 :            :     }
     191                 :       2948 :     pPg->SetPage( nOffset >> 2, STG_EOF );
     192                 :       2948 :     return sal_True;
     193                 :            : }
     194                 :            : 
     195                 :            : // Allocate a block of data from the given page number on.
     196                 :            : // It the page number is != STG_EOF, chain the block.
     197                 :            : 
     198                 :       2876 : sal_Int32 StgFAT::AllocPages( sal_Int32 nBgn, sal_Int32 nPgs )
     199                 :            : {
     200                 :       2876 :     sal_Int32 nOrig = nBgn;
     201                 :       2876 :     sal_Int32 nLast = nBgn;
     202                 :       2876 :     sal_Int32 nBegin = STG_EOF;
     203                 :            :     sal_Int32 nAlloc;
     204                 :       2876 :     sal_Int32 nPages = rStrm.GetSize() >> 2;
     205                 :       2876 :     short nPasses = 0;
     206                 :            :     // allow for two passes
     207         [ +  - ]:       3104 :     while( nPasses < 2 )
     208                 :            :     {
     209                 :            :         // try to satisfy the request from the pool of free pages
     210         [ +  + ]:       6052 :         while( nPgs )
     211                 :            :         {
     212                 :       3176 :             nAlloc = nPgs;
     213         [ +  - ]:       3176 :             nBegin = FindBlock( nAlloc );
     214                 :            :             // no more blocks left in present alloc chain
     215         [ +  + ]:       3176 :             if( nBegin == STG_EOF )
     216                 :        228 :                 break;
     217         [ +  + ]:       2948 :             if( ( nBegin + nAlloc ) > nMaxPage )
     218                 :       2939 :                 nMaxPage = nBegin + nAlloc;
     219 [ +  - ][ -  + ]:       2948 :             if( !MakeChain( nBegin, nAlloc ) )
     220                 :          0 :                 return STG_EOF;
     221         [ +  + ]:       2948 :             if( nOrig == STG_EOF )
     222                 :       1232 :                 nOrig = nBegin;
     223                 :            :             else
     224                 :            :             {
     225                 :            :                 // Patch the chain
     226         [ +  - ]:       1716 :                 StgPage* pPg = GetPhysPage( nLast << 2 );
     227         [ -  + ]:       1716 :                 if( !pPg )
     228                 :          0 :                     return STG_EOF;
     229         [ +  - ]:       1716 :                 pPg->SetPage( nOffset >> 2, nBegin );
     230                 :            :             }
     231                 :       2948 :             nLast = nBegin + nAlloc - 1;
     232                 :       2948 :             nPgs -= nAlloc;
     233                 :            :         }
     234 [ +  + ][ +  - ]:       3104 :         if( nPgs && !nPasses )
     235                 :            :         {
     236                 :            :             // we need new, fresh space, so allocate and retry
     237 [ +  - ][ -  + ]:        228 :             if( !rStrm.SetSize( ( nPages + nPgs ) << 2 ) )
     238                 :          0 :                 return STG_EOF;
     239 [ +  + ][ +  - ]:        228 :             if( !bPhys && !InitNew( nPages ) )
         [ -  + ][ -  + ]
     240                 :          0 :                 return sal_False;
     241                 :        228 :             nPages = rStrm.GetSize() >> 2;
     242                 :        228 :             nPasses++;
     243                 :            :         }
     244                 :            :         else
     245                 :       2876 :             break;
     246                 :            :     }
     247                 :            :     // now we should have a chain for the complete block
     248 [ +  - ][ -  + ]:       2876 :     if( nBegin == STG_EOF || nPgs )
     249                 :            :     {
     250         [ #  # ]:          0 :         rStrm.GetIo().SetError( SVSTREAM_FILEFORMAT_ERROR );
     251                 :          0 :         return STG_EOF; // bad structure
     252                 :            :     }
     253                 :       2876 :     return nOrig;
     254                 :            : }
     255                 :            : 
     256                 :            : // Initialize newly allocated pages for a standard FAT stream
     257                 :            : // It can be assumed that the stream size is always on
     258                 :            : // a page boundary
     259                 :            : 
     260                 :        141 : sal_Bool StgFAT::InitNew( sal_Int32 nPage1 )
     261                 :            : {
     262                 :        141 :     sal_Int32 n = ( ( rStrm.GetSize() >> 2 ) - nPage1 ) / nEntries;
     263         [ +  - ]:        141 :     if ( n > 0 )
     264                 :            :     {
     265         [ +  + ]:        282 :         while( n-- )
     266                 :            :         {
     267                 :        141 :             StgPage* pPg = NULL;
     268                 :            :             // Position within the underlying stream
     269                 :            :             // use the Pos2Page() method of the stream
     270                 :        141 :             rStrm.Pos2Page( nPage1 << 2 );
     271                 :            :             // Initialize the page
     272                 :        141 :             pPg = rStrm.GetIo().Copy( rStrm.GetPage(), STG_FREE );
     273         [ -  + ]:        141 :             if ( !pPg )
     274                 :          0 :                 return sal_False;
     275         [ +  + ]:      18189 :             for( short i = 0; i < nEntries; i++ )
     276                 :      18048 :                 pPg->SetPage( i, STG_FREE );
     277                 :        141 :             nPage1++;
     278                 :            :         }
     279                 :            :     }
     280                 :        141 :     return sal_True;
     281                 :            : }
     282                 :            : 
     283                 :            : // Release a chain
     284                 :            : 
     285                 :        159 : sal_Bool StgFAT::FreePages( sal_Int32 nStart, sal_Bool bAll )
     286                 :            : {
     287         [ +  + ]:        252 :     while( nStart >= 0 )
     288                 :            :     {
     289                 :         93 :         StgPage* pPg = GetPhysPage( nStart << 2 );
     290         [ -  + ]:         93 :         if( !pPg )
     291                 :          0 :             return sal_False;
     292                 :         93 :         nStart = pPg->GetPage( nOffset >> 2 );
     293                 :            :         // The first released page is either set to EOF or FREE
     294         [ +  - ]:         93 :         pPg->SetPage( nOffset >> 2, bAll ? STG_FREE : STG_EOF );
     295                 :         93 :         bAll = sal_True;
     296                 :            :     }
     297                 :        159 :     return sal_True;
     298                 :            : }
     299                 :            : 
     300                 :            : ///////////////////////////// class StgStrm ////////////////////////////////
     301                 :            : 
     302                 :            : // The base stream class provides basic functionality for seeking
     303                 :            : // and accessing the data on a physical basis. It uses the built-in
     304                 :            : // FAT class for the page allocations.
     305                 :            : 
     306                 :       5600 : StgStrm::StgStrm( StgIo& r ) : rIo( r )
     307                 :            : {
     308                 :       5600 :     pFat    = NULL;
     309                 :       5600 :     nStart  = nPage = STG_EOF;
     310                 :       5600 :     nOffset = 0;
     311                 :       5600 :     pEntry  = NULL;
     312                 :       5600 :     nPos = nSize = 0;
     313                 :       5600 :     nPageSize = rIo.GetPhysPageSize();
     314                 :       5600 : }
     315                 :            : 
     316                 :       5528 : StgStrm::~StgStrm()
     317                 :            : {
     318                 :       5528 :     delete pFat;
     319         [ -  + ]:       5528 : }
     320                 :            : 
     321                 :            : // Attach the stream to the given entry.
     322                 :            : 
     323                 :       1281 : void StgStrm::SetEntry( StgDirEntry& r )
     324                 :            : {
     325                 :       1281 :     r.aEntry.SetLeaf( STG_DATA, nStart );
     326                 :       1281 :     r.aEntry.SetSize( nSize );
     327                 :       1281 :     pEntry = &r;
     328                 :       1281 :     r.SetDirty();
     329                 :       1281 : }
     330                 :            : 
     331                 :            : /*
     332                 :            :  * The page chain, is basically a singly linked list of slots each
     333                 :            :  * point to the next page. Instead of traversing the file structure
     334                 :            :  * for this each time build a simple flat in-memory vector list
     335                 :            :  * of pages.
     336                 :            :  */
     337                 :        725 : void StgStrm::scanBuildPageChainCache(sal_Int32 *pOptionalCalcSize)
     338                 :            : {
     339         [ -  + ]:        725 :     if (nSize > 0)
     340         [ #  # ]:          0 :         m_aPagesCache.reserve(nSize/nPageSize);
     341                 :            : 
     342                 :        725 :     bool bError = false;
     343                 :        725 :     sal_Int32 nBgn = nStart;
     344                 :        725 :     sal_Int32 nOldBgn = -1;
     345                 :        725 :     sal_Int32 nOptSize = 0;
     346 [ +  + ][ +  - ]:       1921 :     while( nBgn >= 0 && nBgn != nOldBgn )
                 [ +  + ]
     347                 :            :     {
     348         [ +  - ]:       1196 :         if( nBgn >= 0 )
     349         [ +  - ]:       1196 :             m_aPagesCache.push_back(nBgn);
     350                 :       1196 :         nOldBgn = nBgn;
     351         [ +  - ]:       1196 :         nBgn = pFat->GetNextPage( nBgn );
     352         [ -  + ]:       1196 :         if( nBgn == nOldBgn )
     353                 :          0 :             bError = true;
     354                 :       1196 :         nOptSize += nPageSize;
     355                 :            :     }
     356         [ -  + ]:        725 :     if (bError)
     357                 :            :     {
     358         [ #  # ]:          0 :         if (pOptionalCalcSize)
     359         [ #  # ]:          0 :             rIo.SetError( ERRCODE_IO_WRONGFORMAT );
     360                 :          0 :         m_aPagesCache.clear();
     361                 :            :     }
     362         [ +  - ]:        725 :     if (pOptionalCalcSize)
     363                 :        725 :         *pOptionalCalcSize = nOptSize;
     364                 :        725 : }
     365                 :            : 
     366                 :            : // Compute page number and offset for the given byte position.
     367                 :            : // If the position is behind the size, set the stream right
     368                 :            : // behind the EOF.
     369                 :    4375258 : sal_Bool StgStrm::Pos2Page( sal_Int32 nBytePos )
     370                 :            : {
     371         [ -  + ]:    4375258 :     if ( !pFat )
     372                 :          0 :         return sal_False;
     373                 :            : 
     374                 :            :     // Values < 0 seek to the end
     375 [ +  - ][ +  + ]:    4375258 :     if( nBytePos < 0 || nBytePos >= nSize )
     376                 :      81379 :         nBytePos = nSize;
     377                 :            :     // Adjust the position back to offset 0
     378                 :    4375258 :     nPos -= nOffset;
     379                 :    4375258 :     sal_Int32 nMask = ~( nPageSize - 1 );
     380                 :    4375258 :     sal_Int32 nOld = nPos & nMask;
     381                 :    4375258 :     sal_Int32 nNew = nBytePos & nMask;
     382                 :    4375258 :     nOffset = (short) ( nBytePos & ~nMask );
     383                 :    4375258 :     nPos = nBytePos;
     384         [ +  + ]:    4375258 :     if( nOld == nNew )
     385                 :    4295574 :         return sal_True;
     386                 :            : 
     387                 :            :     // See fdo#47644 for a .doc with a vast amount of pages where seeking around the
     388                 :            :     // document takes a colossal amount of time
     389                 :            :     //
     390                 :            :     // Please Note: we build the pagescache incrementally as we go if necessary,
     391                 :            :     // so that a corrupted FAT doesn't poison the stream state for earlier reads
     392                 :      79684 :     size_t nIdx = nNew / nPageSize;
     393         [ +  + ]:      79684 :     if( nIdx >= m_aPagesCache.size() )
     394                 :            :     {
     395                 :            :         // Extend the FAT cache ! ...
     396                 :      44607 :         size_t nToAdd = nIdx + 1;
     397                 :            : 
     398         [ +  + ]:      44607 :         if (m_aPagesCache.empty())
     399         [ +  - ]:       6269 :             m_aPagesCache.push_back( nStart );
     400                 :            : 
     401                 :      44607 :         nToAdd -= m_aPagesCache.size();
     402                 :            : 
     403         [ +  - ]:      44607 :         sal_Int32 nBgn = m_aPagesCache.back();
     404                 :            : 
     405                 :            :         // Start adding pages while we can
     406 [ +  + ][ +  + ]:     154271 :         while( nToAdd > 0 && nBgn >= 0 )
                 [ +  + ]
     407                 :            :         {
     408         [ +  - ]:     109664 :             nBgn = pFat->GetNextPage( nBgn );
     409         [ +  + ]:     109664 :             if( nBgn >= 0 )
     410                 :            :             {
     411         [ +  - ]:     106052 :                 m_aPagesCache.push_back( nBgn );
     412                 :     106052 :                 nToAdd--;
     413                 :            :             }
     414                 :            :         }
     415                 :            :     }
     416                 :            : 
     417         [ +  + ]:      79684 :     if ( nIdx > m_aPagesCache.size() )
     418                 :            :     {
     419                 :         18 :         rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
     420                 :         18 :         nPage = STG_EOF;
     421                 :         18 :         nOffset = nPageSize;
     422                 :         18 :         return sal_False;
     423                 :            :     }
     424                 :            :     // special case: seek to 1st byte of new, unallocated page
     425                 :            :     // (in case the file size is a multiple of the page size)
     426 [ +  + ][ +  + ]:      79666 :     if( nBytePos == nSize && !nOffset && nIdx > 0 && nIdx == m_aPagesCache.size() )
         [ +  - ][ +  + ]
                 [ +  + ]
     427                 :            :     {
     428                 :       3594 :         nIdx--;
     429                 :       3594 :         nOffset = nPageSize;
     430                 :            :     }
     431         [ -  + ]:      76072 :     else if ( nIdx == m_aPagesCache.size() )
     432                 :            :     {
     433                 :          0 :         nPage = STG_EOF;
     434                 :          0 :         return sal_False;
     435                 :            :     }
     436                 :            : 
     437                 :      79666 :     nPage = m_aPagesCache[ nIdx ];
     438                 :            : 
     439                 :    4375258 :     return nPage >= 0;
     440                 :            : }
     441                 :            : 
     442                 :            : // Retrieve the physical page for a given byte offset.
     443                 :            : 
     444                 :          0 : StgPage* StgStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
     445                 :            : {
     446         [ #  # ]:          0 :     if( !Pos2Page( nBytePos ) )
     447                 :          0 :         return NULL;
     448                 :          0 :     return rIo.Get( nPage, bForce );
     449                 :            : }
     450                 :            : 
     451                 :            : // Copy an entire stream. Both streams are allocated in the FAT.
     452                 :            : // The target stream is this stream.
     453                 :            : 
     454                 :        159 : sal_Bool StgStrm::Copy( sal_Int32 nFrom, sal_Int32 nBytes )
     455                 :            : {
     456         [ -  + ]:        159 :     if ( !pFat )
     457                 :          0 :         return sal_False;
     458                 :            : 
     459                 :        159 :     m_aPagesCache.clear();
     460                 :            : 
     461                 :        159 :     sal_Int32 nTo = nStart;
     462                 :        159 :     sal_Int32 nPgs = ( nBytes + nPageSize - 1 ) / nPageSize;
     463         [ +  + ]:        532 :     while( nPgs-- )
     464                 :            :     {
     465         [ -  + ]:        373 :         if( nTo < 0 )
     466                 :            :         {
     467                 :          0 :             rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
     468                 :          0 :             return sal_False;
     469                 :            :         }
     470                 :        373 :         rIo.Copy( nTo, nFrom );
     471         [ -  + ]:        373 :         if( nFrom >= 0 )
     472                 :            :         {
     473                 :          0 :             nFrom = pFat->GetNextPage( nFrom );
     474         [ #  # ]:          0 :             if( nFrom < 0 )
     475                 :            :             {
     476                 :          0 :                 rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
     477                 :          0 :                 return sal_False;
     478                 :            :             }
     479                 :            :         }
     480                 :        373 :         nTo = pFat->GetNextPage( nTo );
     481                 :            :     }
     482                 :        159 :     return sal_True;
     483                 :            : }
     484                 :            : 
     485                 :      15087 : sal_Bool StgStrm::SetSize( sal_Int32 nBytes )
     486                 :            : {
     487 [ +  - ][ -  + ]:      15087 :     if ( nBytes < 0 || !pFat )
     488                 :          0 :         return sal_False;
     489                 :            : 
     490                 :      15087 :     m_aPagesCache.clear();
     491                 :            : 
     492                 :            :     // round up to page size
     493                 :      15087 :     sal_Int32 nOld = ( ( nSize + nPageSize - 1 ) / nPageSize ) * nPageSize;
     494                 :      15087 :     sal_Int32 nNew = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
     495         [ +  + ]:      15087 :     if( nNew > nOld )
     496                 :            :     {
     497         [ -  + ]:       2876 :         if( !Pos2Page( nSize ) )
     498                 :          0 :             return sal_False;
     499                 :       2876 :         sal_Int32 nBgn = pFat->AllocPages( nPage, ( nNew - nOld ) / nPageSize );
     500         [ -  + ]:       2876 :         if( nBgn == STG_EOF )
     501                 :          0 :             return sal_False;
     502         [ +  + ]:       2876 :         if( nStart == STG_EOF )
     503                 :       1232 :             nStart = nPage = nBgn;
     504                 :            :     }
     505         [ -  + ]:      12211 :     else if( nNew < nOld )
     506                 :            :     {
     507                 :          0 :         sal_Bool bAll = sal_Bool( nBytes == 0 );
     508 [ #  # ][ #  # ]:          0 :         if( !Pos2Page( nBytes ) || !pFat->FreePages( nPage, bAll ) )
                 [ #  # ]
     509                 :          0 :             return sal_False;
     510         [ #  # ]:          0 :         if( bAll )
     511                 :          0 :             nStart = nPage = STG_EOF;
     512                 :            :     }
     513         [ +  + ]:      15087 :     if( pEntry )
     514                 :            :     {
     515                 :            :         // change the dir entry?
     516 [ +  + ][ -  + ]:      13864 :         if( !nSize || !nBytes )
     517                 :       1016 :             pEntry->aEntry.SetLeaf( STG_DATA, nStart );
     518                 :      13864 :         pEntry->aEntry.SetSize( nBytes );
     519                 :      13864 :         pEntry->SetDirty();
     520                 :            :     }
     521                 :      15087 :     nSize = nBytes;
     522                 :      15087 :     pFat->SetLimit( GetPages() );
     523                 :      15087 :     return sal_True;
     524                 :            : }
     525                 :            : 
     526                 :            : // Return the # of allocated pages
     527                 :            : 
     528                 :      15237 : sal_Int32 StgStrm::GetPages() const
     529                 :            : {
     530                 :      15237 :     return ( nSize + nPageSize - 1 ) / nPageSize;
     531                 :            : }
     532                 :            : 
     533                 :            : //////////////////////////// class StgFATStrm //////////////////////////////
     534                 :            : 
     535                 :            : // The FAT stream class provides physical access to the master FAT.
     536                 :            : // Since this access is implemented as a StgStrm, we can use the
     537                 :            : // FAT allocator.
     538                 :            : 
     539                 :        367 : StgFATStrm::StgFATStrm( StgIo& r ) : StgStrm( r )
     540                 :            : {
     541         [ +  - ]:        367 :     pFat = new StgFAT( *this, sal_True );
     542                 :        367 :     nSize = rIo.aHdr.GetFATSize() * nPageSize;
     543                 :        367 : }
     544                 :            : 
     545                 :      85777 : sal_Bool StgFATStrm::Pos2Page( sal_Int32 nBytePos )
     546                 :            : {
     547                 :            :     // Values < 0 seek to the end
     548 [ +  - ][ +  + ]:      85777 :     if( nBytePos < 0 || nBytePos >= nSize  )
     549         [ +  - ]:         15 :         nBytePos = nSize ? nSize - 1 : 0;
     550                 :      85777 :     nPage   = nBytePos / nPageSize;
     551                 :      85777 :     nOffset = (short) ( nBytePos % nPageSize );
     552                 :      85777 :     nPos    = nBytePos;
     553                 :      85777 :     nPage   = GetPage( (short) nPage, sal_False );
     554                 :      85777 :     return sal_Bool( nPage >= 0 );
     555                 :            : }
     556                 :            : 
     557                 :            : // Retrieve the physical page for a given byte offset.
     558                 :            : // Since Pos2Page() already has computed the physical offset,
     559                 :            : // use the byte offset directly.
     560                 :            : 
     561                 :          0 : StgPage* StgFATStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
     562                 :            : {
     563                 :            :     OSL_ENSURE( nBytePos >= 0, "The value may not be negative!" );
     564                 :          0 :     return rIo.Get( nBytePos / ( nPageSize >> 2 ), bForce );
     565                 :            : }
     566                 :            : 
     567                 :            : // Get the page number entry for the given page offset.
     568                 :            : 
     569                 :      85864 : sal_Int32 StgFATStrm::GetPage( short nOff, sal_Bool bMake, sal_uInt16 *pnMasterAlloc )
     570                 :            : {
     571                 :            :     OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
     572         [ +  + ]:      85864 :     if( pnMasterAlloc ) *pnMasterAlloc = 0;
     573         [ +  - ]:      85864 :     if( nOff < rIo.aHdr.GetFAT1Size() )
     574                 :      85864 :         return rIo.aHdr.GetFATPage( nOff );
     575                 :          0 :     sal_Int32 nMaxPage = nSize >> 2;
     576                 :          0 :     nOff = nOff - rIo.aHdr.GetFAT1Size();
     577                 :            :     // Anzahl der Masterpages, durch die wir iterieren muessen
     578                 :          0 :     sal_uInt16 nMasterCount =  ( nPageSize >> 2 ) - 1;
     579                 :          0 :     sal_uInt16 nBlocks = nOff / nMasterCount;
     580                 :            :     // Offset in letzter Masterpage
     581                 :          0 :     nOff = nOff % nMasterCount;
     582                 :            : 
     583                 :          0 :     StgPage* pOldPage = 0;
     584                 :          0 :     StgPage* pMaster = 0;
     585                 :          0 :     sal_Int32 nFAT = rIo.aHdr.GetFATChain();
     586         [ #  # ]:          0 :     for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
     587                 :            :     {
     588 [ #  # ][ #  # ]:          0 :         if( nFAT == STG_EOF || nFAT == STG_FREE )
     589                 :            :         {
     590         [ #  # ]:          0 :             if( bMake )
     591                 :            :             {
     592                 :          0 :                 m_aPagesCache.clear();
     593                 :            : 
     594                 :            :                 // create a new master page
     595                 :          0 :                 nFAT = nMaxPage++;
     596                 :          0 :                 pMaster = rIo.Copy( nFAT, STG_FREE );
     597         [ #  # ]:          0 :                 if ( pMaster )
     598                 :            :                 {
     599         [ #  # ]:          0 :                     for( short k = 0; k < ( nPageSize >> 2 ); k++ )
     600                 :          0 :                         pMaster->SetPage( k, STG_FREE );
     601                 :            :                     // Verkettung herstellen
     602         [ #  # ]:          0 :                     if( !pOldPage )
     603                 :          0 :                         rIo.aHdr.SetFATChain( nFAT );
     604                 :            :                     else
     605                 :          0 :                         pOldPage->SetPage( nMasterCount, nFAT );
     606         [ #  # ]:          0 :                     if( nMaxPage >= rIo.GetPhysPages() )
     607         [ #  # ]:          0 :                         if( !rIo.SetSize( nMaxPage ) )
     608                 :          0 :                             return STG_EOF;
     609                 :            :                     // mark the page as used
     610                 :            :                     // Platz fuer Masterpage schaffen
     611         [ #  # ]:          0 :                     if( !pnMasterAlloc ) // Selbst Platz schaffen
     612                 :            :                     {
     613         [ #  # ]:          0 :                         if( !Pos2Page( nFAT << 2 ) )
     614                 :          0 :                             return STG_EOF;
     615                 :          0 :                         StgPage* pPg = rIo.Get( nPage, sal_True );
     616         [ #  # ]:          0 :                         if( !pPg )
     617                 :          0 :                             return STG_EOF;
     618                 :          0 :                         pPg->SetPage( nOffset >> 2, STG_MASTER );
     619                 :            :                     }
     620                 :            :                     else
     621                 :          0 :                         (*pnMasterAlloc)++;
     622                 :          0 :                     rIo.aHdr.SetMasters( nCount + 1 );
     623                 :          0 :                     pOldPage = pMaster;
     624                 :            :                 }
     625                 :          0 :             }
     626                 :            :         }
     627                 :            :         else
     628                 :            :         {
     629                 :          0 :             pMaster = rIo.Get( nFAT, sal_True );
     630         [ #  # ]:          0 :             if ( pMaster )
     631                 :            :             {
     632                 :          0 :                 nFAT = pMaster->GetPage( nMasterCount );
     633                 :          0 :                 pOldPage = pMaster;
     634                 :            :             }
     635                 :            :         }
     636                 :            :     }
     637         [ #  # ]:          0 :     if( pMaster )
     638                 :          0 :         return pMaster->GetPage( nOff );
     639                 :          0 :     rIo.SetError( SVSTREAM_GENERALERROR );
     640                 :      85864 :     return STG_EOF;
     641                 :            : }
     642                 :            : 
     643                 :            : 
     644                 :            : // Set the page number entry for the given page offset.
     645                 :            : 
     646                 :         87 : sal_Bool StgFATStrm::SetPage( short nOff, sal_Int32 nNewPage )
     647                 :            : {
     648                 :            :     OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
     649                 :         87 :     m_aPagesCache.clear();
     650                 :            : 
     651                 :         87 :     sal_Bool bRes = sal_True;
     652         [ +  - ]:         87 :     if( nOff < rIo.aHdr.GetFAT1Size() )
     653                 :         87 :         rIo.aHdr.SetFATPage( nOff, nNewPage );
     654                 :            :     else
     655                 :            :     {
     656                 :          0 :         nOff = nOff - rIo.aHdr.GetFAT1Size();
     657                 :            :         // Anzahl der Masterpages, durch die wir iterieren muessen
     658                 :          0 :         sal_uInt16 nMasterCount =  ( nPageSize >> 2 ) - 1;
     659                 :          0 :         sal_uInt16 nBlocks = nOff / nMasterCount;
     660                 :            :         // Offset in letzter Masterpage
     661                 :          0 :         nOff = nOff % nMasterCount;
     662                 :            : 
     663                 :          0 :         StgPage* pMaster = 0;
     664                 :          0 :         sal_Int32 nFAT = rIo.aHdr.GetFATChain();
     665         [ #  # ]:          0 :         for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
     666                 :            :         {
     667 [ #  # ][ #  # ]:          0 :             if( nFAT == STG_EOF || nFAT == STG_FREE )
     668                 :            :             {
     669                 :          0 :                 pMaster = 0;
     670                 :          0 :                 break;
     671                 :            :             }
     672                 :          0 :             pMaster = rIo.Get( nFAT, sal_True );
     673         [ #  # ]:          0 :             if ( pMaster )
     674                 :          0 :                 nFAT = pMaster->GetPage( nMasterCount );
     675                 :            :         }
     676         [ #  # ]:          0 :         if( pMaster )
     677                 :          0 :             pMaster->SetPage( nOff, nNewPage );
     678                 :            :         else
     679                 :            :         {
     680                 :          0 :             rIo.SetError( SVSTREAM_GENERALERROR );
     681                 :          0 :             bRes = sal_False;
     682                 :            :         }
     683                 :            :     }
     684                 :            : 
     685                 :            :     // lock the page against access
     686         [ +  - ]:         87 :     if( bRes )
     687                 :            :     {
     688                 :         87 :         Pos2Page( nNewPage << 2 );
     689                 :         87 :         StgPage* pPg = rIo.Get( nPage, sal_True );
     690         [ +  - ]:         87 :         if( pPg )
     691                 :         87 :             pPg->SetPage( nOffset >> 2, STG_FAT );
     692                 :            :         else
     693                 :          0 :             bRes = sal_False;
     694                 :            :     }
     695                 :         87 :     return bRes;
     696                 :            : }
     697                 :            : 
     698                 :         87 : sal_Bool StgFATStrm::SetSize( sal_Int32 nBytes )
     699                 :            : {
     700         [ -  + ]:         87 :     if ( nBytes < 0 )
     701                 :          0 :         return sal_False;
     702                 :            : 
     703                 :         87 :     m_aPagesCache.clear();
     704                 :            : 
     705                 :            :     // Set the number of entries to a multiple of the page size
     706                 :         87 :     short nOld = (short) ( ( nSize + ( nPageSize - 1 ) ) / nPageSize );
     707                 :            :     short nNew = (short) (
     708                 :         87 :         ( nBytes + ( nPageSize - 1 ) ) / nPageSize ) ;
     709         [ -  + ]:         87 :     if( nNew < nOld )
     710                 :            :     {
     711                 :            :         // release master pages
     712         [ #  # ]:          0 :         for( short i = nNew; i < nOld; i++ )
     713                 :          0 :             SetPage( i, STG_FREE );
     714                 :            :     }
     715                 :            :     else
     716                 :            :     {
     717         [ +  + ]:        174 :         while( nOld < nNew )
     718                 :            :         {
     719                 :            :             // allocate master pages
     720                 :            :             // find a free master page slot
     721                 :         87 :             sal_Int32 nPg = 0;
     722                 :         87 :             sal_uInt16 nMasterAlloc = 0;
     723         [ +  - ]:         87 :             nPg = GetPage( nOld, sal_True, &nMasterAlloc );
     724         [ -  + ]:         87 :             if( nPg == STG_EOF )
     725                 :          0 :                 return sal_False;
     726                 :            :             // 4 Bytes have been used for Allocation of each MegaMasterPage
     727                 :         87 :             nBytes += nMasterAlloc << 2;
     728                 :            : 
     729                 :            :             // find a free page using the FAT allocator
     730                 :         87 :             sal_Int32 n = 1;
     731                 :            :             OSL_ENSURE( pFat, "The pointer is always initializer here!" );
     732         [ +  - ]:         87 :             sal_Int32 nNewPage = pFat->FindBlock( n );
     733         [ +  - ]:         87 :             if( nNewPage == STG_EOF )
     734                 :            :             {
     735                 :            :                 // no free pages found; create a new page
     736                 :            :                 // Since all pages are allocated, extend
     737                 :            :                 // the file size for the next page!
     738                 :         87 :                 nNewPage = nSize >> 2;
     739                 :            :                 // if a MegaMasterPage was created avoid taking
     740                 :            :                 // the same Page
     741                 :         87 :                 nNewPage += nMasterAlloc;
     742                 :            :                 // adjust the file size if necessary
     743         [ +  - ]:         87 :                 if( nNewPage >= rIo.GetPhysPages() )
     744 [ +  - ][ -  + ]:         87 :                     if( !rIo.SetSize( nNewPage + 1 ) )
     745                 :          0 :                         return sal_False;
     746                 :            :             }
     747                 :            :             // Set up the page with empty entries
     748         [ +  - ]:         87 :             StgPage* pPg = rIo.Copy( nNewPage, STG_FREE );
     749         [ -  + ]:         87 :             if ( !pPg )
     750                 :          0 :                 return sal_False;
     751         [ +  + ]:      11223 :             for( short j = 0; j < ( nPageSize >> 2 ); j++ )
     752         [ +  - ]:      11136 :                 pPg->SetPage( j, STG_FREE );
     753                 :            : 
     754                 :            :             // store the page number into the master FAT
     755                 :            :             // Set the size before so the correct FAT can be found
     756                 :         87 :             nSize = ( nOld + 1 ) * nPageSize;
     757         [ +  - ]:         87 :             SetPage( nOld, nNewPage );
     758                 :            : 
     759                 :            :             // MegaMasterPages were created, mark it them as used
     760                 :            : 
     761                 :         87 :             sal_uInt32 nMax = rIo.aHdr.GetMasters( );
     762                 :         87 :             sal_uInt32 nFAT = rIo.aHdr.GetFATChain();
     763         [ -  + ]:         87 :             if( nMasterAlloc )
     764         [ #  # ]:          0 :                 for( sal_uInt16 nCount = 0; nCount < nMax; nCount++ )
     765                 :            :                 {
     766 [ #  # ][ #  # ]:          0 :                     if( !Pos2Page( nFAT << 2 ) )
     767                 :          0 :                         return sal_False;
     768         [ #  # ]:          0 :                     if( nMax - nCount <= nMasterAlloc )
     769                 :            :                     {
     770         [ #  # ]:          0 :                         StgPage* piPg = rIo.Get( nPage, sal_True );
     771         [ #  # ]:          0 :                         if( !piPg )
     772                 :          0 :                             return sal_False;
     773         [ #  # ]:          0 :                         piPg->SetPage( nOffset >> 2, STG_MASTER );
     774                 :            :                     }
     775         [ #  # ]:          0 :                     StgPage* pPage = rIo.Get( nFAT, sal_True );
     776         [ #  # ]:          0 :                     if( !pPage ) return sal_False;
     777                 :          0 :                     nFAT = pPage->GetPage( (nPageSize >> 2 ) - 1 );
     778                 :            :                 }
     779                 :            : 
     780                 :         87 :             nOld++;
     781                 :            :             // We have used up 4 bytes for the STG_FAT entry
     782                 :         87 :             nBytes += 4;
     783                 :            :             nNew = (short) (
     784                 :         87 :                 ( nBytes + ( nPageSize - 1 ) ) / nPageSize );
     785                 :            :         }
     786                 :            :     }
     787                 :         87 :     nSize = nNew * nPageSize;
     788                 :         87 :     rIo.aHdr.SetFATSize( nNew );
     789                 :         87 :     return sal_True;
     790                 :            : }
     791                 :            : 
     792                 :            : /////////////////////////// class StgDataStrm //////////////////////////////
     793                 :            : 
     794                 :            : // This class is a normal physical stream which can be initialized
     795                 :            : // either with an existing dir entry or an existing FAT chain.
     796                 :            : // The stream has a size increment which normally is 1, but which can be
     797                 :            : // set to any value is you want the size to be incremented by certain values.
     798                 :            : 
     799                 :        810 : StgDataStrm::StgDataStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
     800                 :            : {
     801         [ +  - ]:        810 :     Init( nBgn, nLen );
     802                 :        810 : }
     803                 :            : 
     804                 :       1070 : StgDataStrm::StgDataStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
     805                 :            : {
     806                 :       1070 :     pEntry = &p;
     807                 :            :     Init( p.aEntry.GetLeaf( STG_DATA ),
     808 [ +  - ][ +  - ]:       1070 :           p.aEntry.GetSize() );
     809                 :       1070 : }
     810                 :            : 
     811                 :       1880 : void StgDataStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
     812                 :            : {
     813         [ +  - ]:       1880 :     if ( rIo.pFAT )
     814                 :       1880 :         pFat = new StgFAT( *rIo.pFAT, sal_True );
     815                 :            : 
     816                 :            :     OSL_ENSURE( pFat, "The pointer should not be empty!" );
     817                 :            : 
     818                 :       1880 :     nStart = nPage = nBgn;
     819                 :       1880 :     nSize  = nLen;
     820                 :       1880 :     nIncr  = 1;
     821                 :       1880 :     nOffset = 0;
     822 [ +  + ][ +  - ]:       1880 :     if( nLen < 0 && pFat )
     823                 :            :     {
     824                 :            :         // determine the actual size of the stream by scanning
     825                 :            :         // the FAT chain and counting the # of pages allocated
     826                 :        725 :         scanBuildPageChainCache( &nSize );
     827                 :            :     }
     828                 :       1880 : }
     829                 :            : 
     830                 :            : // Set the size of a physical stream.
     831                 :            : 
     832                 :      13149 : sal_Bool StgDataStrm::SetSize( sal_Int32 nBytes )
     833                 :            : {
     834         [ -  + ]:      13149 :     if ( !pFat )
     835                 :          0 :         return sal_False;
     836                 :            : 
     837                 :      13149 :     nBytes = ( ( nBytes + nIncr - 1 ) / nIncr ) * nIncr;
     838                 :      13149 :     sal_Int32 nOldSz = nSize;
     839         [ +  - ]:      13149 :     if( ( nOldSz != nBytes ) )
     840                 :            :     {
     841         [ -  + ]:      13149 :         if( !StgStrm::SetSize( nBytes ) )
     842                 :          0 :             return sal_False;
     843                 :      13149 :         sal_Int32 nMaxPage = pFat->GetMaxPage();
     844         [ +  + ]:      13149 :         if( nMaxPage > rIo.GetPhysPages() )
     845         [ -  + ]:       1879 :             if( !rIo.SetSize( nMaxPage ) )
     846                 :          0 :                 return sal_False;
     847                 :            :         // If we only allocated one page or less, create this
     848                 :            :         // page in the cache for faster throughput. The current
     849                 :            :         // position is the former EOF point.
     850         [ +  + ]:      13149 :         if( ( nSize - 1 )  / nPageSize - ( nOldSz - 1 ) / nPageSize == 1 )
     851                 :            :         {
     852                 :       1644 :             Pos2Page( nBytes );
     853         [ +  - ]:       1644 :             if( nPage >= 0 )
     854                 :       1644 :                 rIo.Copy( nPage, STG_FREE );
     855                 :            :         }
     856                 :            :     }
     857                 :      13149 :     return sal_True;
     858                 :            : }
     859                 :            : 
     860                 :            : // Get the address of the data byte at a specified offset.
     861                 :            : // If bForce = sal_True, a read of non-existent data causes
     862                 :            : // a read fault.
     863                 :            : 
     864                 :       4482 : void* StgDataStrm::GetPtr( sal_Int32 Pos, sal_Bool bForce, sal_Bool bDirty )
     865                 :            : {
     866         [ +  - ]:       4482 :     if( Pos2Page( Pos ) )
     867                 :            :     {
     868                 :       4482 :         StgPage* pPg = rIo.Get( nPage, bForce );
     869 [ +  - ][ +  - ]:       4482 :         if (pPg && nOffset < pPg->GetSize())
                 [ +  - ]
     870                 :            :         {
     871                 :       4482 :             pPg->SetOwner( pEntry );
     872         [ +  + ]:       4482 :             if( bDirty )
     873                 :       1492 :                 pPg->SetDirty();
     874                 :       4482 :             return ((sal_uInt8 *)pPg->GetData()) + nOffset;
     875                 :            :         }
     876                 :            :     }
     877                 :       4482 :     return NULL;
     878                 :            : }
     879                 :            : 
     880                 :            : // This could easily be adapted to a better algorithm by determining
     881                 :            : // the amount of consecutable blocks before doing a read. The result
     882                 :            : // is the number of bytes read. No error is generated on EOF.
     883                 :            : 
     884                 :    2263035 : sal_Int32 StgDataStrm::Read( void* pBuf, sal_Int32 n )
     885                 :            : {
     886         [ -  + ]:    2263035 :     if ( n < 0 )
     887                 :          0 :         return 0;
     888                 :            : 
     889         [ +  + ]:    2263035 :     if( ( nPos + n ) > nSize )
     890                 :      73425 :         n = nSize - nPos;
     891                 :    2263035 :     sal_Int32 nDone = 0;
     892         [ +  + ]:    4468172 :     while( n )
     893                 :            :     {
     894                 :    2205152 :         short nBytes = nPageSize - nOffset;
     895                 :            :         StgPage* pPg;
     896         [ +  + ]:    2205152 :         if( (sal_Int32) nBytes > n )
     897                 :    2183023 :             nBytes = (short) n;
     898         [ +  - ]:    2205152 :         if( nBytes )
     899                 :            :         {
     900                 :            :             short nRes;
     901                 :    2205152 :             void *p = (sal_uInt8 *) pBuf + nDone;
     902         [ +  + ]:    2205152 :             if( nBytes == nPageSize )
     903                 :            :             {
     904                 :      14320 :                 pPg = rIo.Find( nPage );
     905         [ +  + ]:      14320 :                 if( pPg )
     906                 :            :                 {
     907                 :            :                     // data is present, so use the cached data
     908                 :        217 :                     pPg->SetOwner( pEntry );
     909                 :        217 :                     memcpy( p, pPg->GetData(), nBytes );
     910                 :        217 :                     nRes = nBytes;
     911                 :            :                 }
     912                 :            :                 else
     913                 :            :                     // do a direct (unbuffered) read
     914                 :      14103 :                     nRes = (short) rIo.Read( nPage, p, 1 ) * nPageSize;
     915                 :            :             }
     916                 :            :             else
     917                 :            :             {
     918                 :            :                 // partial block read thru the cache.
     919                 :    2190832 :                 pPg = rIo.Get( nPage, sal_False );
     920         [ -  + ]:    2190832 :                 if( !pPg )
     921                 :          0 :                     break;
     922                 :    2190832 :                 pPg->SetOwner( pEntry );
     923                 :    2190832 :                 memcpy( p, (sal_uInt8*)pPg->GetData() + nOffset, nBytes );
     924                 :    2190832 :                 nRes = nBytes;
     925                 :            :             }
     926                 :    2205152 :             nDone += nRes;
     927                 :    2205152 :             nPos += nRes;
     928                 :    2205152 :             n -= nRes;
     929                 :    2205152 :             nOffset = nOffset + nRes;
     930         [ +  + ]:    2205152 :             if( nRes != nBytes )
     931                 :         15 :                 break;  // read error or EOF
     932                 :            :         }
     933                 :            :         // Switch to next page if necessary
     934 [ +  + ][ -  + ]:    2205137 :         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
                 [ -  + ]
     935                 :          0 :             break;
     936                 :            :     }
     937                 :    2263035 :     return nDone;
     938                 :            : }
     939                 :            : 
     940                 :      13229 : sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n )
     941                 :            : {
     942         [ -  + ]:      13229 :     if ( n < 0 )
     943                 :          0 :         return 0;
     944                 :            : 
     945                 :      13229 :     sal_Int32 nDone = 0;
     946         [ -  + ]:      13229 :     if( ( nPos + n ) > nSize )
     947                 :            :     {
     948                 :          0 :         sal_Int32 nOld = nPos;
     949         [ #  # ]:          0 :         if( !SetSize( nPos + n ) )
     950                 :          0 :             return 0;
     951                 :          0 :         Pos2Page( nOld );
     952                 :            :     }
     953         [ +  + ]:      28313 :     while( n )
     954                 :            :     {
     955                 :      15084 :         short nBytes = nPageSize - nOffset;
     956                 :            :         StgPage* pPg;
     957         [ +  + ]:      15084 :         if( (sal_Int32) nBytes > n )
     958                 :      11526 :             nBytes = (short) n;
     959         [ +  - ]:      15084 :         if( nBytes )
     960                 :            :         {
     961                 :            :             short nRes;
     962                 :      15084 :             const void *p = (const sal_uInt8 *) pBuf + nDone;
     963         [ +  + ]:      15084 :             if( nBytes == nPageSize )
     964                 :            :             {
     965                 :       2076 :                 pPg = rIo.Find( nPage );
     966         [ -  + ]:       2076 :                 if( pPg )
     967                 :            :                 {
     968                 :            :                     // data is present, so use the cached data
     969                 :          0 :                     pPg->SetOwner( pEntry );
     970                 :          0 :                     memcpy( pPg->GetData(), p, nBytes );
     971                 :          0 :                     pPg->SetDirty();
     972                 :          0 :                     nRes = nBytes;
     973                 :            :                 }
     974                 :            :                 else
     975                 :            :                     // do a direct (unbuffered) write
     976                 :       2076 :                     nRes = (short) rIo.Write( nPage, (void*) p, 1 ) * nPageSize;
     977                 :            :             }
     978                 :            :             else
     979                 :            :             {
     980                 :            :                 // partial block read thru the cache.
     981                 :      13008 :                 pPg = rIo.Get( nPage, sal_False );
     982         [ -  + ]:      13008 :                 if( !pPg )
     983                 :          0 :                     break;
     984                 :      13008 :                 pPg->SetOwner( pEntry );
     985                 :      13008 :                 memcpy( (sal_uInt8*)pPg->GetData() + nOffset, p, nBytes );
     986                 :      13008 :                 pPg->SetDirty();
     987                 :      13008 :                 nRes = nBytes;
     988                 :            :             }
     989                 :      15084 :             nDone += nRes;
     990                 :      15084 :             nPos += nRes;
     991                 :      15084 :             n -= nRes;
     992                 :      15084 :             nOffset = nOffset + nRes;
     993         [ -  + ]:      15084 :             if( nRes != nBytes )
     994                 :          0 :                 break;  // read error
     995                 :            :         }
     996                 :            :         // Switch to next page if necessary
     997 [ +  + ][ -  + ]:      15084 :         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
                 [ -  + ]
     998                 :          0 :             break;
     999                 :            :     }
    1000                 :      13229 :     return nDone;
    1001                 :            : }
    1002                 :            : 
    1003                 :            : //////////////////////////// class StgSmallStream ///////////////////////////
    1004                 :            : 
    1005                 :            : // The small stream class provides access to streams with a size < 4096 bytes.
    1006                 :            : // This stream is a StgStream containing small pages. The FAT for this stream
    1007                 :            : // is also a StgStream. The start of the FAT is in the header at DataRootPage,
    1008                 :            : // the stream itself is pointed to by the root entry (it holds start & size).
    1009                 :            : 
    1010                 :        838 : StgSmallStrm::StgSmallStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
    1011                 :            : {
    1012         [ +  - ]:        838 :     Init( nBgn, nLen );
    1013                 :        838 : }
    1014                 :            : 
    1015                 :       2515 : StgSmallStrm::StgSmallStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
    1016                 :            : {
    1017                 :       2515 :     pEntry = &p;
    1018                 :            :     Init( p.aEntry.GetLeaf( STG_DATA ),
    1019 [ +  - ][ +  - ]:       2515 :           p.aEntry.GetSize() );
    1020                 :       2515 : }
    1021                 :            : 
    1022                 :       3353 : void StgSmallStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
    1023                 :            : {
    1024         [ +  - ]:       3353 :     if ( rIo.pDataFAT )
    1025                 :       3353 :         pFat = new StgFAT( *rIo.pDataFAT, sal_False );
    1026                 :       3353 :     pData = rIo.pDataStrm;
    1027                 :            :     OSL_ENSURE( pFat && pData, "The pointers should not be empty!" );
    1028                 :            : 
    1029                 :       3353 :     nPageSize = rIo.GetDataPageSize();
    1030                 :            :     nStart =
    1031                 :       3353 :     nPage  = nBgn;
    1032                 :       3353 :     nSize  = nLen;
    1033                 :       3353 : }
    1034                 :            : 
    1035                 :            : // This could easily be adapted to a better algorithm by determining
    1036                 :            : // the amount of consecutable blocks before doing a read. The result
    1037                 :            : // is the number of bytes read. No error is generated on EOF.
    1038                 :            : 
    1039                 :      14515 : sal_Int32 StgSmallStrm::Read( void* pBuf, sal_Int32 n )
    1040                 :            : {
    1041                 :            :     // We can safely assume that reads are not huge, since the
    1042                 :            :     // small stream is likely to be < 64 KBytes.
    1043         [ +  + ]:      14515 :     if( ( nPos + n ) > nSize )
    1044                 :       1585 :         n = nSize - nPos;
    1045                 :      14515 :     short nDone = 0;
    1046         [ +  + ]:      47362 :     while( n )
    1047                 :            :     {
    1048                 :      32850 :         short nBytes = nPageSize - nOffset;
    1049         [ +  + ]:      32850 :         if( (sal_Int32) nBytes > n )
    1050                 :      13560 :             nBytes = (short) n;
    1051         [ +  - ]:      32850 :         if( nBytes )
    1052                 :            :         {
    1053 [ +  - ][ -  + ]:      32850 :             if( !pData || !pData->Pos2Page( nPage * nPageSize + nOffset ) )
                 [ -  + ]
    1054                 :          0 :                 break;
    1055                 :            :             // all reading thru the stream
    1056                 :      32850 :             short nRes = (short) pData->Read( (sal_uInt8*)pBuf + nDone, nBytes );
    1057                 :      32850 :             nDone = nDone + nRes;
    1058                 :      32850 :             nPos += nRes;
    1059                 :      32850 :             n -= nRes;
    1060                 :      32850 :             nOffset = nOffset + nRes;
    1061                 :            :             // read problem?
    1062         [ +  + ]:      32850 :             if( nRes != nBytes )
    1063                 :          3 :                 break;
    1064                 :            :         }
    1065                 :            :         // Switch to next page if necessary
    1066 [ +  + ][ -  + ]:      32847 :         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
                 [ -  + ]
    1067                 :          0 :             break;
    1068                 :            :     }
    1069                 :      14515 :     return nDone;
    1070                 :            : }
    1071                 :            : 
    1072                 :        838 : sal_Int32 StgSmallStrm::Write( const void* pBuf, sal_Int32 n )
    1073                 :            : {
    1074                 :            :     // you can safely assume that reads are not huge, since the
    1075                 :            :     // small stream is likely to be < 64 KBytes.
    1076                 :        838 :     short nDone = 0;
    1077         [ -  + ]:        838 :     if( ( nPos + n ) > nSize )
    1078                 :            :     {
    1079                 :          0 :         sal_Int32 nOld = nPos;
    1080         [ #  # ]:          0 :         if( !SetSize( nPos + n ) )
    1081                 :          0 :             return sal_False;
    1082                 :          0 :         Pos2Page( nOld );
    1083                 :            :     }
    1084         [ +  + ]:      13761 :     while( n )
    1085                 :            :     {
    1086                 :      12923 :         short nBytes = nPageSize - nOffset;
    1087         [ +  + ]:      12923 :         if( (sal_Int32) nBytes > n )
    1088                 :        754 :             nBytes = (short) n;
    1089         [ +  - ]:      12923 :         if( nBytes )
    1090                 :            :         {
    1091                 :            :             // all writing goes thru the stream
    1092                 :      12923 :             sal_Int32 nDataPos = nPage * nPageSize + nOffset;
    1093   [ +  -  +  -  :      38769 :             if ( !pData
           -  + ][ -  + ]
    1094                 :      12923 :               || ( pData->GetSize() < ( nDataPos + nBytes )
    1095                 :      12923 :                 && !pData->SetSize( nDataPos + nBytes ) ) )
    1096                 :          0 :                 break;
    1097         [ -  + ]:      12923 :             if( !pData->Pos2Page( nDataPos ) )
    1098                 :          0 :                 break;
    1099                 :      12923 :             short nRes = (short) pData->Write( (sal_uInt8*)pBuf + nDone, nBytes );
    1100                 :      12923 :             nDone = nDone + nRes;
    1101                 :      12923 :             nPos += nRes;
    1102                 :      12923 :             n -= nRes;
    1103                 :      12923 :             nOffset = nOffset + nRes;
    1104                 :            :             // write problem?
    1105         [ -  + ]:      12923 :             if( nRes != nBytes )
    1106                 :          0 :                 break;
    1107                 :            :         }
    1108                 :            :         // Switch to next page if necessary
    1109 [ +  + ][ -  + ]:      12923 :         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
                 [ -  + ]
    1110                 :          0 :             break;
    1111                 :            :     }
    1112                 :        838 :     return nDone;
    1113                 :            : }
    1114                 :            : 
    1115                 :            : /////////////////////////// class StgTmpStrm /////////////////////////////
    1116                 :            : 
    1117                 :            : // The temporary stream uses a memory stream if < 32K, otherwise a
    1118                 :            : // temporary file.
    1119                 :            : 
    1120                 :            : #define THRESHOLD 32768L
    1121                 :            : 
    1122                 :        932 : StgTmpStrm::StgTmpStrm( sal_uLong nInitSize )
    1123                 :            :           : SvMemoryStream( nInitSize > THRESHOLD
    1124                 :            :                               ? 16
    1125 [ +  - ][ +  + ]:        932 :                             : ( nInitSize ? nInitSize : 16 ), 4096 )
                 [ +  - ]
    1126                 :            : {
    1127                 :        932 :     pStrm = NULL;
    1128                 :            :     // this calls FlushData, so all members should be set by this time
    1129         [ +  - ]:        932 :     SetBufferSize( 0 );
    1130         [ -  + ]:        932 :     if( nInitSize > THRESHOLD )
    1131         [ #  # ]:          0 :         SetSize( nInitSize );
    1132                 :        932 : }
    1133                 :            : 
    1134                 :          9 : sal_Bool StgTmpStrm::Copy( StgTmpStrm& rSrc )
    1135                 :            : {
    1136                 :          9 :     sal_uLong n    = rSrc.GetSize();
    1137                 :          9 :     sal_uLong nCur = rSrc.Tell();
    1138                 :          9 :     SetSize( n );
    1139         [ +  - ]:          9 :     if( GetError() == SVSTREAM_OK )
    1140                 :            :     {
    1141                 :          9 :         sal_uInt8* p = new sal_uInt8[ 4096 ];
    1142                 :          9 :         rSrc.Seek( 0L );
    1143                 :          9 :         Seek( 0L );
    1144         [ +  + ]:         18 :         while( n )
    1145                 :            :         {
    1146                 :          9 :             sal_uLong nn = n;
    1147         [ -  + ]:          9 :             if( nn > 4096 )
    1148                 :          0 :                 nn = 4096;
    1149         [ -  + ]:          9 :             if( rSrc.Read( p, nn ) != nn )
    1150                 :          0 :                 break;
    1151         [ -  + ]:          9 :             if( Write( p, nn ) != nn )
    1152                 :          0 :                 break;
    1153                 :          9 :             n -= nn;
    1154                 :            :         }
    1155         [ +  - ]:          9 :         delete [] p;
    1156                 :          9 :         rSrc.Seek( nCur );
    1157                 :          9 :         Seek( nCur );
    1158                 :          9 :         return sal_Bool( n == 0 );
    1159                 :            :     }
    1160                 :            :     else
    1161                 :          9 :         return sal_False;
    1162                 :            : }
    1163                 :            : 
    1164         [ +  - ]:        932 : StgTmpStrm::~StgTmpStrm()
    1165                 :            : {
    1166         [ -  + ]:        932 :     if( pStrm )
    1167                 :            :     {
    1168         [ #  # ]:          0 :         pStrm->Close();
    1169 [ #  # ][ #  # ]:          0 :         osl::File::remove( aName );
    1170 [ #  # ][ #  # ]:          0 :         delete pStrm;
    1171                 :            :     }
    1172         [ -  + ]:       1864 : }
    1173                 :            : 
    1174                 :       1558 : sal_uLong StgTmpStrm::GetSize() const
    1175                 :            : {
    1176                 :            :     sal_uLong n;
    1177         [ -  + ]:       1558 :     if( pStrm )
    1178                 :            :     {
    1179                 :          0 :         sal_uLong old = pStrm->Tell();
    1180                 :          0 :         n = pStrm->Seek( STREAM_SEEK_TO_END );
    1181                 :          0 :         pStrm->Seek( old );
    1182                 :            :     }
    1183                 :            :     else
    1184                 :       1558 :         n = nEndOfData;
    1185                 :       1558 :     return n;
    1186                 :            : }
    1187                 :            : 
    1188                 :        482 : void StgTmpStrm::SetSize( sal_uLong n )
    1189                 :            : {
    1190         [ -  + ]:        482 :     if( pStrm )
    1191                 :          0 :         pStrm->SetStreamSize( n );
    1192                 :            :     else
    1193                 :            :     {
    1194         [ -  + ]:        482 :         if( n > THRESHOLD )
    1195                 :            :         {
    1196 [ #  # ][ #  # ]:          0 :             aName = TempFile::CreateTempName();
                 [ #  # ]
    1197 [ #  # ][ #  # ]:          0 :             SvFileStream* s = new SvFileStream( aName, STREAM_READWRITE );
    1198                 :          0 :             sal_uLong nCur = Tell();
    1199                 :          0 :             sal_uLong i = nEndOfData;
    1200         [ #  # ]:          0 :             if( i )
    1201                 :            :             {
    1202         [ #  # ]:          0 :                 sal_uInt8* p = new sal_uInt8[ 4096 ];
    1203         [ #  # ]:          0 :                 Seek( 0L );
    1204         [ #  # ]:          0 :                 while( i )
    1205                 :            :                 {
    1206                 :          0 :                     sal_uLong nb = ( i > 4096 ) ? 4096 : i;
    1207 [ #  # ][ #  # ]:          0 :                     if( Read( p, nb ) == nb
         [ #  # ][ #  # ]
    1208         [ #  # ]:          0 :                      && s->Write( p, nb ) == nb )
    1209                 :          0 :                         i -= nb;
    1210                 :            :                     else
    1211                 :          0 :                         break;
    1212                 :            :                 }
    1213         [ #  # ]:          0 :                 delete [] p;
    1214                 :            :             }
    1215 [ #  # ][ #  # ]:          0 :             if( !i && n > nEndOfData )
    1216                 :            :             {
    1217                 :            :                 // We have to write one byte at the end of the file
    1218                 :            :                 // if the file is bigger than the memstream to see
    1219                 :            :                 // if it fits on disk
    1220         [ #  # ]:          0 :                 s->Seek( n - 1 );
    1221         [ #  # ]:          0 :                 s->Write( &i, 1 );
    1222         [ #  # ]:          0 :                 s->Flush();
    1223         [ #  # ]:          0 :                 if( s->GetError() != SVSTREAM_OK )
    1224                 :          0 :                     i = 1;
    1225                 :            :             }
    1226         [ #  # ]:          0 :             Seek( nCur );
    1227         [ #  # ]:          0 :             s->Seek( nCur );
    1228         [ #  # ]:          0 :             if( i )
    1229                 :            :             {
    1230         [ #  # ]:          0 :                 SetError( s->GetError() );
    1231 [ #  # ][ #  # ]:          0 :                 delete s;
    1232                 :        482 :                 return;
    1233                 :            :             }
    1234                 :          0 :             pStrm = s;
    1235                 :            :             // Shrink the memory to 16 bytes, which seems to be the minimum
    1236         [ #  # ]:          0 :             ReAllocateMemory( - ( (long) nEndOfData - 16 ) );
    1237                 :            :         }
    1238                 :            :         else
    1239                 :            :         {
    1240         [ +  + ]:        482 :             if( n > nEndOfData )
    1241                 :            :             {
    1242                 :        464 :                 sal_uLong nCur = Tell();
    1243                 :        464 :                 Seek( nEndOfData - 1 );
    1244                 :        464 :                 *this << (sal_uInt8) 0;
    1245                 :        464 :                 Seek( nCur );
    1246                 :            :             }
    1247                 :            :             else
    1248                 :         18 :                 nEndOfData = n;
    1249                 :            :         }
    1250                 :            :     }
    1251                 :            : }
    1252                 :            : 
    1253                 :       1153 : sal_uLong StgTmpStrm::GetData( void* pData, sal_uLong n )
    1254                 :            : {
    1255         [ -  + ]:       1153 :     if( pStrm )
    1256                 :            :     {
    1257                 :          0 :         n = pStrm->Read( pData, n );
    1258                 :          0 :         SetError( pStrm->GetError() );
    1259                 :          0 :         return n;
    1260                 :            :     }
    1261                 :            :     else
    1262                 :       1153 :         return SvMemoryStream::GetData( (sal_Char *)pData, n );
    1263                 :            : }
    1264                 :            : 
    1265                 :       2513 : sal_uLong StgTmpStrm::PutData( const void* pData, sal_uLong n )
    1266                 :            : {
    1267                 :       2513 :     sal_uInt32 nCur = Tell();
    1268                 :       2513 :     sal_uInt32 nNew = nCur + n;
    1269 [ #  # ][ -  + ]:       2513 :     if( nNew > THRESHOLD && !pStrm )
    1270                 :            :     {
    1271                 :          0 :         SetSize( nNew );
    1272         [ #  # ]:          0 :         if( GetError() != SVSTREAM_OK )
    1273                 :          0 :             return 0;
    1274                 :            :     }
    1275         [ -  + ]:       2513 :     if( pStrm )
    1276                 :            :     {
    1277                 :          0 :         nNew = pStrm->Write( pData, n );
    1278                 :          0 :         SetError( pStrm->GetError() );
    1279                 :            :     }
    1280                 :            :     else
    1281                 :       2513 :         nNew = SvMemoryStream::PutData( (sal_Char*)pData, n );
    1282                 :       2513 :     return nNew;
    1283                 :            : }
    1284                 :            : 
    1285                 :       5736 : sal_uLong StgTmpStrm::SeekPos( sal_uLong n )
    1286                 :            : {
    1287         [ +  + ]:       5736 :     if( n == STREAM_SEEK_TO_END )
    1288                 :        464 :         n = GetSize();
    1289 [ +  + ][ -  + ]:       5736 :     if( n && n > THRESHOLD && !pStrm )
                 [ #  # ]
    1290                 :            :     {
    1291                 :          0 :         SetSize( n );
    1292         [ #  # ]:          0 :         if( GetError() != SVSTREAM_OK )
    1293                 :          0 :             return Tell();
    1294                 :            :         else
    1295                 :          0 :             return n;
    1296                 :            :     }
    1297         [ -  + ]:       5736 :     else if( pStrm )
    1298                 :            :     {
    1299                 :          0 :         n = pStrm->Seek( n );
    1300                 :          0 :         SetError( pStrm->GetError() );
    1301                 :          0 :         return n;
    1302                 :            :     }
    1303                 :            :     else
    1304                 :       5736 :         return SvMemoryStream::SeekPos( n );
    1305                 :            : }
    1306                 :            : 
    1307                 :          0 : void StgTmpStrm::FlushData()
    1308                 :            : {
    1309         [ #  # ]:          0 :     if( pStrm )
    1310                 :            :     {
    1311                 :          0 :         pStrm->Flush();
    1312                 :          0 :         SetError( pStrm->GetError() );
    1313                 :            :     }
    1314                 :            :     else
    1315                 :          0 :         SvMemoryStream::FlushData();
    1316                 :          0 : }
    1317                 :            : 
    1318                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10