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