xref: /aoo42x/main/sot/source/sdstor/stgstrms.cxx (revision 297a844a)
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     if ( n > 0 )
270     {
271         while( n-- )
272         {
273             StgPage* pPg = NULL;
274             // Position within the underlying stream
275             // use the Pos2Page() method of the stream
276             rStrm.Pos2Page( nPage1 << 2 );
277             // Initialize the page
278             pPg = rStrm.GetIo().Copy( rStrm.GetPage(), STG_FREE );
279             if ( !pPg )
280                 return sal_False;
281             for( short i = 0; i < nEntries; i++ )
282                 pPg->SetPage( i, STG_FREE );
283             nPage1++;
284         }
285     }
286     return sal_True;
287 }
288 
289 // Release a chain
290 
291 sal_Bool StgFAT::FreePages( sal_Int32 nStart, sal_Bool bAll )
292 {
293     while( nStart >= 0 )
294     {
295         StgPage* pPg = GetPhysPage( nStart << 2 );
296         if( !pPg )
297             return sal_False;
298         nStart = pPg->GetPage( nOffset >> 2 );
299         // The first released page is either set to EOF or FREE
300         pPg->SetPage( nOffset >> 2, bAll ? STG_FREE : STG_EOF );
301         bAll = sal_True;
302     }
303     return sal_True;
304 }
305 
306 ///////////////////////////// class StgStrm ////////////////////////////////
307 
308 // The base stream class provides basic functionality for seeking
309 // and accessing the data on a physical basis. It uses the built-in
310 // FAT class for the page allocations.
311 
312 StgStrm::StgStrm( StgIo& r ) : rIo( r )
313 {
314     pFat    = NULL;
315     nStart  = nPage = STG_EOF;
316     nOffset = 0;
317     pEntry  = NULL;
318     nPos = nSize = 0;
319     nPageSize = rIo.GetPhysPageSize();
320 }
321 
322 StgStrm::~StgStrm()
323 {
324     delete pFat;
325 }
326 
327 // Attach the stream to the given entry.
328 
329 void StgStrm::SetEntry( StgDirEntry& r )
330 {
331 	r.aEntry.SetLeaf( STG_DATA, nStart );
332 	r.aEntry.SetSize( nSize );
333 	pEntry = &r;
334 	r.SetDirty();
335 }
336 
337 // Compute page number and offset for the given byte position.
338 // If the position is behind the size, set the stream right
339 // behind the EOF.
340 
341 sal_Bool StgStrm::Pos2Page( sal_Int32 nBytePos )
342 {
343     if ( !pFat )
344         return sal_False;
345 
346     sal_Int32 nRel, nBgn;
347     // Values < 0 seek to the end
348     if( nBytePos < 0 || nBytePos >= nSize )
349         nBytePos = nSize;
350     // Adjust the position back to offset 0
351     nPos -= nOffset;
352     sal_Int32 nMask = ~( nPageSize - 1 );
353     sal_Int32 nOld = nPos & nMask;
354     sal_Int32 nNew = nBytePos & nMask;
355     nOffset = (short) ( nBytePos & ~nMask );
356     nPos = nBytePos;
357     if( nOld == nNew )
358         return sal_True;
359     if( nNew > nOld )
360     {
361         // the new position is behind the current, so an incremental
362         // positioning is OK. Set the page relative position
363         nRel = nNew - nOld;
364         nBgn = nPage;
365     }
366     else
367     {
368         // the new position is before the current, so we have to scan
369         // the entire chain.
370         nRel = nNew;
371         nBgn = nStart;
372     }
373     // now, traverse the FAT chain.
374     nRel /= nPageSize;
375     sal_Int32 nLast = STG_EOF;
376     while( nRel && nBgn >= 0 )
377     {
378         nLast = nBgn;
379         nBgn = pFat->GetNextPage( nBgn );
380         nRel--;
381     }
382     // special case: seek to 1st byte of new, unallocated page
383     // (in case the file size is a multiple of the page size)
384     if( nBytePos == nSize && nBgn == STG_EOF && !nRel && !nOffset )
385         nBgn = nLast, nOffset = nPageSize;
386     if( nBgn < 0 && nBgn != STG_EOF )
387     {
388         rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
389         nBgn = STG_EOF;
390         nOffset = nPageSize;
391     }
392     nPage = nBgn;
393     return sal_Bool( nRel == 0 && nPage >= 0 );
394 }
395 
396 // Retrieve the physical page for a given byte offset.
397 
398 StgPage* StgStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
399 {
400     if( !Pos2Page( nBytePos ) )
401         return NULL;
402     return rIo.Get( nPage, bForce );
403 }
404 
405 // Copy an entire stream. Both streams are allocated in the FAT.
406 // The target stream is this stream.
407 
408 sal_Bool StgStrm::Copy( sal_Int32 nFrom, sal_Int32 nBytes )
409 {
410     if ( !pFat )
411         return sal_False;
412 
413     sal_Int32 nTo = nStart;
414     sal_Int32 nPgs = ( nBytes + nPageSize - 1 ) / nPageSize;
415     while( nPgs-- )
416     {
417         if( nTo < 0 )
418         {
419             rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
420             return sal_False;
421         }
422         rIo.Copy( nTo, nFrom );
423         if( nFrom >= 0 )
424         {
425             nFrom = pFat->GetNextPage( nFrom );
426             if( nFrom < 0 )
427             {
428                 rIo.SetError( SVSTREAM_FILEFORMAT_ERROR );
429                 return sal_False;
430             }
431         }
432         nTo = pFat->GetNextPage( nTo );
433     }
434     return sal_True;
435 }
436 
437 sal_Bool StgStrm::SetSize( sal_Int32 nBytes )
438 {
439     if ( nBytes < 0 || !pFat )
440         return sal_False;
441 
442     // round up to page size
443     sal_Int32 nOld = ( ( nSize + nPageSize - 1 ) / nPageSize ) * nPageSize;
444     sal_Int32 nNew = ( ( nBytes + nPageSize - 1 ) / nPageSize ) * nPageSize;
445     if( nNew > nOld )
446     {
447 		if( !Pos2Page( nSize ) )
448             return sal_False;
449         sal_Int32 nBgn = pFat->AllocPages( nPage, ( nNew - nOld ) / nPageSize );
450         if( nBgn == STG_EOF )
451             return sal_False;
452         if( nStart == STG_EOF )
453             nStart = nPage = nBgn;
454     }
455     else if( nNew < nOld )
456     {
457         sal_Bool bAll = sal_Bool( nBytes == 0 );
458         if( !Pos2Page( nBytes ) || !pFat->FreePages( nPage, bAll ) )
459             return sal_False;
460         if( bAll )
461             nStart = nPage = STG_EOF;
462     }
463     if( pEntry )
464     {
465         // change the dir entry?
466         if( !nSize || !nBytes )
467             pEntry->aEntry.SetLeaf( STG_DATA, nStart );
468         pEntry->aEntry.SetSize( nBytes );
469         pEntry->SetDirty();
470     }
471     nSize = nBytes;
472 	pFat->SetLimit( GetPages() );
473 	return sal_True;
474 }
475 
476 // Return the # of allocated pages
477 
478 sal_Int32 StgStrm::GetPages()
479 {
480 	return ( nSize + nPageSize - 1 ) / nPageSize;
481 }
482 
483 //////////////////////////// class StgFATStrm //////////////////////////////
484 
485 // The FAT stream class provides physical access to the master FAT.
486 // Since this access is implemented as a StgStrm, we can use the
487 // FAT allocator.
488 
489 StgFATStrm::StgFATStrm( StgIo& r ) : StgStrm( r )
490 {
491     pFat = new StgFAT( *this, sal_True );
492     nSize = rIo.aHdr.GetFATSize() * nPageSize;
493 }
494 
495 sal_Bool StgFATStrm::Pos2Page( sal_Int32 nBytePos )
496 {
497     // Values < 0 seek to the end
498     if( nBytePos < 0 || nBytePos >= nSize  )
499         nBytePos = nSize ? nSize - 1 : 0;
500     nPage   = nBytePos / nPageSize;
501     nOffset = (short) ( nBytePos % nPageSize );
502     nPos    = nBytePos;
503     nPage   = GetPage( (short) nPage, sal_False );
504     return sal_Bool( nPage >= 0 );
505 }
506 
507 // Retrieve the physical page for a given byte offset.
508 // Since Pos2Page() already has computed the physical offset,
509 // use the byte offset directly.
510 
511 StgPage* StgFATStrm::GetPhysPage( sal_Int32 nBytePos, sal_Bool bForce )
512 {
513     OSL_ENSURE( nBytePos >= 0, "The value may not be negative!" );
514     return rIo.Get( nBytePos / ( nPageSize >> 2 ), bForce );
515 }
516 
517 // Get the page number entry for the given page offset.
518 
519 sal_Int32 StgFATStrm::GetPage( short nOff, sal_Bool bMake, sal_uInt16 *pnMasterAlloc )
520 {
521     OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
522     if( pnMasterAlloc ) *pnMasterAlloc = 0;
523     if( nOff < rIo.aHdr.GetFAT1Size() )
524         return rIo.aHdr.GetFATPage( nOff );
525     sal_Int32 nMaxPage = nSize >> 2;
526     nOff = nOff - rIo.aHdr.GetFAT1Size();
527     // Anzahl der Masterpages, durch die wir iterieren muessen
528     sal_uInt16 nMasterCount =  ( nPageSize >> 2 ) - 1;
529     sal_uInt16 nBlocks = nOff / nMasterCount;
530     // Offset in letzter Masterpage
531     nOff = nOff % nMasterCount;
532 
533     StgPage* pOldPage = 0;
534     StgPage* pMaster = 0;
535     sal_Int32 nFAT = rIo.aHdr.GetFATChain();
536     for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
537     {
538         if( nFAT == STG_EOF || nFAT == STG_FREE )
539         {
540             if( bMake )
541             {
542                 // create a new master page
543                 nFAT = nMaxPage++;
544                 pMaster = rIo.Copy( nFAT, STG_FREE );
545 				if ( pMaster )
546 				{
547 					for( short k = 0; k < ( nPageSize >> 2 ); k++ )
548 						pMaster->SetPage( k, STG_FREE );
549 					// Verkettung herstellen
550 					if( !pOldPage )
551 						rIo.aHdr.SetFATChain( nFAT );
552 					else
553 						pOldPage->SetPage( nMasterCount, nFAT );
554 					if( nMaxPage >= rIo.GetPhysPages() )
555 						if( !rIo.SetSize( nMaxPage ) )
556 							return STG_EOF;
557 					// mark the page as used
558 					// Platz fuer Masterpage schaffen
559 					if( !pnMasterAlloc ) // Selbst Platz schaffen
560 					{
561 						if( !Pos2Page( nFAT << 2 ) )
562 							return STG_EOF;
563 						StgPage* pPg = rIo.Get( nPage, sal_True );
564 						if( !pPg )
565 							return STG_EOF;
566 						pPg->SetPage( nOffset >> 2, STG_MASTER );
567 					}
568 					else
569 						(*pnMasterAlloc)++;
570 					rIo.aHdr.SetMasters( nCount + 1 );
571 					pOldPage = pMaster;
572 				}
573             }
574         }
575         else
576         {
577 			pMaster = rIo.Get( nFAT, sal_True );
578 			if ( pMaster )
579 			{
580 				nFAT = pMaster->GetPage( nMasterCount );
581 				pOldPage = pMaster;
582 			}
583 		}
584 	}
585 	if( pMaster )
586 		return pMaster->GetPage( nOff );
587     rIo.SetError( SVSTREAM_GENERALERROR );
588     return STG_EOF;
589 }
590 
591 
592 // Set the page number entry for the given page offset.
593 
594 sal_Bool StgFATStrm::SetPage( short nOff, sal_Int32 nNewPage )
595 {
596     OSL_ENSURE( nOff >= 0, "The offset may not be negative!" );
597     sal_Bool bRes = sal_True;
598     if( nOff < rIo.aHdr.GetFAT1Size() )
599         rIo.aHdr.SetFATPage( nOff, nNewPage );
600 	else
601 	{
602 	    nOff = nOff - rIo.aHdr.GetFAT1Size();
603 		// Anzahl der Masterpages, durch die wir iterieren muessen
604 		sal_uInt16 nMasterCount =  ( nPageSize >> 2 ) - 1;
605 		sal_uInt16 nBlocks = nOff / nMasterCount;
606 		// Offset in letzter Masterpage
607 		nOff = nOff % nMasterCount;
608 
609 		StgPage* pMaster = 0;
610 		sal_Int32 nFAT = rIo.aHdr.GetFATChain();
611 		for( sal_uInt16 nCount = 0; nCount <= nBlocks; nCount++ )
612 		{
613 			if( nFAT == STG_EOF || nFAT == STG_FREE )
614 			{
615 				pMaster = 0;
616 				break;
617 			}
618 			pMaster = rIo.Get( nFAT, sal_True );
619 			if ( pMaster )
620 				nFAT = pMaster->GetPage( nMasterCount );
621 		}
622 		if( pMaster )
623 			pMaster->SetPage( nOff, nNewPage );
624 		else
625 		{
626 			rIo.SetError( SVSTREAM_GENERALERROR );
627 			bRes = sal_False;
628 		}
629 	}
630 
631 	// lock the page against access
632 	if( bRes )
633 	{
634 		Pos2Page( nNewPage << 2 );
635 		StgPage* pPg = rIo.Get( nPage, sal_True );
636 		if( pPg )
637 			pPg->SetPage( nOffset >> 2, STG_FAT );
638 		else
639 			bRes = sal_False;
640 	}
641 	return bRes;
642 }
643 
644 sal_Bool StgFATStrm::SetSize( sal_Int32 nBytes )
645 {
646     if ( nBytes < 0 )
647         return sal_False;
648 
649     // Set the number of entries to a multiple of the page size
650     short nOld = (short) ( ( nSize + ( nPageSize - 1 ) ) / nPageSize );
651     short nNew = (short) (
652 		( nBytes + ( nPageSize - 1 ) ) / nPageSize ) ;
653     if( nNew < nOld )
654     {
655         // release master pages
656         for( short i = nNew; i < nOld; i++ )
657             SetPage( i, STG_FREE );
658     }
659     else
660     {
661         while( nOld < nNew )
662         {
663             // allocate master pages
664             // find a free master page slot
665             sal_Int32 nPg = 0;
666 			sal_uInt16 nMasterAlloc = 0;
667 			nPg = GetPage( nOld, sal_True, &nMasterAlloc );
668 			if( nPg == STG_EOF )
669 				return sal_False;
670 			// 4 Bytes have been used for Allocation of each MegaMasterPage
671 			nBytes += nMasterAlloc << 2;
672 
673             // find a free page using the FAT allocator
674             sal_Int32 n = 1;
675             OSL_ENSURE( pFat, "The pointer is always initializer here!" );
676             sal_Int32 nNewPage = pFat->FindBlock( n );
677             if( nNewPage == STG_EOF )
678 			{
679                 // no free pages found; create a new page
680 				// Since all pages are allocated, extend
681 				// the file size for the next page!
682 				nNewPage = nSize >> 2;
683 				// if a MegaMasterPage was created avoid taking
684 				// the same Page
685 				nNewPage += nMasterAlloc;
686 			    // adjust the file size if necessary
687 			    if( nNewPage >= rIo.GetPhysPages() )
688 			        if( !rIo.SetSize( nNewPage + 1 ) )
689 			            return sal_False;
690 			}
691 			// Set up the page with empty entries
692 	        StgPage* pPg = rIo.Copy( nNewPage, STG_FREE );
693 			if ( !pPg )
694 				return sal_False;
695 	        for( short j = 0; j < ( nPageSize >> 2 ); j++ )
696 	            pPg->SetPage( j, STG_FREE );
697 
698 			// store the page number into the master FAT
699 			// Set the size before so the correct FAT can be found
700 			nSize = ( nOld + 1 ) * nPageSize;
701             SetPage( nOld, nNewPage );
702 
703 			// MegaMasterPages were created, mark it them as used
704 
705 			sal_uInt32 nMax = rIo.aHdr.GetMasters( );
706 			sal_uInt32 nFAT = rIo.aHdr.GetFATChain();
707 			if( nMasterAlloc )
708 				for( sal_uInt16 nCount = 0; nCount < nMax; nCount++ )
709 				{
710 					if( !Pos2Page( nFAT << 2 ) )
711 						return sal_False;
712 					if( nMax - nCount <= nMasterAlloc )
713 					{
714 						StgPage* piPg = rIo.Get( nPage, sal_True );
715 						if( !piPg )
716 							return sal_False;
717 						piPg->SetPage( nOffset >> 2, STG_MASTER );
718 					}
719 					StgPage* pPage = rIo.Get( nFAT, sal_True );
720 					if( !pPage ) return sal_False;
721 					nFAT = pPage->GetPage( (nPageSize >> 2 ) - 1 );
722 				}
723 
724 			nOld++;
725 			// We have used up 4 bytes for the STG_FAT entry
726 			nBytes += 4;
727 			nNew = (short) (
728 				( nBytes + ( nPageSize - 1 ) ) / nPageSize );
729         }
730     }
731 	nSize = nNew * nPageSize;
732 	rIo.aHdr.SetFATSize( nNew );
733     return sal_True;
734 }
735 
736 /////////////////////////// class StgDataStrm //////////////////////////////
737 
738 // This class is a normal physical stream which can be initialized
739 // either with an existing dir entry or an existing FAT chain.
740 // The stream has a size increment which normally is 1, but which can be
741 // set to any value is you want the size to be incremented by certain values.
742 
743 StgDataStrm::StgDataStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
744 {
745     Init( nBgn, nLen );
746 }
747 
748 StgDataStrm::StgDataStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
749 {
750     pEntry = &p;
751     Init( p.aEntry.GetLeaf( STG_DATA ),
752           p.aEntry.GetSize() );
753 }
754 
755 void StgDataStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
756 {
757     if ( rIo.pFAT )
758         pFat = new StgFAT( *rIo.pFAT, sal_True );
759 
760     OSL_ENSURE( pFat, "The pointer should not be empty!" );
761 
762     nStart = nPage = nBgn;
763     nSize  = nLen;
764     nIncr  = 1;
765     nOffset = 0;
766     if( nLen < 0 && pFat )
767     {
768         // determine the actual size of the stream by scanning
769         // the FAT chain and counting the # of pages allocated
770         nSize = 0;
771 		sal_Int32 nOldBgn = -1;
772         while( nBgn >= 0 && nBgn != nOldBgn )
773         {
774 			nOldBgn = nBgn;
775             nBgn = pFat->GetNextPage( nBgn );
776 			if( nBgn == nOldBgn )
777 				rIo.SetError( ERRCODE_IO_WRONGFORMAT );
778             nSize += nPageSize;
779         }
780     }
781 }
782 
783 // Set the size of a physical stream.
784 
785 sal_Bool StgDataStrm::SetSize( sal_Int32 nBytes )
786 {
787     if ( !pFat )
788         return sal_False;
789 
790     nBytes = ( ( nBytes + nIncr - 1 ) / nIncr ) * nIncr;
791     sal_Int32 nOldSz = nSize;
792     if( ( nOldSz != nBytes ) )
793     {
794 		if( !StgStrm::SetSize( nBytes ) )
795 			return sal_False;
796         sal_Int32 nMaxPage = pFat->GetMaxPage();
797         if( nMaxPage > rIo.GetPhysPages() )
798             if( !rIo.SetSize( nMaxPage ) )
799                 return sal_False;
800         // If we only allocated one page or less, create this
801         // page in the cache for faster throughput. The current
802         // position is the former EOF point.
803         if( ( nSize - 1 )  / nPageSize - ( nOldSz - 1 ) / nPageSize == 1 )
804         {
805             Pos2Page( nBytes );
806 			if( nPage >= 0 )
807 	            rIo.Copy( nPage, STG_FREE );
808         }
809     }
810     return sal_True;
811 }
812 
813 // Get the address of the data byte at a specified offset.
814 // If bForce = sal_True, a read of non-existent data causes
815 // a read fault.
816 
817 void* StgDataStrm::GetPtr( sal_Int32 Pos, sal_Bool bForce, sal_Bool bDirty )
818 {
819     if( Pos2Page( Pos ) )
820     {
821         StgPage* pPg = rIo.Get( nPage, bForce );
822         if( pPg )
823         {
824             pPg->SetOwner( pEntry );
825             if( bDirty )
826                 pPg->SetDirty();
827             return ((sal_uInt8 *)pPg->GetData()) + nOffset;
828         }
829     }
830     return NULL;
831 }
832 
833 // This could easily be adapted to a better algorithm by determining
834 // the amount of consecutable blocks before doing a read. The result
835 // is the number of bytes read. No error is generated on EOF.
836 
837 sal_Int32 StgDataStrm::Read( void* pBuf, sal_Int32 n )
838 {
839     if ( n < 0 )
840         return 0;
841 
842     if( ( nPos + n ) > nSize )
843         n = nSize - nPos;
844     sal_Int32 nDone = 0;
845     while( n )
846     {
847         short nBytes = nPageSize - nOffset;
848         short nRes;
849         StgPage* pPg;
850         if( (sal_Int32) nBytes > n )
851             nBytes = (short) n;
852         if( nBytes )
853         {
854             void *p = (sal_uInt8 *) pBuf + nDone;
855             if( nBytes == nPageSize )
856             {
857                 pPg = rIo.Find( nPage );
858                 if( pPg )
859                 {
860                     // data is present, so use the cached data
861                     pPg->SetOwner( pEntry );
862                     memcpy( p, pPg->GetData(), nBytes );
863                     nRes = nBytes;
864                 }
865                 else
866                     // do a direct (unbuffered) read
867                     nRes = (short) rIo.Read( nPage, p, 1 ) * nPageSize;
868             }
869             else
870             {
871                 // partial block read thru the cache.
872                 pPg = rIo.Get( nPage, sal_False );
873                 if( !pPg )
874                     break;
875                 pPg->SetOwner( pEntry );
876                 memcpy( p, (sal_uInt8*)pPg->GetData() + nOffset, nBytes );
877                 nRes = nBytes;
878             }
879             nDone += nRes;
880             nPos += nRes;
881             n -= nRes;
882             nOffset = nOffset + nRes;
883             if( nRes != nBytes )
884                 break;  // read error or EOF
885         }
886         // Switch to next page if necessary
887         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
888             break;
889     }
890     return nDone;
891 }
892 
893 sal_Int32 StgDataStrm::Write( const void* pBuf, sal_Int32 n )
894 {
895     if ( n < 0 )
896         return 0;
897 
898     sal_Int32 nDone = 0;
899     if( ( nPos + n ) > nSize )
900 	{
901 		sal_Int32 nOld = nPos;
902 		if( !SetSize( nPos + n ) )
903             return 0;
904 		Pos2Page( nOld );
905 	}
906     while( n )
907     {
908         short nBytes = nPageSize - nOffset;
909         short nRes;
910         StgPage* pPg;
911         if( (sal_Int32) nBytes > n )
912             nBytes = (short) n;
913         if( nBytes )
914         {
915 			const void *p = (const sal_uInt8 *) pBuf + nDone;
916             if( nBytes == nPageSize )
917             {
918                 pPg = rIo.Find( nPage );
919                 if( pPg )
920                 {
921                     // data is present, so use the cached data
922                     pPg->SetOwner( pEntry );
923 					memcpy( pPg->GetData(), p, nBytes );
924 					pPg->SetDirty();
925                     nRes = nBytes;
926                 }
927                 else
928                     // do a direct (unbuffered) write
929                     nRes = (short) rIo.Write( nPage, (void*) p, 1 ) * nPageSize;
930             }
931             else
932             {
933                 // partial block read thru the cache.
934                 pPg = rIo.Get( nPage, sal_False );
935                 if( !pPg )
936                     break;
937                 pPg->SetOwner( pEntry );
938 				memcpy( (sal_uInt8*)pPg->GetData() + nOffset, p, nBytes );
939                 pPg->SetDirty();
940                 nRes = nBytes;
941             }
942             nDone += nRes;
943             nPos += nRes;
944             n -= nRes;
945             nOffset = nOffset + nRes;
946             if( nRes != nBytes )
947                 break;  // read error
948         }
949         // Switch to next page if necessary
950         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
951             break;
952     }
953     return nDone;
954 }
955 
956 //////////////////////////// class StgSmallStream ///////////////////////////
957 
958 // The small stream class provides access to streams with a size < 4096 bytes.
959 // This stream is a StgStream containing small pages. The FAT for this stream
960 // is also a StgStream. The start of the FAT is in the header at DataRootPage,
961 // the stream itself is pointed to by the root entry (it holds start & size).
962 
963 StgSmallStrm::StgSmallStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r )
964 {
965 	Init( nBgn, nLen );
966 }
967 
968 StgSmallStrm::StgSmallStrm( StgIo& r, StgDirEntry& p ) : StgStrm( r )
969 {
970     pEntry = &p;
971     Init( p.aEntry.GetLeaf( STG_DATA ),
972           p.aEntry.GetSize() );
973 }
974 
975 void StgSmallStrm::Init( sal_Int32 nBgn, sal_Int32 nLen )
976 {
977     if ( rIo.pDataFAT )
978         pFat = new StgFAT( *rIo.pDataFAT, sal_False );
979     pData = rIo.pDataStrm;
980     OSL_ENSURE( pFat && pData, "The pointers should not be empty!" );
981 
982     nPageSize = rIo.GetDataPageSize();
983     nStart =
984     nPage  = nBgn;
985     nSize  = nLen;
986 }
987 
988 // This could easily be adapted to a better algorithm by determining
989 // the amount of consecutable blocks before doing a read. The result
990 // is the number of bytes read. No error is generated on EOF.
991 
992 sal_Int32 StgSmallStrm::Read( void* pBuf, sal_Int32 n )
993 {
994     // We can safely assume that reads are not huge, since the
995     // small stream is likely to be < 64 KBytes.
996     if( ( nPos + n ) > nSize )
997         n = nSize - nPos;
998     short nDone = 0;
999     while( n )
1000     {
1001         short nBytes = nPageSize - nOffset;
1002         if( (sal_Int32) nBytes > n )
1003             nBytes = (short) n;
1004         if( nBytes )
1005         {
1006             if( !pData || !pData->Pos2Page( nPage * nPageSize + nOffset ) )
1007                 break;
1008             // all reading thru the stream
1009             short nRes = (short) pData->Read( (sal_uInt8*)pBuf + nDone, nBytes );
1010             nDone = nDone + nRes;
1011             nPos += nRes;
1012             n -= nRes;
1013             nOffset = nOffset + nRes;
1014             // read problem?
1015             if( nRes != nBytes )
1016                 break;
1017         }
1018         // Switch to next page if necessary
1019         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
1020             break;
1021     }
1022     return nDone;
1023 }
1024 
1025 sal_Int32 StgSmallStrm::Write( const void* pBuf, sal_Int32 n )
1026 {
1027     // you can safely assume that reads are not huge, since the
1028     // small stream is likely to be < 64 KBytes.
1029     short nDone = 0;
1030     if( ( nPos + n ) > nSize )
1031     {
1032         sal_Int32 nOld = nPos;
1033         if( !SetSize( nPos + n ) )
1034             return sal_False;
1035         Pos2Page( nOld );
1036     }
1037     while( n )
1038     {
1039         short nBytes = nPageSize - nOffset;
1040         if( (sal_Int32) nBytes > n )
1041             nBytes = (short) n;
1042         if( nBytes )
1043         {
1044             // all writing goes thru the stream
1045             sal_Int32 nDataPos = nPage * nPageSize + nOffset;
1046             if ( !pData
1047               || ( pData->GetSize() < ( nDataPos + nBytes )
1048                 && !pData->SetSize( nDataPos + nBytes ) ) )
1049                 break;
1050             if( !pData->Pos2Page( nDataPos ) )
1051                 break;
1052             short nRes = (short) pData->Write( (sal_uInt8*)pBuf + nDone, nBytes );
1053             nDone = nDone + nRes;
1054             nPos += nRes;
1055             n -= nRes;
1056             nOffset = nOffset + nRes;
1057             // write problem?
1058             if( nRes != nBytes )
1059                 break;
1060         }
1061         // Switch to next page if necessary
1062         if( nOffset >= nPageSize && !Pos2Page( nPos ) )
1063             break;
1064     }
1065     return nDone;
1066 }
1067 
1068 /////////////////////////// class StgTmpStrm /////////////////////////////
1069 
1070 // The temporary stream uses a memory stream if < 32K, otherwise a
1071 // temporary file.
1072 
1073 #define THRESHOLD 32768L
1074 
1075 StgTmpStrm::StgTmpStrm( sal_uLong nInitSize )
1076 		  : SvMemoryStream( nInitSize > THRESHOLD
1077 		  					? 16
1078 							: ( nInitSize ? nInitSize : 16 ), 4096 )
1079 {
1080 	pStrm = NULL;
1081 	// this calls FlushData, so all members should be set by this time
1082 	SetBufferSize( 0 );
1083 	if( nInitSize > THRESHOLD )
1084 		SetSize( nInitSize );
1085 }
1086 
1087 sal_Bool StgTmpStrm::Copy( StgTmpStrm& rSrc )
1088 {
1089 	sal_uLong n    = rSrc.GetSize();
1090 	sal_uLong nCur = rSrc.Tell();
1091 	SetSize( n );
1092 	if( GetError() == SVSTREAM_OK )
1093 	{
1094 		sal_uInt8* p = new sal_uInt8[ 4096 ];
1095 		rSrc.Seek( 0L );
1096 		Seek( 0L );
1097 		while( n )
1098 		{
1099 			sal_uLong nn = n;
1100 			if( nn > 4096 )
1101 				nn = 4096;
1102 			if( rSrc.Read( p, nn ) != nn )
1103 				break;
1104 			if( Write( p, nn ) != nn )
1105 				break;
1106 			n -= nn;
1107 		}
1108         delete [] p;
1109 		rSrc.Seek( nCur );
1110 		Seek( nCur );
1111 		return sal_Bool( n == 0 );
1112 	}
1113 	else
1114 		return sal_False;
1115 }
1116 
1117 StgTmpStrm::~StgTmpStrm()
1118 {
1119 	if( pStrm )
1120 	{
1121 		pStrm->Close();
1122 		osl::File::remove( aName );
1123 		delete pStrm;
1124 	}
1125 }
1126 
1127 sal_uLong StgTmpStrm::GetSize() const
1128 {
1129 	sal_uLong n;
1130 	if( pStrm )
1131 	{
1132 		sal_uLong old = pStrm->Tell();
1133 		n = pStrm->Seek( STREAM_SEEK_TO_END );
1134 		pStrm->Seek( old );
1135 	}
1136 	else
1137 		n = nEndOfData;
1138 	return n;
1139 }
1140 
1141 void StgTmpStrm::SetSize( sal_uLong n )
1142 {
1143 	if( pStrm )
1144 		pStrm->SetStreamSize( n );
1145 	else
1146 	{
1147 		if( n > THRESHOLD )
1148 		{
1149 			aName = TempFile::CreateTempName();
1150 			SvFileStream* s = new SvFileStream( aName, STREAM_READWRITE );
1151 			sal_uLong nCur = Tell();
1152 			sal_uLong i = nEndOfData;
1153 			if( i )
1154 			{
1155 				sal_uInt8* p = new sal_uInt8[ 4096 ];
1156 				Seek( 0L );
1157 				while( i )
1158 				{
1159 					sal_uLong nb = ( i > 4096 ) ? 4096 : i;
1160 					if( Read( p, nb ) == nb
1161 					 && s->Write( p, nb ) == nb )
1162 						i -= nb;
1163 					else
1164 						break;
1165 				}
1166 				delete [] p;
1167 			}
1168 			if( !i && n > nEndOfData )
1169 			{
1170 				// We have to write one byte at the end of the file
1171 				// if the file is bigger than the memstream to see
1172 				// if it fits on disk
1173 				s->Seek( n - 1 );
1174 				s->Write( &i, 1 );
1175 				s->Flush();
1176 				if( s->GetError() != SVSTREAM_OK )
1177 					i = 1;
1178 			}
1179 			Seek( nCur );
1180 			s->Seek( nCur );
1181 			if( i )
1182 			{
1183 				SetError( s->GetError() );
1184 				delete s;
1185 				return;
1186 			}
1187 			pStrm = s;
1188 			// Shrink the memory to 16 bytes, which seems to be the minimum
1189 			ReAllocateMemory( - ( (long) nEndOfData - 16 ) );
1190 		}
1191 		else
1192 		{
1193 			if( n > nEndOfData )
1194 			{
1195 				sal_uLong nCur = Tell();
1196 				Seek( nEndOfData - 1 );
1197 				*this << (sal_uInt8) 0;
1198 				Seek( nCur );
1199 			}
1200 			else
1201 				nEndOfData = n;
1202 		}
1203 	}
1204 }
1205 
1206 sal_uLong StgTmpStrm::GetData( void* pData, sal_uLong n )
1207 {
1208 	if( pStrm )
1209 	{
1210 		n = pStrm->Read( pData, n );
1211 		SetError( pStrm->GetError() );
1212 		return n;
1213 	}
1214 	else
1215 		return SvMemoryStream::GetData( (sal_Char *)pData, n );
1216 }
1217 
1218 sal_uLong StgTmpStrm::PutData( const void* pData, sal_uLong n )
1219 {
1220 	sal_uInt32 nCur = Tell();
1221 	sal_uInt32 nNew = nCur + n;
1222 	if( nNew > THRESHOLD && !pStrm )
1223 	{
1224 		SetSize( nNew );
1225 		if( GetError() != SVSTREAM_OK )
1226 			return 0;
1227 	}
1228 	if( pStrm )
1229 	{
1230 		nNew = pStrm->Write( pData, n );
1231 		SetError( pStrm->GetError() );
1232 	}
1233 	else
1234 		nNew = SvMemoryStream::PutData( (sal_Char*)pData, n );
1235 	return nNew;
1236 }
1237 
1238 sal_uLong StgTmpStrm::SeekPos( sal_uLong n )
1239 {
1240 	if( n == STREAM_SEEK_TO_END )
1241 		n = GetSize();
1242 	if( n && n > THRESHOLD && !pStrm )
1243 	{
1244 		SetSize( n );
1245 		if( GetError() != SVSTREAM_OK )
1246 			return Tell();
1247 		else
1248 			return n;
1249 	}
1250 	else if( pStrm )
1251 	{
1252 		n = pStrm->Seek( n );
1253 		SetError( pStrm->GetError() );
1254 		return n;
1255 	}
1256 	else
1257 		return SvMemoryStream::SeekPos( n );
1258 }
1259 
1260 void StgTmpStrm::FlushData()
1261 {
1262 	if( pStrm )
1263 	{
1264 		pStrm->Flush();
1265 		SetError( pStrm->GetError() );
1266 	}
1267 	else
1268 		SvMemoryStream::FlushData();
1269 }
1270 
1271