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