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