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 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 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 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 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 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 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 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 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 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 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 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 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 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 490 StgFATStrm::StgFATStrm( StgIo& r ) : StgStrm( r ) 491 { 492 pFat = new StgFAT( *this, sal_True ); 493 nSize = rIo.aHdr.GetFATSize() * nPageSize; 494 } 495 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 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 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 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 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 744 StgDataStrm::StgDataStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r ) 745 { 746 Init( nBgn, nLen ); 747 } 748 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 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 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 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 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 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 976 StgSmallStrm::StgSmallStrm( StgIo& r, sal_Int32 nBgn, sal_Int32 nLen ) : StgStrm( r ) 977 { 978 Init( nBgn, nLen ); 979 } 980 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 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 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 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 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 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 1130 StgTmpStrm::~StgTmpStrm() 1131 { 1132 if( pStrm ) 1133 { 1134 pStrm->Close(); 1135 osl::File::remove( aName ); 1136 delete pStrm; 1137 } 1138 } 1139 1140 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 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 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 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 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 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