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