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