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_svl.hxx" 30 31 #include <string.h> 32 #include <stdio.h> 33 34 #ifndef GCC 35 #endif 36 37 #include <tools/solar.h> 38 #include <svl/itempool.hxx> 39 #include "whassert.hxx" 40 #include <svl/brdcst.hxx> 41 #include <svl/filerec.hxx> 42 #include <svl/svldata.hxx> 43 #include "poolio.hxx" 44 45 // STATIC DATA ----------------------------------------------------------- 46 47 DBG_NAME(SfxItemPool); 48 49 //======================================================================== 50 51 void SfxItemPool::SetStoringPool( const SfxItemPool *pStoringPool ) 52 53 /* [Beschreibung] 54 55 Diese Methode setzt den <SfxItemPool>, der gerade gespeichert wird. 56 Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format- 57 Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines 58 <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen 59 Pool mit <SfxItemPool::GetStoringPool()> zu besorgen. 60 61 Sie wird von <SfxItemPool::Store()> bedient, kann jedoch f"ur nicht 62 poolable Items auch direkt gerufen werden. Bitte m"oglichst nicht 63 f"ur jedes Item einzeln, da 2 Calls! 64 */ 65 66 { 67 ImpSvlData::GetSvlData().pStoringPool = pStoringPool; 68 } 69 70 //------------------------------------------------------------------------- 71 72 const SfxItemPool* SfxItemPool::GetStoringPool() 73 74 /* [Beschreibung] 75 76 Diese Methode liefert den <SfxItemPool>, der gerade gespeichert wird. 77 Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format- 78 Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines 79 <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen 80 Pool zu besorgen. 81 */ 82 83 { 84 return ImpSvlData::GetSvlData().pStoringPool; 85 } 86 87 //------------------------------------------------------------------------- 88 89 SvStream &SfxItemPool::Store(SvStream &rStream) const 90 91 /* [Beschreibung] 92 93 Der SfxItemPool wird inklusive aller seiner Sekund"arpools mit 94 Pool-Defaults und gepoolten Items in dem angegebenen Stream gespeichert. 95 Die statischen Defaults werden nicht gespeichert. 96 97 98 [Fileformat] 99 100 ;zun"achst ein Kompatiblit"ats-Header-Block 101 Start: 0x1111 SFX_ITEMPOOL_TAG_STARTPOOLS(_4/_5) 102 sal_uInt8 MAJOR_VER ;SfxItemPool-Version 103 sal_uInt8 MINOR_VER ;" 104 0xFFFF SFX_ITEMPOOL_TAG_TRICK4OLD ;ex. GetVersion() 105 sal_uInt16 0x0000 ;Pseudo-StyleSheetPool 106 sal_uInt16 0x0000 ;Pseudo-StyleSheetPool 107 108 ;den ganzen Pool in einen Record 109 record SfxMiniRecod(SFX_ITEMPOOL_REC) 110 111 ;je ein Header vorweg 112 Header: record SfxMiniRecord(SFX_ITEMPOOL_REC_HEADER) 113 sal_uInt16 GetVersion() ;Which-Ranges etc. 114 String GetName() ;Pool-Name 115 116 ;die Versions-Map, um WhichIds neuer File-Versionen mappen zu k"onnen 117 Versions: record SfxMultiRecord(SFX_ITEMPOOL_REC_VERSIONS, 0) 118 sal_uInt16 OldVersion 119 sal_uInt16 OldStartWhich 120 sal_uInt16 OldEndWhich 121 sal_uInt16[] NewWhich (OldEndWhich-OldStartWhich+1) 122 123 ;jetzt die gepoolten Items (zuerst nicht-SfxSetItems) 124 Items: record SfxMultiRecord(SFX_ITEMPOOL_REC_WHICHIDS, 0) 125 content SlotId, 0 126 sal_uInt16 WhichId 127 sal_uInt16 pItem->GetVersion() 128 sal_uInt16 Array-Size 129 record SfxMultiRecord(SFX_, 0) 130 content Surrogate 131 sal_uInt16 RefCount 132 unknown pItem->Store() 133 134 ;jetzt die gesetzten Pool-Defaults 135 Defaults: record SfxMultiRecord(SFX_ITEMPOOL_REC_DEFAULTS, 0) 136 content SlotId, 0 137 sal_uInt16 WhichId 138 sal_uInt16 pPoolDef->GetVersion() 139 unknown pPoolDef->Store(); 140 141 ;dahinter folgt ggf. der Secondary ohne Kompatiblit"ats-Header-Block 142 */ 143 144 { 145 DBG_CHKTHIS(SfxItemPool, 0); 146 147 // Store-Master finden 148 SfxItemPool *pStoreMaster = pMaster != this ? pMaster : 0; 149 while ( pStoreMaster && !pStoreMaster->pImp->bStreaming ) 150 pStoreMaster = pStoreMaster->pSecondary; 151 152 // Alter-Header (Version des Pools an sich und Inhalts-Version 0xffff) 153 pImp->bStreaming = sal_True; 154 if ( !pStoreMaster ) 155 { 156 rStream << ( rStream.GetVersion() >= SOFFICE_FILEFORMAT_50 157 ? SFX_ITEMPOOL_TAG_STARTPOOL_5 158 : SFX_ITEMPOOL_TAG_STARTPOOL_4 ); 159 rStream << SFX_ITEMPOOL_VER_MAJOR << SFX_ITEMPOOL_VER_MINOR; 160 rStream << SFX_ITEMPOOL_TAG_TRICK4OLD; 161 162 // SfxStyleSheet-Bug umgehen 163 rStream << sal_uInt16(0); // Version 164 rStream << sal_uInt16(0); // Count (2. Schleife f"allt sonst auf die Fresse) 165 } 166 167 // jeder Pool ist als ganzes ein Record 168 SfxMiniRecordWriter aPoolRec( &rStream, SFX_ITEMPOOL_REC ); 169 ImpSvlData::GetSvlData().pStoringPool = this; 170 171 // Einzel-Header (Version des Inhalts und Name) 172 { 173 SfxMiniRecordWriter aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER); 174 rStream << pImp->nVersion; 175 SfxPoolItem::writeByteString(rStream, aName); 176 } 177 178 // Version-Maps 179 { 180 SfxMultiVarRecordWriter aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP, 0 ); 181 for ( size_t nVerNo = 0; nVerNo < pImp->aVersions.size(); ++nVerNo ) 182 { 183 aVerRec.NewContent(); 184 SfxPoolVersion_ImplPtr pVer = pImp->aVersions[nVerNo]; 185 rStream << pVer->_nVer << pVer->_nStart << pVer->_nEnd; 186 sal_uInt16 nCount = pVer->_nEnd - pVer->_nStart + 1; 187 sal_uInt16 nNewWhich = 0; 188 for ( sal_uInt16 n = 0; n < nCount; ++n ) 189 { 190 nNewWhich = pVer->_pMap[n]; 191 rStream << nNewWhich; 192 } 193 194 // Workaround gegen Bug in SetVersionMap der 312 195 if ( SOFFICE_FILEFORMAT_31 == _nFileFormatVersion ) 196 rStream << sal_uInt16(nNewWhich+1); 197 } 198 } 199 200 // gepoolte Items 201 { 202 SfxMultiMixRecordWriter aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS, 0 ); 203 204 // erst Atomaren-Items und dann die Sets schreiben (wichtig beim Laden) 205 for ( pImp->bInSetItem = sal_False; pImp->bInSetItem <= sal_True && !rStream.GetError(); ++pImp->bInSetItem ) 206 { 207 SfxPoolItemArray_Impl **pArr = pImp->ppPoolItems; 208 SfxPoolItem **ppDefItem = ppStaticDefaults; 209 const sal_uInt16 nSize = GetSize_Impl(); 210 for ( size_t i = 0; i < nSize && !rStream.GetError(); ++i, ++pArr, ++ppDefItem ) 211 { 212 // Version des Items feststellen 213 sal_uInt16 nItemVersion = (*ppDefItem)->GetVersion( _nFileFormatVersion ); 214 if ( USHRT_MAX == nItemVersion ) 215 // => kam in zu exportierender Version gar nicht vor 216 continue; 217 218 // !poolable wird gar nicht im Pool gespeichert 219 // und itemsets/plain-items je nach Runde 220 #ifdef TF_POOLABLE 221 if ( *pArr && IsItemFlag(**ppDefItem, SFX_ITEM_POOLABLE) && 222 #else 223 if ( *pArr && (*ppDefItem)->IsPoolable() && 224 #endif 225 pImp->bInSetItem == (*ppDefItem)->ISA(SfxSetItem) ) 226 { 227 // eigene Kennung, globale Which-Id und Item-Version 228 sal_uInt16 nSlotId = GetSlotId( (*ppDefItem)->Which(), sal_False ); 229 aWhichIdsRec.NewContent(nSlotId, 0); 230 rStream << (*ppDefItem)->Which(); 231 rStream << nItemVersion; 232 const sal_uInt32 nCount = ::std::min<size_t>( (*pArr)->size(), SAL_MAX_UINT32 ); 233 DBG_ASSERT(nCount, "ItemArr is empty"); 234 rStream << nCount; 235 236 // Items an sich schreiben 237 SfxMultiMixRecordWriter aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS, 0 ); 238 for ( size_t j = 0; j < nCount; ++j ) 239 { 240 // Item selbst besorgen 241 const SfxPoolItem *pItem = (*pArr)->operator[](j); 242 if ( pItem && pItem->GetRefCount() ) //! siehe anderes MI-REF 243 { 244 aItemsRec.NewContent((sal_uInt16)j, 'X' ); 245 246 if ( pItem->GetRefCount() == SFX_ITEMS_SPECIAL ) 247 rStream << (sal_uInt16) pItem->GetKind(); 248 else 249 { 250 rStream << (sal_uInt16) pItem->GetRefCount(); 251 if( pItem->GetRefCount() > SFX_ITEMS_OLD_MAXREF ) 252 rStream.SetError( ERRCODE_IO_NOTSTORABLEINBINARYFORMAT ); 253 } 254 255 if ( !rStream.GetError() ) 256 pItem->Store(rStream, nItemVersion); 257 else 258 break; 259 #ifdef DBG_UTIL_MI 260 if ( !pItem->ISA(SfxSetItem) ) 261 { 262 sal_uLong nMark = rStream.Tell(); 263 rStream.Seek( nItemStartPos + sizeof(sal_uInt16) ); 264 SfxPoolItem *pClone = pItem->Create(rStream, nItemVersion ); 265 sal_uInt16 nWh = pItem->Which(); 266 SFX_ASSERT( rStream.Tell() == nMark, nWh,"asymmetric store/create" ); 267 SFX_ASSERT( *pClone == *pItem, nWh, "unequal after store/create" ); 268 delete pClone; 269 } 270 #endif 271 } 272 } 273 } 274 } 275 } 276 277 pImp->bInSetItem = sal_False; 278 } 279 280 // die gesetzten Defaults speichern (Pool-Defaults) 281 if ( !rStream.GetError() ) 282 { 283 SfxMultiMixRecordWriter aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS, 0 ); 284 sal_uInt16 nCount = GetSize_Impl(); 285 for ( sal_uInt16 n = 0; n < nCount; ++n ) 286 { 287 const SfxPoolItem* pDefaultItem = ppPoolDefaults[n]; 288 if ( pDefaultItem ) 289 { 290 // Version ermitteln 291 sal_uInt16 nItemVersion = pDefaultItem->GetVersion( _nFileFormatVersion ); 292 if ( USHRT_MAX == nItemVersion ) 293 // => gab es in der Version noch nicht 294 continue; 295 296 // eigene Kennung, globale Kennung, Version 297 sal_uInt16 nSlotId = GetSlotId( pDefaultItem->Which(), sal_False ); 298 aDefsRec.NewContent( nSlotId, 0 ); 299 rStream << pDefaultItem->Which(); 300 rStream << nItemVersion; 301 302 // Item an sich 303 pDefaultItem->Store( rStream, nItemVersion ); 304 } 305 } 306 } 307 308 // weitere Pools rausschreiben 309 ImpSvlData::GetSvlData().pStoringPool = 0; 310 aPoolRec.Close(); 311 if ( !rStream.GetError() && pSecondary ) 312 pSecondary->Store( rStream ); 313 314 pImp->bStreaming = sal_False; 315 return rStream; 316 } 317 318 // ----------------------------------------------------------------------- 319 320 void SfxItemPool::LoadCompleted() 321 322 /* [Beschreibung] 323 324 Wurde der SfxItemPool mit 'bRefCounts' == sal_False geladen, mu\s das 325 Laden der Dokumentinhalte mit einem Aufruf dieser Methode beendet 326 werden. Ansonsten hat der Aufruf dieser Methode keine Funktion. 327 328 329 [Anmerkung] 330 331 Beim Laden ohne Ref-Counts werden diese tats"achlich auf 1 gesetzt, 332 damit nicht w"ahrend des Ladevorgangs SfxPoolItems gel"oscht werden, 333 die danach, aber auch noch beim Ladevorgang, ben"otigt werden. Diese 334 Methode setzt den Ref-Count wieder zur"uck und entfernt dabei 335 gleichzeitig alle nicht mehr ben"otigten Items. 336 337 338 [Querverweise] 339 340 <SfxItemPool::Load()> 341 */ 342 343 { 344 // wurden keine Ref-Counts mitgeladen? 345 if ( pImp->nInitRefCount > 1 ) 346 { 347 348 // "uber alle Which-Werte iterieren 349 SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems; 350 for( sal_uInt16 nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr ) 351 { 352 // ist "uberhaupt ein Item mit dem Which-Wert da? 353 if ( *ppItemArr ) 354 { 355 // "uber alle Items mit dieser Which-Id iterieren 356 SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin(); 357 for( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr ) 358 if (*ppHtArr) 359 { 360 #ifdef DBG_UTIL 361 const SfxPoolItem &rItem = **ppHtArr; 362 DBG_ASSERT( !rItem.ISA(SfxSetItem) || 363 0 != &((const SfxSetItem&)rItem).GetItemSet(), 364 "SetItem without ItemSet" ); 365 #endif 366 367 if ( !ReleaseRef( **ppHtArr, 1 ) ) 368 DELETEZ( *ppHtArr ); 369 } 370 } 371 } 372 373 // from now on normal initial ref count 374 pImp->nInitRefCount = 1; 375 } 376 377 // notify secondary pool 378 if ( pSecondary ) 379 pSecondary->LoadCompleted(); 380 } 381 382 //============================================================================ 383 // This had to be moved to a method of its own to keep Solaris GCC happy: 384 void SfxItemPool::readTheItems ( 385 SvStream & rStream, sal_uInt32 nItemCount, sal_uInt16 nVersion, 386 SfxPoolItem * pDefItem, SfxPoolItemArray_Impl ** ppArr) 387 { 388 SfxMultiRecordReader aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS ); 389 390 SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl(); 391 SfxPoolItem *pItem = 0; 392 393 sal_uLong n, nLastSurrogate = sal_uLong(-1); 394 while (aItemsRec.GetContent()) 395 { 396 // n"achstes Surrogat holen 397 sal_uInt16 nSurrogate = aItemsRec.GetContentTag(); 398 DBG_ASSERT( aItemsRec.GetContentVersion() == 'X', 399 "not an item content" ); 400 401 // fehlende auff"ullen 402 for ( pItem = 0, n = nLastSurrogate+1; n < nSurrogate; ++n ) 403 pNewArr->push_back( (SfxPoolItem*) pItem ); 404 nLastSurrogate = nSurrogate; 405 406 // Ref-Count und Item laden 407 sal_uInt16 nRef; 408 rStream >> nRef; 409 410 pItem = pDefItem->Create(rStream, nVersion); 411 pNewArr->push_back( (SfxPoolItem*) pItem ); 412 413 if ( !bPersistentRefCounts ) 414 // bis <SfxItemPool::LoadCompleted()> festhalten 415 AddRef(*pItem, 1); 416 else 417 { 418 if ( nRef > SFX_ITEMS_OLD_MAXREF ) 419 pItem->SetKind( nRef ); 420 else 421 AddRef(*pItem, nRef); 422 } 423 } 424 425 // fehlende auff"ullen 426 for ( pItem = 0, n = nLastSurrogate+1; n < nItemCount; ++n ) 427 pNewArr->push_back( (SfxPoolItem*) pItem ); 428 429 SfxPoolItemArray_Impl *pOldArr = *ppArr; 430 *ppArr = pNewArr; 431 432 // die Items merken, die schon im Pool sind 433 bool bEmpty = true; 434 if ( 0 != pOldArr ) 435 for ( n = 0; bEmpty && n < pOldArr->size(); ++n ) 436 bEmpty = pOldArr->operator[](n) == 0; 437 DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" ); 438 if ( !bEmpty ) 439 { 440 // f"ur alle alten suchen, ob ein gleiches neues existiert 441 for ( size_t nOld = 0; nOld < pOldArr->size(); ++nOld ) 442 { 443 SfxPoolItem *pOldItem = (*pOldArr)[nOld]; 444 if ( pOldItem ) 445 { 446 sal_uInt32 nFree = SAL_MAX_UINT32; 447 bool bFound = false; 448 for ( size_t nNew = (*ppArr)->size(); nNew--; ) 449 { 450 // geladenes Item 451 SfxPoolItem *&rpNewItem = 452 (SfxPoolItem*&)(*ppArr)->operator[](nNew); 453 454 // surrogat unbenutzt? 455 if ( !rpNewItem ) 456 nFree = nNew; 457 458 // gefunden? 459 else if ( *rpNewItem == *pOldItem ) 460 { 461 // wiederverwenden 462 AddRef( *pOldItem, rpNewItem->GetRefCount() ); 463 SetRefCount( *rpNewItem, 0 ); 464 delete rpNewItem; 465 rpNewItem = pOldItem; 466 bFound = true; 467 break; 468 } 469 } 470 471 // vorhervorhandene, nicht geladene uebernehmen 472 if ( !bFound ) 473 { 474 if ( nFree != SAL_MAX_UINT32 ) 475 (SfxPoolItem*&)(*ppArr)->operator[](nFree) = pOldItem; 476 else 477 (*ppArr)->push_back( (SfxPoolItem*) pOldItem ); 478 } 479 } 480 } 481 } 482 delete pOldArr; 483 } 484 485 // ----------------------------------------------------------------------- 486 487 SvStream &SfxItemPool::Load(SvStream &rStream) 488 { 489 DBG_CHKTHIS(SfxItemPool, 0); 490 DBG_ASSERT(ppStaticDefaults, "kein DefaultArray"); 491 492 // protect items by increasing ref count 493 if ( !bPersistentRefCounts ) 494 { 495 496 // "uber alle Which-Werte iterieren 497 SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems; 498 for( size_t nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr ) 499 { 500 // ist "uberhaupt ein Item mit dem Which-Wert da? 501 if ( *ppItemArr ) 502 { 503 // "uber alle Items mit dieser Which-Id iterieren 504 SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin(); 505 for( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr ) 506 if (*ppHtArr) 507 { 508 #ifdef DBG_UTIL 509 const SfxPoolItem &rItem = **ppHtArr; 510 DBG_ASSERT( !rItem.ISA(SfxSetItem) || 511 0 != &((const SfxSetItem&)rItem).GetItemSet(), 512 "SetItem without ItemSet" ); 513 DBG_WARNING( "loading non-empty ItemPool" ); 514 #endif 515 516 AddRef( **ppHtArr, 1 ); 517 } 518 } 519 } 520 521 // during loading (until LoadCompleted()) protect all items 522 pImp->nInitRefCount = 2; 523 } 524 525 // Load-Master finden 526 SfxItemPool *pLoadMaster = pMaster != this ? pMaster : 0; 527 while ( pLoadMaster && !pLoadMaster->pImp->bStreaming ) 528 pLoadMaster = pLoadMaster->pSecondary; 529 530 // Gesamt Header einlesen 531 pImp->bStreaming = sal_True; 532 if ( !pLoadMaster ) 533 { 534 // Format-Version laden 535 CHECK_FILEFORMAT2( rStream, 536 SFX_ITEMPOOL_TAG_STARTPOOL_5, SFX_ITEMPOOL_TAG_STARTPOOL_4 ); 537 rStream >> pImp->nMajorVer >> pImp->nMinorVer; 538 539 // Format-Version in Master-Pool "ubertragen 540 pMaster->pImp->nMajorVer = pImp->nMajorVer; 541 pMaster->pImp->nMinorVer = pImp->nMinorVer; 542 543 // altes Format? 544 if ( pImp->nMajorVer < 2 ) 545 // pImp->bStreaming wird von Load1_Impl() zur"uckgesetzt 546 return Load1_Impl( rStream ); 547 548 // zu neues Format? 549 if ( pImp->nMajorVer > SFX_ITEMPOOL_VER_MAJOR ) 550 { 551 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR); 552 pImp->bStreaming = sal_False; 553 return rStream; 554 } 555 556 // Version 1.2-Trick-Daten "uberspringen 557 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_TRICK4OLD ); 558 rStream.SeekRel( 4 ); // Hack-Daten wegen SfxStyleSheetPool-Bug skippen 559 } 560 561 // neues Record-orientiertes Format 562 SfxMiniRecordReader aPoolRec( &rStream, SFX_ITEMPOOL_REC ); 563 if ( rStream.GetError() ) 564 { 565 pImp->bStreaming = sal_False; 566 return rStream; 567 } 568 569 // Einzel-Header 570 int bOwnPool = sal_True; 571 UniString aExternName; 572 { 573 // Header-Record suchen 574 SfxMiniRecordReader aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER ); 575 if ( rStream.GetError() ) 576 { 577 pImp->bStreaming = sal_False; 578 return rStream; 579 } 580 581 // Header-lesen 582 rStream >> pImp->nLoadingVersion; 583 SfxPoolItem::readByteString(rStream, aExternName); 584 bOwnPool = aExternName == aName; 585 586 //! solange wir keine fremden Pools laden k"onnen 587 if ( !bOwnPool ) 588 { 589 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR); 590 aPoolRec.Skip(); 591 pImp->bStreaming = sal_False; 592 return rStream; 593 } 594 } 595 596 // Version-Maps 597 { 598 SfxMultiRecordReader aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP ); 599 if ( rStream.GetError() ) 600 { 601 pImp->bStreaming = sal_False; 602 return rStream; 603 } 604 605 // Versions-Maps einlesen 606 sal_uInt16 nOwnVersion = pImp->nVersion; 607 for ( sal_uInt16 nVerNo = 0; aVerRec.GetContent(); ++nVerNo ) 608 { 609 // Header f"ur einzelne Version einlesen 610 sal_uInt16 nVersion, nHStart, nHEnd; 611 rStream >> nVersion >> nHStart >> nHEnd; 612 sal_uInt16 nCount = nHEnd - nHStart + 1; 613 614 // Is new version is known? 615 if ( nVerNo >= pImp->aVersions.size() ) 616 { 617 // Add new Version 618 sal_uInt16 *pMap = new sal_uInt16[nCount]; 619 for ( sal_uInt16 n = 0; n < nCount; ++n ) 620 rStream >> pMap[n]; 621 SetVersionMap( nVersion, nHStart, nHEnd, pMap ); 622 } 623 } 624 pImp->nVersion = nOwnVersion; 625 } 626 627 // Items laden 628 FASTBOOL bSecondaryLoaded = sal_False; 629 long nSecondaryEnd = 0; 630 { 631 SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS); 632 while ( aWhichIdsRec.GetContent() ) 633 { 634 // SlotId, Which-Id und Item-Version besorgen 635 sal_uInt32 nCount; 636 sal_uInt16 nVersion, nWhich; 637 //!sal_uInt16 nSlotId = aWhichIdsRec.GetContentTag(); 638 rStream >> nWhich; 639 if ( pImp->nLoadingVersion != pImp->nVersion ) 640 // Which-Id aus File-Version in Pool-Version verschieben 641 nWhich = GetNewWhich( nWhich ); 642 643 // unbekanntes Item aus neuerer Version 644 if ( !IsInRange(nWhich) ) 645 continue; 646 647 rStream >> nVersion; 648 rStream >> nCount; 649 //!SFX_ASSERTWARNING( !nSlotId || !HasMap() || 650 //! ( nSlotId == GetSlotId( nWhich, sal_False ) ) || 651 //! !GetSlotId( nWhich, sal_False ), 652 //! nWhich, "Slot/Which mismatch" ); 653 654 sal_uInt16 nIndex = GetIndex_Impl(nWhich); 655 SfxPoolItemArray_Impl **ppArr = pImp->ppPoolItems + nIndex; 656 657 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten 658 SfxPoolItem *pDefItem = *(ppStaticDefaults + nIndex); 659 pImp->bInSetItem = pDefItem->ISA(SfxSetItem); 660 if ( !bSecondaryLoaded && pSecondary && pImp->bInSetItem ) 661 { 662 // an das Ende des eigenen Pools seeken 663 sal_uLong nLastPos = rStream.Tell(); 664 aPoolRec.Skip(); 665 666 // Sekund"arpool einlesen 667 pSecondary->Load( rStream ); 668 bSecondaryLoaded = sal_True; 669 nSecondaryEnd = rStream.Tell(); 670 671 // zur"uck zu unseren eigenen Items 672 rStream.Seek(nLastPos); 673 } 674 675 // Items an sich lesen 676 readTheItems(rStream, nCount, nVersion, pDefItem, ppArr); 677 678 pImp->bInSetItem = sal_False; 679 } 680 } 681 682 // Pool-Defaults lesen 683 { 684 SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS ); 685 686 while ( aDefsRec.GetContent() ) 687 { 688 // SlotId, Which-Id und Item-Version besorgen 689 sal_uInt16 nVersion, nWhich; 690 //!sal_uInt16 nSlotId = aDefsRec.GetContentTag(); 691 rStream >> nWhich; 692 if ( pImp->nLoadingVersion != pImp->nVersion ) 693 // Which-Id aus File-Version in Pool-Version verschieben 694 nWhich = GetNewWhich( nWhich ); 695 696 // unbekanntes Item aus neuerer Version 697 if ( !IsInRange(nWhich) ) 698 continue; 699 700 rStream >> nVersion; 701 //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, sal_False ) ), 702 //! nWhich, "Slot/Which mismatch" ); 703 704 // Pool-Default-Item selbst laden 705 SfxPoolItem *pItem = 706 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) ) 707 ->Create( rStream, nVersion ); 708 pItem->SetKind( SFX_ITEMS_POOLDEFAULT ); 709 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem; 710 } 711 } 712 713 // ggf. Secondary-Pool laden 714 aPoolRec.Skip(); 715 if ( pSecondary ) 716 { 717 if ( !bSecondaryLoaded ) 718 pSecondary->Load( rStream ); 719 else 720 rStream.Seek( nSecondaryEnd ); 721 } 722 723 // wenn nicht own-Pool, dann kein Name 724 if ( aExternName != aName ) 725 aName.Erase(); 726 727 pImp->bStreaming = sal_False; 728 return rStream; 729 }; 730 731 // ----------------------------------------------------------------------- 732 733 SvStream &SfxItemPool::Load1_Impl(SvStream &rStream) 734 { 735 // beim Master ist der Header schon von <Load()> geladen worden 736 if ( !pImp->bStreaming ) 737 { 738 // Header des Secondary lesen 739 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_STARTPOOL_4 ); 740 rStream >> pImp->nMajorVer >> pImp->nMinorVer; 741 } 742 sal_uInt32 nAttribSize; 743 int bOwnPool = sal_True; 744 UniString aExternName; 745 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 2 ) 746 rStream >> pImp->nLoadingVersion; 747 SfxPoolItem::readByteString(rStream, aExternName); 748 bOwnPool = aExternName == aName; 749 pImp->bStreaming = sal_True; 750 751 //! solange wir keine fremden laden k"onnen 752 if ( !bOwnPool ) 753 { 754 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR); 755 pImp->bStreaming = sal_False; 756 return rStream; 757 } 758 759 // Versionen bis 1.3 k"onnen noch keine Which-Verschiebungen lesen 760 if ( pImp->nMajorVer == 1 && pImp->nMinorVer <= 2 && 761 pImp->nVersion < pImp->nLoadingVersion ) 762 { 763 rStream.SetError(ERRCODE_IO_WRONGVERSION); 764 pImp->bStreaming = sal_False; 765 return rStream; 766 } 767 768 // Size-Table liegt hinter den eigentlichen Attributen 769 rStream >> nAttribSize; 770 771 // Size-Table einlesen 772 sal_uLong nStartPos = rStream.Tell(); 773 rStream.SeekRel( nAttribSize ); 774 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_SIZES ); 775 sal_uInt32 nSizeTableLen; 776 rStream >> nSizeTableLen; 777 sal_Char *pBuf = new sal_Char[nSizeTableLen]; 778 rStream.Read( pBuf, nSizeTableLen ); 779 sal_uLong nEndOfSizes = rStream.Tell(); 780 SvMemoryStream aSizeTable( pBuf, nSizeTableLen, STREAM_READ ); 781 782 // ab Version 1.3 steht in der Size-Table eine Versions-Map 783 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 3 ) 784 { 785 // Version-Map finden (letztes sal_uLong der Size-Table gibt Pos an) 786 rStream.Seek( nEndOfSizes - sizeof(sal_uInt32) ); 787 sal_uInt32 nVersionMapPos; 788 rStream >> nVersionMapPos; 789 rStream.Seek( nVersionMapPos ); 790 791 // Versions-Maps einlesen 792 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_VERSIONMAP ); 793 sal_uInt16 nVerCount; 794 rStream >> nVerCount; 795 for ( sal_uInt16 nVerNo = 0; nVerNo < nVerCount; ++nVerNo ) 796 { 797 // Header f"ur einzelne Version einlesen 798 sal_uInt16 nVersion, nHStart, nHEnd; 799 rStream >> nVersion >> nHStart >> nHEnd; 800 sal_uInt16 nCount = nHEnd - nHStart + 1; 801 sal_uInt16 nBytes = (nCount)*sizeof(sal_uInt16); 802 803 // Is new version is known? 804 if ( nVerNo >= pImp->aVersions.size() ) 805 { 806 // Add new Version 807 sal_uInt16 *pMap = new sal_uInt16[nCount]; 808 for ( sal_uInt16 n = 0; n < nCount; ++n ) 809 rStream >> pMap[n]; 810 SetVersionMap( nVersion, nHStart, nHEnd, pMap ); 811 } 812 else 813 // Version schon bekannt => "uberspringen 814 rStream.SeekRel( nBytes ); 815 } 816 } 817 818 // Items laden 819 rStream.Seek( nStartPos ); 820 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ITEMS ); 821 FASTBOOL bSecondaryLoaded = sal_False; 822 long nSecondaryEnd = 0; 823 sal_uInt16 nWhich, nSlot; 824 while ( rStream >> nWhich, nWhich ) 825 { 826 // ggf. Which-Id aus alter Version verschieben? 827 if ( pImp->nLoadingVersion != pImp->nVersion ) 828 nWhich = GetNewWhich( nWhich ); 829 830 rStream >> nSlot; 831 sal_uInt16 nMappedWhich = GetWhich(nSlot, sal_False); 832 int bKnownItem = bOwnPool || IsWhich(nMappedWhich); 833 834 sal_uInt16 nRef, nCount, nVersion; 835 sal_uInt32 nAttrSize; 836 rStream >> nVersion >> nCount; 837 838 SfxPoolItemArray_Impl **ppArr = 0; 839 SfxPoolItemArray_Impl *pNewArr = 0; 840 SfxPoolItem *pDefItem = 0; 841 if ( bKnownItem ) 842 { 843 if ( !bOwnPool ) 844 nWhich = nMappedWhich; 845 846 //!SFX_ASSERTWARNING( !nSlot || !HasMap() || 847 //! ( nSlot == GetSlotId( nWhich, sal_False ) ) || 848 //! !GetSlotId( nWhich, sal_False ), 849 //! nWhich, "Slot/Which mismatch" ); 850 851 sal_uInt16 nIndex = GetIndex_Impl(nWhich); 852 ppArr = pImp->ppPoolItems + nIndex; 853 pNewArr = new SfxPoolItemArray_Impl(); 854 pDefItem = *(ppStaticDefaults + nIndex); 855 } 856 857 // Position vor ersten Item merken 858 sal_uLong nLastPos = rStream.Tell(); 859 860 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten 861 if ( !bSecondaryLoaded && pSecondary && pDefItem->ISA(SfxSetItem) ) 862 { 863 // an das Ende des eigenen Pools seeken 864 rStream.Seek(nEndOfSizes); 865 CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr ); 866 CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr ); 867 868 // Sekund"arpool einlesen 869 pSecondary->Load1_Impl( rStream ); 870 bSecondaryLoaded = sal_True; 871 nSecondaryEnd = rStream.Tell(); 872 873 // zur"uck zu unseren eigenen Items 874 rStream.Seek(nLastPos); 875 } 876 877 // Items an sich lesen 878 for ( sal_uInt16 j = 0; j < nCount; ++j ) 879 { 880 sal_uLong nPos = nLastPos; 881 rStream >> nRef; 882 883 if ( bKnownItem ) 884 { 885 SfxPoolItem *pItem = 0; 886 if ( nRef ) 887 { 888 pItem = pDefItem->Create(rStream, nVersion); 889 890 if ( !bPersistentRefCounts ) 891 // bis <SfxItemPool::LoadCompleted()> festhalten 892 AddRef(*pItem, 1); 893 else 894 { 895 if ( nRef > SFX_ITEMS_OLD_MAXREF ) 896 pItem->SetKind( nRef ); 897 else 898 AddRef(*pItem, nRef); 899 } 900 } 901 //pNewArr->insert( pItem, j ); 902 pNewArr->push_back( (SfxPoolItem*) pItem ); 903 904 // restliche gespeicherte Laenge skippen (neueres Format) 905 nLastPos = rStream.Tell(); 906 } 907 908 aSizeTable >> nAttrSize; 909 SFX_ASSERT( !bKnownItem || ( nPos + nAttrSize) >= nLastPos, 910 nPos, 911 "too many bytes read - version mismatch?" ); 912 913 if ( !bKnownItem || ( nLastPos < (nPos + nAttrSize) ) ) 914 { 915 nLastPos = nPos + nAttrSize; 916 rStream.Seek( nLastPos ); 917 } 918 } 919 920 if ( bKnownItem ) 921 { 922 SfxPoolItemArray_Impl *pOldArr = *ppArr; 923 *ppArr = pNewArr; 924 925 // die Items merken, die schon im Pool sind 926 int bEmpty = sal_True; 927 if ( 0 != pOldArr ) 928 for ( size_t n = 0; bEmpty && n < pOldArr->size(); ++n ) 929 bEmpty = pOldArr->operator[](n) == 0; 930 DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" ); 931 if ( !bEmpty ) 932 { 933 // f"ur alle alten suchen, ob ein gleiches neues existiert 934 for ( size_t nOld = 0; nOld < pOldArr->size(); ++nOld ) 935 { 936 SfxPoolItem *pOldItem = (*pOldArr)[nOld]; 937 if ( pOldItem ) 938 { 939 bool bFound = false; 940 for ( size_t nNew = 0; 941 nNew < (*ppArr)->size(); ++nNew ) 942 { 943 SfxPoolItem *&rpNewItem = 944 (SfxPoolItem*&)(*ppArr)->operator[](nNew); 945 946 if ( rpNewItem && *rpNewItem == *pOldItem ) 947 { 948 AddRef( *pOldItem, rpNewItem->GetRefCount() ); 949 SetRefCount( *rpNewItem, 0 ); 950 delete rpNewItem; 951 rpNewItem = pOldItem; 952 bFound = true; 953 SFX_TRACE( "reusing item", pOldItem ); 954 break; 955 } 956 } 957 if ( !bFound ) 958 { 959 SFX_TRACE( "item not found: ", pOldItem ); 960 } 961 } 962 } 963 } 964 delete pOldArr; /* @@@ */ 965 } 966 } 967 968 // Pool-Defaults lesen 969 if ( pImp->nMajorVer > 1 || pImp->nMinorVer > 0 ) 970 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_DEFAULTS ); 971 972 sal_uLong nLastPos = rStream.Tell(); 973 while ( rStream >> nWhich, nWhich ) 974 { 975 // ggf. Which-Id aus alter Version verschieben? 976 if ( pImp->nLoadingVersion != pImp->nVersion ) 977 nWhich = GetNewWhich( nWhich ); 978 979 rStream >> nSlot; 980 sal_uInt16 nMappedWhich = GetWhich(nSlot, sal_False); 981 int bKnownItem = bOwnPool || IsWhich(nMappedWhich); 982 983 sal_uLong nPos = nLastPos; 984 sal_uInt32 nSize; 985 sal_uInt16 nVersion; 986 rStream >> nVersion; 987 988 if ( bKnownItem ) 989 { 990 if ( !bOwnPool ) 991 nWhich = nMappedWhich; 992 SfxPoolItem *pItem = 993 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) ) 994 ->Create( rStream, nVersion ); 995 pItem->SetKind( SFX_ITEMS_POOLDEFAULT ); 996 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem; 997 } 998 999 nLastPos = rStream.Tell(); 1000 aSizeTable >> nSize; 1001 SFX_ASSERT( ( nPos + nSize) >= nLastPos, nPos, 1002 "too many bytes read - version mismatch?" ); 1003 if ( nLastPos < (nPos + nSize) ) 1004 rStream.Seek( nPos + nSize ); 1005 } 1006 1007 delete[] pBuf; 1008 rStream.Seek(nEndOfSizes); 1009 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL ); 1010 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL ); 1011 1012 if ( pSecondary ) 1013 { 1014 if ( !bSecondaryLoaded ) 1015 pSecondary->Load1_Impl( rStream ); 1016 else 1017 rStream.Seek( nSecondaryEnd ); 1018 } 1019 1020 if ( aExternName != aName ) 1021 aName.Erase(); 1022 1023 pImp->bStreaming = sal_False; 1024 return rStream; 1025 } 1026 1027 // ----------------------------------------------------------------------- 1028 1029 const SfxPoolItem* SfxItemPool::LoadSurrogate 1030 ( 1031 SvStream& rStream, // vor einem Surrogat positionierter Stream 1032 sal_uInt16& rWhich, // Which-Id des zu ladenden <SfxPoolItem>s 1033 sal_uInt16 nSlotId, // Slot-Id des zu ladenden <SfxPoolItem>s 1034 const SfxItemPool* pRefPool // <SfxItemPool> in dem das Surrogat gilt 1035 ) 1036 1037 /* [Beschreibung] 1038 1039 L"adt Surrogat aus 'rStream' und liefert das dadurch in 'rRefPool' 1040 repr"asentierte SfxPoolItem zu"ruck. Ist das im Stream befindliche 1041 Surrogat == SFX_ITEMS_DIRECT (!SFX_ITEM_POOLABLE) wird 0 zur"uckgegeben, 1042 das Item ist direkt aus dem Stream zu laden. Bei 0xfffffff0 (SFX_ITEMS_NULL) 1043 wird auch 0 zurueckgegeben und rWhich auf 0 gesetzt, das Item ist nicht 1044 verfuegbar. 1045 1046 Ansonsten wird ber"ucksichtigt, ob der betroffene Pool ohne Ref-Counts 1047 geladen wird, ob aus einem neuen Pool nachgeladen wird (&rRefPool != this) 1048 oder ob aus einem g"anzlich anders aufgebauten Pool geladen wird. 1049 1050 Wird aus einem anders aufgebauten Pool geladen und die 'nSlotId' kann 1051 nicht in eine Which-Id dieses Pools gemappt werden, wird ebenfalls 0 1052 zur"uckgeliefert. 1053 1054 Preconditions: - Pool mu\s geladen sein 1055 - LoadCompleted darf noch nicht gerufen worden sein 1056 - 'rStream' steht genau an der Position, an der ein 1057 Surrogat f"ur ein Item mit der SlotId 'nSlotId' und 1058 der WhichId 'rWhichId' mit StoreSurrogate gepeichert 1059 wurde 1060 1061 Postconditions: - 'rStream' ist so positioniert, wie auch StoreSurrogate 1062 sein speichern beendet hatte 1063 - konnte ein Item geladen werden, befindet es sich 1064 in diesem SfxItemPool 1065 - 'rWhichId' enth"alt die ggf. gemappte Which-Id 1066 Laufzeit: Tiefe des Ziel Sekund"arpools * 10 + 10 1067 1068 [Querverweise] 1069 1070 <SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const> 1071 */ 1072 1073 { 1074 // Read the first surrogate 1075 sal_uInt32 nSurrogat; 1076 rStream >> nSurrogat; 1077 1078 // Is item stored directly? 1079 if ( SFX_ITEMS_DIRECT == nSurrogat ) 1080 return 0; 1081 1082 // Item does not exist? 1083 if ( SFX_ITEMS_NULL == nSurrogat ) 1084 { 1085 rWhich = 0; 1086 return 0; 1087 } 1088 1089 // Bei einem identisch aufgebauten Pool (im Stream) kann das Surrogat 1090 // auf jeden Fall aufgel"ost werden. 1091 if ( !pRefPool ) 1092 pRefPool = this; 1093 FASTBOOL bResolvable = pRefPool->GetName().Len() > 0; 1094 if ( !bResolvable ) 1095 { 1096 // Bei einem anders aufgebauten Pool im Stream, mu\s die SlotId 1097 // aus dem Stream in eine Which-Id gemappt werden k"onnen. 1098 sal_uInt16 nMappedWhich = nSlotId ? GetWhich(nSlotId, sal_True) : 0; 1099 if ( IsWhich(nMappedWhich) ) 1100 { 1101 // gemappte SlotId kann "ubernommen werden 1102 rWhich = nMappedWhich; 1103 bResolvable = sal_True; 1104 } 1105 } 1106 1107 // kann Surrogat aufgel"ost werden? 1108 const SfxPoolItem *pItem = 0; 1109 if ( bResolvable ) 1110 { 1111 for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pSecondary ) 1112 { 1113 // richtigen (Folge-) Pool gefunden? 1114 if ( pTarget->IsInRange(rWhich) ) 1115 { 1116 // dflt-Attribut? 1117 if ( SFX_ITEMS_DEFAULT == nSurrogat ) 1118 return *(pTarget->ppStaticDefaults + 1119 pTarget->GetIndex_Impl(rWhich)); 1120 1121 SfxPoolItemArray_Impl* pItemArr = *(pTarget->pImp->ppPoolItems + 1122 pTarget->GetIndex_Impl(rWhich)); 1123 pItem = pItemArr && nSurrogat < pItemArr->size() 1124 ? (*pItemArr)[nSurrogat] 1125 : 0; 1126 if ( !pItem ) 1127 { 1128 DBG_ERROR( "can't resolve surrogate" ); 1129 rWhich = 0; // nur zur Sicherheit fuer richtige Stream-Pos 1130 return 0; 1131 } 1132 1133 // Nachladen aus Ref-Pool? 1134 if ( pRefPool != pMaster ) 1135 return &pTarget->Put( *pItem ); 1136 1137 // Referenzen sind NICHT schon mit Pool geladen worden? 1138 if ( !pTarget->HasPersistentRefCounts() ) 1139 AddRef( *pItem, 1 ); 1140 else 1141 return pItem; 1142 1143 return pItem; 1144 } 1145 } 1146 1147 SFX_ASSERT( sal_False, rWhich, "can't resolve Which-Id in LoadSurrogate" ); 1148 } 1149 1150 return 0; 1151 } 1152 1153 //------------------------------------------------------------------------- 1154 1155 1156 FASTBOOL SfxItemPool::StoreSurrogate 1157 ( 1158 SvStream& rStream, 1159 const SfxPoolItem* pItem 1160 ) const 1161 1162 /* [Beschreibung] 1163 1164 Speichert ein Surrogat f"ur '*pItem' in 'rStream'. 1165 1166 1167 [R"uckgabewert] 1168 1169 FASTBOOL sal_True 1170 es wurde ein echtes Surrogat gespeichert, auch 1171 SFX_ITEMS_NULL bei 'pItem==0', 1172 SFX_ITEMS_STATICDEFAULT und SFX_ITEMS_POOLDEFAULT 1173 gelten als 'echte' Surrogate 1174 1175 sal_False 1176 es wurde ein Dummy-Surrogat (SFX_ITEMS_DIRECT) 1177 gespeichert, das eigentliche Item mu\s direkt 1178 hinterher selbst gespeichert werden 1179 */ 1180 1181 { 1182 if ( pItem ) 1183 { 1184 FASTBOOL bRealSurrogate = IsItemFlag(*pItem, SFX_ITEM_POOLABLE); 1185 rStream << ( bRealSurrogate 1186 ? GetSurrogate( pItem ) 1187 : SFX_ITEMS_DIRECT ); 1188 return bRealSurrogate; 1189 } 1190 1191 rStream << SFX_ITEMS_NULL; 1192 return sal_True; 1193 } 1194 1195 // ----------------------------------------------------------------------- 1196 1197 sal_uInt32 SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const 1198 { 1199 DBG_CHKTHIS(SfxItemPool, 0); 1200 DBG_ASSERT( pItem, "no 0-Pointer Surrogate" ); 1201 DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" ); 1202 DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" ); 1203 1204 if ( !IsInRange(pItem->Which()) ) 1205 { 1206 if ( pSecondary ) 1207 return pSecondary->GetSurrogate( pItem ); 1208 SFX_ASSERT( 0, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" ); 1209 } 1210 1211 // Pointer auf static- oder pool-dflt-Attribut? 1212 if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) ) 1213 return SFX_ITEMS_DEFAULT; 1214 1215 SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(pItem->Which())); 1216 DBG_ASSERT(pItemArr, "ItemArr is not available"); 1217 1218 for ( size_t i = 0; i < pItemArr->size(); ++i ) 1219 { 1220 const SfxPoolItem *p = (*pItemArr)[i]; 1221 if ( p == pItem ) 1222 return i; 1223 } 1224 SFX_ASSERT( 0, pItem->Which(), "Item not in the pool"); 1225 return SFX_ITEMS_NULL; 1226 } 1227 1228 // ----------------------------------------------------------------------- 1229 1230 FASTBOOL SfxItemPool::IsInStoringRange( sal_uInt16 nWhich ) const 1231 { 1232 return nWhich >= pImp->nStoringStart && 1233 nWhich <= pImp->nStoringEnd; 1234 } 1235 1236 //------------------------------------------------------------------------ 1237 1238 void SfxItemPool::SetStoringRange( sal_uInt16 nFrom, sal_uInt16 nTo ) 1239 1240 /* [Beschreibung] 1241 1242 Mit dieser Methode kann der Which-Bereich eingeengt werden, der 1243 von ItemSets dieses Pool (und dem Pool selbst) gespeichert wird. 1244 Die Methode muss dazu vor <SfxItemPool::Store()> gerufen werden 1245 und die Werte muessen auch noch gesetzt sein, wenn das eigentliche 1246 Dokument (also die ItemSets gespeicher werden). 1247 1248 Ein Zuruecksetzen ist dann nicht noetig, wenn dieser Range vor 1249 JEDEM Speichern richtig gesetzt wird, da er nur beim Speichern 1250 beruecksichtigt wird. 1251 1252 Dieses muss fuer das 3.1-Format gemacht werden, da dort eine 1253 Bug in der Pool-Lade-Methode vorliegt. 1254 */ 1255 1256 { 1257 pImp->nStoringStart = nFrom; 1258 pImp->nStoringEnd = nTo; 1259 } 1260 1261 // ----------------------------------------------------------------------- 1262 1263 void SfxItemPool::SetVersionMap 1264 ( 1265 sal_uInt16 nVer, /* neue Versionsnummer */ 1266 sal_uInt16 nOldStart, /* alte erste Which-Id */ 1267 sal_uInt16 nOldEnd, /* alte letzte Which-Id */ 1268 sal_uInt16* pOldWhichIdTab /* Array mit genau dem Aufbau der Which-Ids 1269 der vorhergehenden Version, in denen 1270 die jeweils neue Which-Id steht. */ 1271 ) 1272 1273 /* [Beschreibung] 1274 1275 Mit dieser Methode k"onnen neue, inkompatible Which-Id-Folgen oder 1276 Verteilungen realisiert werden. Pools, die noch mit alten Versionen 1277 gespeichert wurden, werden dann "uber die angegebene Tabelle solange 1278 gemappt, bis die aktuelle Version erreicht ist. Neuere Pools k"onnen 1279 unter Verlust neuer Attribute geladen werden, da die Map mit dem Pool 1280 gespeichert wird. 1281 1282 Precondition: Pool darf noch nicht geladen sein 1283 Postcondition: Which-Ids aus fr"uheren Versionen k"onnen bei Laden auf 1284 Version 'nVer' gemappt werden 1285 Laufzeit: 1.5 * new + 10 1286 1287 [Anmerkung] 1288 1289 F"ur neue Which-Ranges (nStart,nEnd) m"ssen im Vergleich zur Vorg"anger- 1290 Version (nOldStart,nOldEnd) immer gelten, da\s (nOldStart,nOldEnd) 1291 vollst"andig in (nStart,nEnd) enthalten ist. Es ist also zul"assig, den 1292 Which-Range in beide Richtungen zu erweitern, auch durch Einf"ugung 1293 von Which-Ids, nicht aber ihn zu beschneiden. 1294 1295 Diese Methode sollte nur im oder direkt nach Aufruf des Konstruktors 1296 gerufen werden. 1297 1298 Das Array mu\s statisch sein, da es nicht kopiert wird und au\serdem 1299 im Copy-Ctor des SfxItemPool wiederverwendet wird. 1300 1301 1302 [Beispiel] 1303 1304 Urspr"unglich (Version 0) hatte der Pool folgende Which-Ids: 1305 1306 1:A, 2:B, 3:C, 4:D 1307 1308 Nun soll eine neue Version (Version 1) zwei zus"atzliche Ids X und Y 1309 zwischen B und C erhalten, also wie folgt aussehen: 1310 1311 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D 1312 1313 Dabei haben sich also die Ids 3 und 4 ge"andert. F"ur die neue Version 1314 m"u\ste am Pool folgendes gesetzt werden: 1315 1316 static sal_uInt16 nVersion1Map = { 1, 2, 5, 6 }; 1317 pPool->SetVersionMap( 1, 1, 4, &nVersion1Map ); 1318 1319 1320 [Querverweise] 1321 1322 <SfxItemPool::IsLoadingVersionCurrent()const> 1323 <SfxItemPool::GetNewWhich(sal_uInt16)> 1324 <SfxItemPool::GetVersion()const> 1325 <SfxItemPool::GetLoadingVersion()const> 1326 */ 1327 1328 { 1329 // create new map entry to insert 1330 const SfxPoolVersion_ImplPtr pVerMap = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl( 1331 nVer, nOldStart, nOldEnd, pOldWhichIdTab ) ); 1332 pImp->aVersions.push_back( pVerMap ); 1333 1334 DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" ); 1335 pImp->nVersion = nVer; 1336 1337 // Versions-Range anpassen 1338 for ( sal_uInt16 n = 0; n < nOldEnd-nOldStart+1; ++n ) 1339 { 1340 sal_uInt16 nWhich = pOldWhichIdTab[n]; 1341 if ( nWhich < pImp->nVerStart ) 1342 { 1343 if ( !nWhich ) 1344 nWhich = 0; 1345 pImp->nVerStart = nWhich; 1346 } 1347 else if ( nWhich > pImp->nVerEnd ) 1348 pImp->nVerEnd = nWhich; 1349 } 1350 } 1351 1352 // ----------------------------------------------------------------------- 1353 1354 sal_uInt16 SfxItemPool::GetNewWhich 1355 ( 1356 sal_uInt16 nFileWhich // die aus dem Stream geladene Which-Id 1357 ) const 1358 1359 /* [Beschreibung] 1360 1361 Diese Methoden rechnet Which-Ids aus einem File-Format in die der 1362 aktuellen Pool-Version um. Ist das File-Format "alter, werden die vom 1363 Pool-Entwickler mit SetVersion() gesetzten Tabellen verwendet, 1364 ist das File-Format neuer, dann die aus dem File geladenen Tabellen. 1365 Im letzteren Fall kann ggf. nicht jede Which-Id gemappt werden, 1366 so da\s 0 zur"uckgeliefert wird. 1367 1368 Die Berechnung ist nur f"ur Which-Ids definiert, die in der betreffenden 1369 File-Version unterst"utzt wurden. Dies ist per Assertion abgesichert. 1370 1371 Precondition: Pool mu\s geladen sein 1372 Postcondition: unver"andert 1373 Laufzeit: linear(Anzahl der Sekund"arpools) + 1374 linear(Differenz zwischen alter und neuer Version) 1375 1376 1377 [Querverweise] 1378 1379 <SfxItemPool::IsLoadingVersionCurrent()const> 1380 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1381 <SfxItemPool::GetVersion()const> 1382 <SfxItemPool::GetLoadingVersion()const> 1383 */ 1384 1385 { 1386 // (Sekund"ar-) Pool bestimmen 1387 if ( !IsInVersionsRange(nFileWhich) ) 1388 { 1389 if ( pSecondary ) 1390 return pSecondary->GetNewWhich( nFileWhich ); 1391 SFX_ASSERT( 0, nFileWhich, "unknown which in GetNewWhich()" ); 1392 } 1393 1394 // Version neuer/gleich/"alter? 1395 short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion; 1396 1397 // Which-Id einer neueren Version? 1398 if ( nDiff > 0 ) 1399 { 1400 // von der Top-Version bis runter zur File-Version stufenweise mappen 1401 for ( size_t nMap = pImp->aVersions.size(); nMap > 0; --nMap ) 1402 { 1403 SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap-1]; 1404 if ( pVerInfo->_nVer > pImp->nVersion ) 1405 { sal_uInt16 nOfs; 1406 sal_uInt16 nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1; 1407 for ( nOfs = 0; 1408 nOfs <= nCount && 1409 pVerInfo->_pMap[nOfs] != nFileWhich; 1410 ++nOfs ) 1411 continue; 1412 1413 if ( pVerInfo->_pMap[nOfs] == nFileWhich ) 1414 nFileWhich = pVerInfo->_nStart + nOfs; 1415 else 1416 return 0; 1417 } 1418 else 1419 break; 1420 } 1421 } 1422 1423 // Which-Id einer neueren Version? 1424 else if ( nDiff < 0 ) 1425 { 1426 // von der File-Version bis zur aktuellen Version stufenweise mappen 1427 for ( size_t nMap = 0; nMap < pImp->aVersions.size(); ++nMap ) 1428 { 1429 SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap]; 1430 if ( pVerInfo->_nVer > pImp->nLoadingVersion ) 1431 { 1432 DBG_ASSERT( nFileWhich >= pVerInfo->_nStart && 1433 nFileWhich <= pVerInfo->_nEnd, 1434 "which-id unknown in version" ); 1435 nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart]; 1436 } 1437 } 1438 } 1439 1440 // originale (nDiff==0) bzw. gemappte (nDiff!=0) Id zur"uckliefern 1441 return nFileWhich; 1442 } 1443 1444 // ----------------------------------------------------------------------- 1445 1446 1447 FASTBOOL SfxItemPool::IsInVersionsRange( sal_uInt16 nWhich ) const 1448 { 1449 return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd; 1450 } 1451 1452 // ----------------------------------------------------------------------- 1453 1454 FASTBOOL SfxItemPool::IsCurrentVersionLoading() const 1455 1456 /* [Beschreibung] 1457 1458 Mit dieser Methode kann festgestellt werden, ob die geladene Pool-Version 1459 dem aktuellen Pool-Aufbau entspricht. 1460 1461 Precondition: Pool mu\s geladen sein 1462 Postcondition: unver"andert 1463 Laufzeit: linear(Anzahl der Sekund"arpools) 1464 1465 1466 [Querverweise] 1467 1468 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1469 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1470 <SfxItemPool::GetVersion()const> 1471 <SfxItemPool::GetLoadingVersion()const> 1472 */ 1473 1474 { 1475 return ( pImp->nVersion == pImp->nLoadingVersion ) && 1476 ( !pSecondary || pSecondary->IsCurrentVersionLoading() ); 1477 } 1478 1479 // ----------------------------------------------------------------------- 1480 1481 sal_uInt16 SfxItemPool::GetVersion() const 1482 1483 /* [Beschreibung] 1484 1485 Diese Methode liefert die aktuelle Versionsnummer des SfxItemPool-Aufbaus 1486 (also des Which-Bereichs). 1487 1488 Precondition: keine 1489 Postcondition: unver"andert 1490 Laufzeit: 2 1491 1492 1493 [Anmerkung] 1494 1495 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools 1496 ber"ucksichtigt werden. 1497 1498 1499 [Querverweise] 1500 1501 <SfxItemPool::IsLoadingVersionCurrent()const> 1502 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1503 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1504 <SfxItemPool::GetLoadingVersion()const> 1505 */ 1506 1507 { 1508 return pImp->nVersion; 1509 } 1510 1511 // ----------------------------------------------------------------------- 1512 1513 sal_uInt16 SfxItemPool::GetLoadingVersion() const 1514 1515 /* [Beschreibung] 1516 1517 Diese Methode liefert die Versionsnummer des SfxItemPool-Aufbaus 1518 (also des Which-Bereichs), die bei Laden vorgefunden wurde. 1519 1520 Precondition: Pool mu\s geladen sein 1521 Postcondition: unver"andert 1522 Laufzeit: 2 1523 1524 1525 [Anmerkung] 1526 1527 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools 1528 ber"ucksichtigt werden. 1529 1530 1531 [Querverweise] 1532 1533 <SfxItemPool::IsLoadingVersionCurrent()const> 1534 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1535 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1536 <SfxItemPool::GetVersion()const> 1537 */ 1538 1539 { 1540 return pImp->nLoadingVersion; 1541 } 1542 1543 //------------------------------------------------------------------------- 1544 1545 FASTBOOL SfxItemPool::IsVer2_Impl() const 1546 { 1547 return pMaster->pImp->nMajorVer >= 2; 1548 } 1549 1550 //------------------------------------------------------------------------- 1551 1552 1553 FASTBOOL SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem, 1554 FASTBOOL bDirect ) const 1555 1556 /* [Beschreibung] 1557 1558 Speichert das <SfxPoolItem> 'rItem' in den <SvStream> 'rStream' 1559 entweder als Surrogat ('bDirect == sal_False') oder direkt mit 'rItem.Store()'. 1560 Nicht poolable Items werden immer direkt gespeichert. Items ohne Which-Id, 1561 also SID-Items, werden nicht gespeichert, ebenso wenn Items, die in der 1562 File-Format-Version noch nicht vorhanden waren (return sal_False). 1563 1564 Das Item wird im Stream wie folgt abgelegt: 1565 1566 sal_uInt16 rItem.Which() 1567 sal_uInt16 GetSlotId( rItem.Which() ) bzw. 0 falls nicht verf"urbar 1568 sal_uInt16 GetSurrogate( &rItem ) bzw. SFX_ITEM_DIRECT bei '!SFX_ITEM_POOLBLE' 1569 1570 optional (falls 'bDirect == sal_True' oder '!rItem.IsPoolable()': 1571 1572 sal_uInt16 rItem.GetVersion() 1573 sal_uLong Size 1574 Size rItem.Store() 1575 1576 1577 [Querverweise] 1578 1579 <SfxItemPool::LoadItem(SvStream&,FASTBOOL)const> 1580 */ 1581 1582 { 1583 DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" ); 1584 1585 if ( IsSlot( rItem.Which() ) ) 1586 return sal_False; 1587 const SfxItemPool *pPool = this; 1588 while ( !pPool->IsInStoringRange(rItem.Which()) ) 1589 if ( 0 == ( pPool = pPool->pSecondary ) ) 1590 return sal_False; 1591 1592 DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem), 1593 "SetItem contains ItemSet with SetItem" ); 1594 1595 sal_uInt16 nSlotId = pPool->GetSlotId( rItem.Which(), sal_True ); 1596 sal_uInt16 nItemVersion = rItem.GetVersion(_nFileFormatVersion); 1597 if ( USHRT_MAX == nItemVersion ) 1598 return sal_False; 1599 1600 rStream << rItem.Which() << nSlotId; 1601 if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) ) 1602 { 1603 rStream << nItemVersion; 1604 rStream << (sal_uInt32) 0L; // Platz fuer Laenge in Bytes 1605 sal_uLong nIStart = rStream.Tell(); 1606 rItem.Store(rStream, nItemVersion); 1607 sal_uLong nIEnd = rStream.Tell(); 1608 rStream.Seek( nIStart-4 ); 1609 rStream << (sal_Int32) ( nIEnd-nIStart ); 1610 rStream.Seek( nIEnd ); 1611 } 1612 1613 return sal_True; 1614 } 1615 1616 //------------------------------------------------------------------------- 1617 1618 1619 const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, FASTBOOL bDirect, 1620 const SfxItemPool *pRefPool ) 1621 1622 // pRefPool==-1 => nicht putten! 1623 1624 { 1625 sal_uInt16 nWhich, nSlot; // nSurrogate; 1626 rStream >> nWhich >> nSlot; 1627 1628 sal_Bool bDontPut = (SfxItemPool*)-1 == pRefPool; 1629 if ( bDontPut || !pRefPool ) 1630 pRefPool = this; 1631 1632 // richtigen Sekund"ar-Pool finden 1633 while ( !pRefPool->IsInVersionsRange(nWhich) ) 1634 { 1635 if ( pRefPool->pSecondary ) 1636 pRefPool = pRefPool->pSecondary; 1637 else 1638 { 1639 // WID in der Version nicht vorhanden => ueberspringen 1640 sal_uInt32 nSurro; 1641 sal_uInt16 nVersion, nLen; 1642 rStream >> nSurro; 1643 if ( SFX_ITEMS_DIRECT == nSurro ) 1644 { 1645 rStream >> nVersion >> nLen; 1646 rStream.SeekRel( nLen ); 1647 } 1648 return 0; 1649 } 1650 } 1651 1652 // wird eine andere Version geladen? 1653 FASTBOOL bCurVersion = pRefPool->IsCurrentVersionLoading(); 1654 if ( !bCurVersion ) 1655 // Which-Id auf neue Version mappen 1656 nWhich = pRefPool->GetNewWhich( nWhich ); 1657 1658 DBG_ASSERT( !nWhich || !pImp->bInSetItem || 1659 !pRefPool->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem), 1660 "loading SetItem in ItemSet of SetItem" ); 1661 1662 // soll "uber Surrogat geladen werden? 1663 const SfxPoolItem *pItem = 0; 1664 if ( !bDirect ) 1665 { 1666 // Which-Id in dieser Version bekannt? 1667 if ( nWhich ) 1668 // Surrogat laden, reagieren falls keins vorhanden 1669 pItem = LoadSurrogate( rStream, nWhich, nSlot, pRefPool ); 1670 else 1671 // sonst "uberspringen 1672 rStream.SeekRel( sizeof(sal_uInt16) ); 1673 } 1674 1675 // wird direkt, also nicht "uber Surrogat geladen? 1676 if ( bDirect || ( nWhich && !pItem ) ) 1677 { 1678 // bDirekt bzw. nicht IsPoolable() => Item direkt laden 1679 sal_uInt16 nVersion; 1680 sal_uInt32 nLen; 1681 rStream >> nVersion >> nLen; 1682 sal_uLong nIStart = rStream.Tell(); 1683 1684 // Which-Id in dieser Version bekannt? 1685 if ( nWhich ) 1686 { 1687 // Item direkt laden 1688 SfxPoolItem *pNewItem = 1689 pRefPool->GetDefaultItem(nWhich).Create(rStream, nVersion); 1690 if ( bDontPut ) 1691 pItem = pNewItem; 1692 else 1693 if ( pNewItem ) 1694 { 1695 pItem = &Put(*pNewItem); 1696 delete pNewItem; 1697 } 1698 else 1699 pItem = 0; 1700 sal_uLong nIEnd = rStream.Tell(); 1701 DBG_ASSERT( nIEnd <= (nIStart+nLen), "read past end of item" ); 1702 if ( (nIStart+nLen) != nIEnd ) 1703 rStream.Seek( nIStart+nLen ); 1704 } 1705 else 1706 // Item "uberspringen 1707 rStream.Seek( nIStart+nLen ); 1708 } 1709 1710 return pItem; 1711 } 1712 1713 1714