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