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(0); 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(0), nHStart(0), nHEnd(0); 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 memset(pMap, 0, nCount * sizeof(sal_uInt16)); 620 for ( sal_uInt16 n = 0; n < nCount; ++n ) 621 rStream >> pMap[n]; 622 SetVersionMap( nVersion, nHStart, nHEnd, pMap ); 623 } 624 } 625 pImp->nVersion = nOwnVersion; 626 } 627 628 // Items laden 629 FASTBOOL bSecondaryLoaded = sal_False; 630 long nSecondaryEnd = 0; 631 { 632 SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS); 633 while ( aWhichIdsRec.GetContent() ) 634 { 635 // SlotId, Which-Id und Item-Version besorgen 636 sal_uInt32 nCount(0); 637 sal_uInt16 nVersion(0), nWhich(0); 638 //!sal_uInt16 nSlotId = aWhichIdsRec.GetContentTag(); 639 rStream >> nWhich; 640 if ( pImp->nLoadingVersion != pImp->nVersion ) 641 // Which-Id aus File-Version in Pool-Version verschieben 642 nWhich = GetNewWhich( nWhich ); 643 644 // unbekanntes Item aus neuerer Version 645 if ( !IsInRange(nWhich) ) 646 continue; 647 648 rStream >> nVersion; 649 rStream >> nCount; 650 //!SFX_ASSERTWARNING( !nSlotId || !HasMap() || 651 //! ( nSlotId == GetSlotId( nWhich, sal_False ) ) || 652 //! !GetSlotId( nWhich, sal_False ), 653 //! nWhich, "Slot/Which mismatch" ); 654 655 sal_uInt16 nIndex = GetIndex_Impl(nWhich); 656 SfxPoolItemArray_Impl **ppArr = pImp->ppPoolItems + nIndex; 657 658 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten 659 SfxPoolItem *pDefItem = *(ppStaticDefaults + nIndex); 660 pImp->bInSetItem = pDefItem->ISA(SfxSetItem); 661 if ( !bSecondaryLoaded && pSecondary && pImp->bInSetItem ) 662 { 663 // an das Ende des eigenen Pools seeken 664 sal_uLong nLastPos = rStream.Tell(); 665 aPoolRec.Skip(); 666 667 // Sekund"arpool einlesen 668 pSecondary->Load( rStream ); 669 bSecondaryLoaded = sal_True; 670 nSecondaryEnd = rStream.Tell(); 671 672 // zur"uck zu unseren eigenen Items 673 rStream.Seek(nLastPos); 674 } 675 676 // Items an sich lesen 677 readTheItems(rStream, nCount, nVersion, pDefItem, ppArr); 678 679 pImp->bInSetItem = sal_False; 680 } 681 } 682 683 // Pool-Defaults lesen 684 { 685 SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS ); 686 687 while ( aDefsRec.GetContent() ) 688 { 689 // SlotId, Which-Id und Item-Version besorgen 690 sal_uInt16 nVersion(0), nWhich(0); 691 //!sal_uInt16 nSlotId = aDefsRec.GetContentTag(); 692 rStream >> nWhich; 693 if ( pImp->nLoadingVersion != pImp->nVersion ) 694 // Which-Id aus File-Version in Pool-Version verschieben 695 nWhich = GetNewWhich( nWhich ); 696 697 // unbekanntes Item aus neuerer Version 698 if ( !IsInRange(nWhich) ) 699 continue; 700 701 rStream >> nVersion; 702 //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, sal_False ) ), 703 //! nWhich, "Slot/Which mismatch" ); 704 705 // Pool-Default-Item selbst laden 706 SfxPoolItem *pItem = 707 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) ) 708 ->Create( rStream, nVersion ); 709 pItem->SetKind( SFX_ITEMS_POOLDEFAULT ); 710 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem; 711 } 712 } 713 714 // ggf. Secondary-Pool laden 715 aPoolRec.Skip(); 716 if ( pSecondary ) 717 { 718 if ( !bSecondaryLoaded ) 719 pSecondary->Load( rStream ); 720 else 721 rStream.Seek( nSecondaryEnd ); 722 } 723 724 // wenn nicht own-Pool, dann kein Name 725 if ( aExternName != aName ) 726 aName.Erase(); 727 728 pImp->bStreaming = sal_False; 729 return rStream; 730 }; 731 732 // ----------------------------------------------------------------------- 733 734 SvStream &SfxItemPool::Load1_Impl(SvStream &rStream) 735 { 736 // beim Master ist der Header schon von <Load()> geladen worden 737 if ( !pImp->bStreaming ) 738 { 739 // Header des Secondary lesen 740 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_STARTPOOL_4 ); 741 rStream >> pImp->nMajorVer >> pImp->nMinorVer; 742 } 743 sal_uInt32 nAttribSize(0); 744 int bOwnPool = sal_True; 745 UniString aExternName; 746 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 2 ) 747 rStream >> pImp->nLoadingVersion; 748 SfxPoolItem::readByteString(rStream, aExternName); 749 bOwnPool = aExternName == aName; 750 pImp->bStreaming = sal_True; 751 752 //! solange wir keine fremden laden k"onnen 753 if ( !bOwnPool ) 754 { 755 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR); 756 pImp->bStreaming = sal_False; 757 return rStream; 758 } 759 760 // Versionen bis 1.3 k"onnen noch keine Which-Verschiebungen lesen 761 if ( pImp->nMajorVer == 1 && pImp->nMinorVer <= 2 && 762 pImp->nVersion < pImp->nLoadingVersion ) 763 { 764 rStream.SetError(ERRCODE_IO_WRONGVERSION); 765 pImp->bStreaming = sal_False; 766 return rStream; 767 } 768 769 // Size-Table liegt hinter den eigentlichen Attributen 770 rStream >> nAttribSize; 771 772 // Size-Table einlesen 773 sal_uLong nStartPos = rStream.Tell(); 774 rStream.SeekRel( nAttribSize ); 775 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_SIZES ); 776 sal_uInt32 nSizeTableLen(0); 777 rStream >> nSizeTableLen; 778 sal_Char *pBuf = new sal_Char[nSizeTableLen]; 779 rStream.Read( pBuf, nSizeTableLen ); 780 sal_uLong nEndOfSizes = rStream.Tell(); 781 SvMemoryStream aSizeTable( pBuf, nSizeTableLen, STREAM_READ ); 782 783 // ab Version 1.3 steht in der Size-Table eine Versions-Map 784 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 3 ) 785 { 786 // Version-Map finden (letztes sal_uLong der Size-Table gibt Pos an) 787 rStream.Seek( nEndOfSizes - sizeof(sal_uInt32) ); 788 sal_uInt32 nVersionMapPos(0); 789 rStream >> nVersionMapPos; 790 rStream.Seek( nVersionMapPos ); 791 792 // Versions-Maps einlesen 793 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_VERSIONMAP ); 794 sal_uInt16 nVerCount(0); 795 rStream >> nVerCount; 796 for ( sal_uInt16 nVerNo = 0; nVerNo < nVerCount; ++nVerNo ) 797 { 798 // Header f"ur einzelne Version einlesen 799 sal_uInt16 nVersion(0), nHStart(0), nHEnd(0); 800 rStream >> nVersion >> nHStart >> nHEnd; 801 sal_uInt16 nCount = nHEnd - nHStart + 1; 802 sal_uInt16 nBytes = (nCount)*sizeof(sal_uInt16); 803 804 // Is new version is known? 805 if ( nVerNo >= pImp->aVersions.size() ) 806 { 807 // Add new Version 808 sal_uInt16 *pMap = new sal_uInt16[nCount]; 809 memset(pMap, 0, nCount * sizeof(sal_uInt16)); 810 for ( sal_uInt16 n = 0; n < nCount; ++n ) 811 rStream >> pMap[n]; 812 SetVersionMap( nVersion, nHStart, nHEnd, pMap ); 813 } 814 else 815 // Version schon bekannt => "uberspringen 816 rStream.SeekRel( nBytes ); 817 } 818 } 819 820 // Items laden 821 rStream.Seek( nStartPos ); 822 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ITEMS ); 823 FASTBOOL bSecondaryLoaded = sal_False; 824 long nSecondaryEnd = 0; 825 sal_uInt16 nWhich(0), nSlot(0); 826 while ( rStream >> nWhich, nWhich ) 827 { 828 // ggf. Which-Id aus alter Version verschieben? 829 if ( pImp->nLoadingVersion != pImp->nVersion ) 830 nWhich = GetNewWhich( nWhich ); 831 832 rStream >> nSlot; 833 sal_uInt16 nMappedWhich = GetWhich(nSlot, sal_False); 834 int bKnownItem = bOwnPool || IsWhich(nMappedWhich); 835 836 sal_uInt16 nRef(0), nCount(0), nVersion(0); 837 sal_uInt32 nAttrSize(0); 838 rStream >> nVersion >> nCount; 839 840 SfxPoolItemArray_Impl **ppArr = 0; 841 SfxPoolItemArray_Impl *pNewArr = 0; 842 SfxPoolItem *pDefItem = 0; 843 if ( bKnownItem ) 844 { 845 if ( !bOwnPool ) 846 nWhich = nMappedWhich; 847 848 //!SFX_ASSERTWARNING( !nSlot || !HasMap() || 849 //! ( nSlot == GetSlotId( nWhich, sal_False ) ) || 850 //! !GetSlotId( nWhich, sal_False ), 851 //! nWhich, "Slot/Which mismatch" ); 852 853 sal_uInt16 nIndex = GetIndex_Impl(nWhich); 854 ppArr = pImp->ppPoolItems + nIndex; 855 pNewArr = new SfxPoolItemArray_Impl(); 856 pDefItem = *(ppStaticDefaults + nIndex); 857 } 858 859 // Position vor ersten Item merken 860 sal_uLong nLastPos = rStream.Tell(); 861 862 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten 863 if ( !bSecondaryLoaded && pSecondary && pDefItem->ISA(SfxSetItem) ) 864 { 865 // an das Ende des eigenen Pools seeken 866 rStream.Seek(nEndOfSizes); 867 CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr ); 868 CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr ); 869 870 // Sekund"arpool einlesen 871 pSecondary->Load1_Impl( rStream ); 872 bSecondaryLoaded = sal_True; 873 nSecondaryEnd = rStream.Tell(); 874 875 // zur"uck zu unseren eigenen Items 876 rStream.Seek(nLastPos); 877 } 878 879 // Items an sich lesen 880 for ( sal_uInt16 j = 0; j < nCount; ++j ) 881 { 882 sal_uLong nPos = nLastPos; 883 rStream >> nRef; 884 885 if ( bKnownItem ) 886 { 887 SfxPoolItem *pItem = 0; 888 if ( nRef ) 889 { 890 pItem = pDefItem->Create(rStream, nVersion); 891 892 if ( !bPersistentRefCounts ) 893 // bis <SfxItemPool::LoadCompleted()> festhalten 894 AddRef(*pItem, 1); 895 else 896 { 897 if ( nRef > SFX_ITEMS_OLD_MAXREF ) 898 pItem->SetKind( nRef ); 899 else 900 AddRef(*pItem, nRef); 901 } 902 } 903 //pNewArr->insert( pItem, j ); 904 pNewArr->push_back( (SfxPoolItem*) pItem ); 905 906 // restliche gespeicherte Laenge skippen (neueres Format) 907 nLastPos = rStream.Tell(); 908 } 909 910 aSizeTable >> nAttrSize; 911 SFX_ASSERT( !bKnownItem || ( nPos + nAttrSize) >= nLastPos, 912 nPos, 913 "too many bytes read - version mismatch?" ); 914 915 if ( !bKnownItem || ( nLastPos < (nPos + nAttrSize) ) ) 916 { 917 nLastPos = nPos + nAttrSize; 918 rStream.Seek( nLastPos ); 919 } 920 } 921 922 if ( bKnownItem ) 923 { 924 SfxPoolItemArray_Impl *pOldArr = *ppArr; 925 *ppArr = pNewArr; 926 927 // die Items merken, die schon im Pool sind 928 int bEmpty = sal_True; 929 if ( 0 != pOldArr ) 930 for ( size_t n = 0; bEmpty && n < pOldArr->size(); ++n ) 931 bEmpty = pOldArr->operator[](n) == 0; 932 DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" ); 933 if ( !bEmpty ) 934 { 935 // f"ur alle alten suchen, ob ein gleiches neues existiert 936 for ( size_t nOld = 0; nOld < pOldArr->size(); ++nOld ) 937 { 938 SfxPoolItem *pOldItem = (*pOldArr)[nOld]; 939 if ( pOldItem ) 940 { 941 bool bFound = false; 942 for ( size_t nNew = 0; 943 nNew < (*ppArr)->size(); ++nNew ) 944 { 945 SfxPoolItem *&rpNewItem = 946 (SfxPoolItem*&)(*ppArr)->operator[](nNew); 947 948 if ( rpNewItem && *rpNewItem == *pOldItem ) 949 { 950 AddRef( *pOldItem, rpNewItem->GetRefCount() ); 951 SetRefCount( *rpNewItem, 0 ); 952 delete rpNewItem; 953 rpNewItem = pOldItem; 954 bFound = true; 955 SFX_TRACE( "reusing item", pOldItem ); 956 break; 957 } 958 } 959 if ( !bFound ) 960 { 961 SFX_TRACE( "item not found: ", pOldItem ); 962 } 963 } 964 } 965 } 966 delete pOldArr; /* @@@ */ 967 } 968 } 969 970 // Pool-Defaults lesen 971 if ( pImp->nMajorVer > 1 || pImp->nMinorVer > 0 ) 972 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_DEFAULTS ); 973 974 sal_uLong nLastPos = rStream.Tell(); 975 while ( rStream >> nWhich, nWhich ) 976 { 977 // ggf. Which-Id aus alter Version verschieben? 978 if ( pImp->nLoadingVersion != pImp->nVersion ) 979 nWhich = GetNewWhich( nWhich ); 980 981 rStream >> nSlot; 982 sal_uInt16 nMappedWhich = GetWhich(nSlot, sal_False); 983 int bKnownItem = bOwnPool || IsWhich(nMappedWhich); 984 985 sal_uLong nPos = nLastPos; 986 sal_uInt32 nSize(0); 987 sal_uInt16 nVersion(0); 988 rStream >> nVersion; 989 990 if ( bKnownItem ) 991 { 992 if ( !bOwnPool ) 993 nWhich = nMappedWhich; 994 SfxPoolItem *pItem = 995 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) ) 996 ->Create( rStream, nVersion ); 997 pItem->SetKind( SFX_ITEMS_POOLDEFAULT ); 998 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem; 999 } 1000 1001 nLastPos = rStream.Tell(); 1002 aSizeTable >> nSize; 1003 SFX_ASSERT( ( nPos + nSize) >= nLastPos, nPos, 1004 "too many bytes read - version mismatch?" ); 1005 if ( nLastPos < (nPos + nSize) ) 1006 rStream.Seek( nPos + nSize ); 1007 } 1008 1009 delete[] pBuf; 1010 rStream.Seek(nEndOfSizes); 1011 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL ); 1012 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL ); 1013 1014 if ( pSecondary ) 1015 { 1016 if ( !bSecondaryLoaded ) 1017 pSecondary->Load1_Impl( rStream ); 1018 else 1019 rStream.Seek( nSecondaryEnd ); 1020 } 1021 1022 if ( aExternName != aName ) 1023 aName.Erase(); 1024 1025 pImp->bStreaming = sal_False; 1026 return rStream; 1027 } 1028 1029 // ----------------------------------------------------------------------- 1030 1031 const SfxPoolItem* SfxItemPool::LoadSurrogate 1032 ( 1033 SvStream& rStream, // vor einem Surrogat positionierter Stream 1034 sal_uInt16& rWhich, // Which-Id des zu ladenden <SfxPoolItem>s 1035 sal_uInt16 nSlotId, // Slot-Id des zu ladenden <SfxPoolItem>s 1036 const SfxItemPool* pRefPool // <SfxItemPool> in dem das Surrogat gilt 1037 ) 1038 1039 /* [Beschreibung] 1040 1041 L"adt Surrogat aus 'rStream' und liefert das dadurch in 'rRefPool' 1042 repr"asentierte SfxPoolItem zu"ruck. Ist das im Stream befindliche 1043 Surrogat == SFX_ITEMS_DIRECT (!SFX_ITEM_POOLABLE) wird 0 zur"uckgegeben, 1044 das Item ist direkt aus dem Stream zu laden. Bei 0xfffffff0 (SFX_ITEMS_NULL) 1045 wird auch 0 zurueckgegeben und rWhich auf 0 gesetzt, das Item ist nicht 1046 verfuegbar. 1047 1048 Ansonsten wird ber"ucksichtigt, ob der betroffene Pool ohne Ref-Counts 1049 geladen wird, ob aus einem neuen Pool nachgeladen wird (&rRefPool != this) 1050 oder ob aus einem g"anzlich anders aufgebauten Pool geladen wird. 1051 1052 Wird aus einem anders aufgebauten Pool geladen und die 'nSlotId' kann 1053 nicht in eine Which-Id dieses Pools gemappt werden, wird ebenfalls 0 1054 zur"uckgeliefert. 1055 1056 Preconditions: - Pool mu\s geladen sein 1057 - LoadCompleted darf noch nicht gerufen worden sein 1058 - 'rStream' steht genau an der Position, an der ein 1059 Surrogat f"ur ein Item mit der SlotId 'nSlotId' und 1060 der WhichId 'rWhichId' mit StoreSurrogate gepeichert 1061 wurde 1062 1063 Postconditions: - 'rStream' ist so positioniert, wie auch StoreSurrogate 1064 sein speichern beendet hatte 1065 - konnte ein Item geladen werden, befindet es sich 1066 in diesem SfxItemPool 1067 - 'rWhichId' enth"alt die ggf. gemappte Which-Id 1068 Laufzeit: Tiefe des Ziel Sekund"arpools * 10 + 10 1069 1070 [Querverweise] 1071 1072 <SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const> 1073 */ 1074 1075 { 1076 // Read the first surrogate 1077 sal_uInt32 nSurrogat(0); 1078 rStream >> nSurrogat; 1079 1080 // Is item stored directly? 1081 if ( SFX_ITEMS_DIRECT == nSurrogat ) 1082 return 0; 1083 1084 // Item does not exist? 1085 if ( SFX_ITEMS_NULL == nSurrogat ) 1086 { 1087 rWhich = 0; 1088 return 0; 1089 } 1090 1091 // Bei einem identisch aufgebauten Pool (im Stream) kann das Surrogat 1092 // auf jeden Fall aufgel"ost werden. 1093 if ( !pRefPool ) 1094 pRefPool = this; 1095 FASTBOOL bResolvable = pRefPool->GetName().Len() > 0; 1096 if ( !bResolvable ) 1097 { 1098 // Bei einem anders aufgebauten Pool im Stream, mu\s die SlotId 1099 // aus dem Stream in eine Which-Id gemappt werden k"onnen. 1100 sal_uInt16 nMappedWhich = nSlotId ? GetWhich(nSlotId, sal_True) : 0; 1101 if ( IsWhich(nMappedWhich) ) 1102 { 1103 // gemappte SlotId kann "ubernommen werden 1104 rWhich = nMappedWhich; 1105 bResolvable = sal_True; 1106 } 1107 } 1108 1109 // kann Surrogat aufgel"ost werden? 1110 const SfxPoolItem *pItem = 0; 1111 if ( bResolvable ) 1112 { 1113 for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pSecondary ) 1114 { 1115 // richtigen (Folge-) Pool gefunden? 1116 if ( pTarget->IsInRange(rWhich) ) 1117 { 1118 // dflt-Attribut? 1119 if ( SFX_ITEMS_DEFAULT == nSurrogat ) 1120 return *(pTarget->ppStaticDefaults + 1121 pTarget->GetIndex_Impl(rWhich)); 1122 1123 SfxPoolItemArray_Impl* pItemArr = *(pTarget->pImp->ppPoolItems + 1124 pTarget->GetIndex_Impl(rWhich)); 1125 pItem = pItemArr && nSurrogat < pItemArr->size() 1126 ? (*pItemArr)[nSurrogat] 1127 : 0; 1128 if ( !pItem ) 1129 { 1130 DBG_ERROR( "can't resolve surrogate" ); 1131 rWhich = 0; // nur zur Sicherheit fuer richtige Stream-Pos 1132 return 0; 1133 } 1134 1135 // Nachladen aus Ref-Pool? 1136 if ( pRefPool != pMaster ) 1137 return &pTarget->Put( *pItem ); 1138 1139 // Referenzen sind NICHT schon mit Pool geladen worden? 1140 if ( !pTarget->HasPersistentRefCounts() ) 1141 AddRef( *pItem, 1 ); 1142 else 1143 return pItem; 1144 1145 return pItem; 1146 } 1147 } 1148 1149 SFX_ASSERT( sal_False, rWhich, "can't resolve Which-Id in LoadSurrogate" ); 1150 } 1151 1152 return 0; 1153 } 1154 1155 //------------------------------------------------------------------------- 1156 1157 1158 FASTBOOL SfxItemPool::StoreSurrogate 1159 ( 1160 SvStream& rStream, 1161 const SfxPoolItem* pItem 1162 ) const 1163 1164 /* [Beschreibung] 1165 1166 Speichert ein Surrogat f"ur '*pItem' in 'rStream'. 1167 1168 1169 [R"uckgabewert] 1170 1171 FASTBOOL sal_True 1172 es wurde ein echtes Surrogat gespeichert, auch 1173 SFX_ITEMS_NULL bei 'pItem==0', 1174 SFX_ITEMS_STATICDEFAULT und SFX_ITEMS_POOLDEFAULT 1175 gelten als 'echte' Surrogate 1176 1177 sal_False 1178 es wurde ein Dummy-Surrogat (SFX_ITEMS_DIRECT) 1179 gespeichert, das eigentliche Item mu\s direkt 1180 hinterher selbst gespeichert werden 1181 */ 1182 1183 { 1184 if ( pItem ) 1185 { 1186 FASTBOOL bRealSurrogate = IsItemFlag(*pItem, SFX_ITEM_POOLABLE); 1187 rStream << ( bRealSurrogate 1188 ? GetSurrogate( pItem ) 1189 : SFX_ITEMS_DIRECT ); 1190 return bRealSurrogate; 1191 } 1192 1193 rStream << SFX_ITEMS_NULL; 1194 return sal_True; 1195 } 1196 1197 // ----------------------------------------------------------------------- 1198 1199 sal_uInt32 SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const 1200 { 1201 DBG_CHKTHIS(SfxItemPool, 0); 1202 DBG_ASSERT( pItem, "no 0-Pointer Surrogate" ); 1203 DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" ); 1204 DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" ); 1205 1206 if ( !IsInRange(pItem->Which()) ) 1207 { 1208 if ( pSecondary ) 1209 return pSecondary->GetSurrogate( pItem ); 1210 SFX_ASSERT( 0, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" ); 1211 } 1212 1213 // Pointer auf static- oder pool-dflt-Attribut? 1214 if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) ) 1215 return SFX_ITEMS_DEFAULT; 1216 1217 SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(pItem->Which())); 1218 DBG_ASSERT(pItemArr, "ItemArr is not available"); 1219 1220 for ( size_t i = 0; i < pItemArr->size(); ++i ) 1221 { 1222 const SfxPoolItem *p = (*pItemArr)[i]; 1223 if ( p == pItem ) 1224 return i; 1225 } 1226 SFX_ASSERT( 0, pItem->Which(), "Item not in the pool"); 1227 return SFX_ITEMS_NULL; 1228 } 1229 1230 // ----------------------------------------------------------------------- 1231 1232 FASTBOOL SfxItemPool::IsInStoringRange( sal_uInt16 nWhich ) const 1233 { 1234 return nWhich >= pImp->nStoringStart && 1235 nWhich <= pImp->nStoringEnd; 1236 } 1237 1238 //------------------------------------------------------------------------ 1239 1240 void SfxItemPool::SetStoringRange( sal_uInt16 nFrom, sal_uInt16 nTo ) 1241 1242 /* [Beschreibung] 1243 1244 Mit dieser Methode kann der Which-Bereich eingeengt werden, der 1245 von ItemSets dieses Pool (und dem Pool selbst) gespeichert wird. 1246 Die Methode muss dazu vor <SfxItemPool::Store()> gerufen werden 1247 und die Werte muessen auch noch gesetzt sein, wenn das eigentliche 1248 Dokument (also die ItemSets gespeicher werden). 1249 1250 Ein Zuruecksetzen ist dann nicht noetig, wenn dieser Range vor 1251 JEDEM Speichern richtig gesetzt wird, da er nur beim Speichern 1252 beruecksichtigt wird. 1253 1254 Dieses muss fuer das 3.1-Format gemacht werden, da dort eine 1255 Bug in der Pool-Lade-Methode vorliegt. 1256 */ 1257 1258 { 1259 pImp->nStoringStart = nFrom; 1260 pImp->nStoringEnd = nTo; 1261 } 1262 1263 // ----------------------------------------------------------------------- 1264 1265 void SfxItemPool::SetVersionMap 1266 ( 1267 sal_uInt16 nVer, /* neue Versionsnummer */ 1268 sal_uInt16 nOldStart, /* alte erste Which-Id */ 1269 sal_uInt16 nOldEnd, /* alte letzte Which-Id */ 1270 sal_uInt16* pOldWhichIdTab /* Array mit genau dem Aufbau der Which-Ids 1271 der vorhergehenden Version, in denen 1272 die jeweils neue Which-Id steht. */ 1273 ) 1274 1275 /* [Beschreibung] 1276 1277 Mit dieser Methode k"onnen neue, inkompatible Which-Id-Folgen oder 1278 Verteilungen realisiert werden. Pools, die noch mit alten Versionen 1279 gespeichert wurden, werden dann "uber die angegebene Tabelle solange 1280 gemappt, bis die aktuelle Version erreicht ist. Neuere Pools k"onnen 1281 unter Verlust neuer Attribute geladen werden, da die Map mit dem Pool 1282 gespeichert wird. 1283 1284 Precondition: Pool darf noch nicht geladen sein 1285 Postcondition: Which-Ids aus fr"uheren Versionen k"onnen bei Laden auf 1286 Version 'nVer' gemappt werden 1287 Laufzeit: 1.5 * new + 10 1288 1289 [Anmerkung] 1290 1291 F"ur neue Which-Ranges (nStart,nEnd) m"ssen im Vergleich zur Vorg"anger- 1292 Version (nOldStart,nOldEnd) immer gelten, da\s (nOldStart,nOldEnd) 1293 vollst"andig in (nStart,nEnd) enthalten ist. Es ist also zul"assig, den 1294 Which-Range in beide Richtungen zu erweitern, auch durch Einf"ugung 1295 von Which-Ids, nicht aber ihn zu beschneiden. 1296 1297 Diese Methode sollte nur im oder direkt nach Aufruf des Konstruktors 1298 gerufen werden. 1299 1300 Das Array mu\s statisch sein, da es nicht kopiert wird und au\serdem 1301 im Copy-Ctor des SfxItemPool wiederverwendet wird. 1302 1303 1304 [Beispiel] 1305 1306 Urspr"unglich (Version 0) hatte der Pool folgende Which-Ids: 1307 1308 1:A, 2:B, 3:C, 4:D 1309 1310 Nun soll eine neue Version (Version 1) zwei zus"atzliche Ids X und Y 1311 zwischen B und C erhalten, also wie folgt aussehen: 1312 1313 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D 1314 1315 Dabei haben sich also die Ids 3 und 4 ge"andert. F"ur die neue Version 1316 m"u\ste am Pool folgendes gesetzt werden: 1317 1318 static sal_uInt16 nVersion1Map = { 1, 2, 5, 6 }; 1319 pPool->SetVersionMap( 1, 1, 4, &nVersion1Map ); 1320 1321 1322 [Querverweise] 1323 1324 <SfxItemPool::IsLoadingVersionCurrent()const> 1325 <SfxItemPool::GetNewWhich(sal_uInt16)> 1326 <SfxItemPool::GetVersion()const> 1327 <SfxItemPool::GetLoadingVersion()const> 1328 */ 1329 1330 { 1331 // create new map entry to insert 1332 const SfxPoolVersion_ImplPtr pVerMap = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl( 1333 nVer, nOldStart, nOldEnd, pOldWhichIdTab ) ); 1334 pImp->aVersions.push_back( pVerMap ); 1335 1336 DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" ); 1337 pImp->nVersion = nVer; 1338 1339 // Versions-Range anpassen 1340 for ( sal_uInt16 n = 0; n < nOldEnd-nOldStart+1; ++n ) 1341 { 1342 sal_uInt16 nWhich = pOldWhichIdTab[n]; 1343 if ( nWhich < pImp->nVerStart ) 1344 { 1345 if ( !nWhich ) 1346 nWhich = 0; 1347 pImp->nVerStart = nWhich; 1348 } 1349 else if ( nWhich > pImp->nVerEnd ) 1350 pImp->nVerEnd = nWhich; 1351 } 1352 } 1353 1354 // ----------------------------------------------------------------------- 1355 1356 sal_uInt16 SfxItemPool::GetNewWhich 1357 ( 1358 sal_uInt16 nFileWhich // die aus dem Stream geladene Which-Id 1359 ) const 1360 1361 /* [Beschreibung] 1362 1363 Diese Methoden rechnet Which-Ids aus einem File-Format in die der 1364 aktuellen Pool-Version um. Ist das File-Format "alter, werden die vom 1365 Pool-Entwickler mit SetVersion() gesetzten Tabellen verwendet, 1366 ist das File-Format neuer, dann die aus dem File geladenen Tabellen. 1367 Im letzteren Fall kann ggf. nicht jede Which-Id gemappt werden, 1368 so da\s 0 zur"uckgeliefert wird. 1369 1370 Die Berechnung ist nur f"ur Which-Ids definiert, die in der betreffenden 1371 File-Version unterst"utzt wurden. Dies ist per Assertion abgesichert. 1372 1373 Precondition: Pool mu\s geladen sein 1374 Postcondition: unver"andert 1375 Laufzeit: linear(Anzahl der Sekund"arpools) + 1376 linear(Differenz zwischen alter und neuer Version) 1377 1378 1379 [Querverweise] 1380 1381 <SfxItemPool::IsLoadingVersionCurrent()const> 1382 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1383 <SfxItemPool::GetVersion()const> 1384 <SfxItemPool::GetLoadingVersion()const> 1385 */ 1386 1387 { 1388 // (Sekund"ar-) Pool bestimmen 1389 if ( !IsInVersionsRange(nFileWhich) ) 1390 { 1391 if ( pSecondary ) 1392 return pSecondary->GetNewWhich( nFileWhich ); 1393 SFX_ASSERT( 0, nFileWhich, "unknown which in GetNewWhich()" ); 1394 } 1395 1396 // Version neuer/gleich/"alter? 1397 short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion; 1398 1399 // Which-Id einer neueren Version? 1400 if ( nDiff > 0 ) 1401 { 1402 // von der Top-Version bis runter zur File-Version stufenweise mappen 1403 for ( size_t nMap = pImp->aVersions.size(); nMap > 0; --nMap ) 1404 { 1405 SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap-1]; 1406 if ( pVerInfo->_nVer > pImp->nVersion ) 1407 { sal_uInt16 nOfs; 1408 sal_uInt16 nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1; 1409 for ( nOfs = 0; 1410 nOfs <= nCount && 1411 pVerInfo->_pMap[nOfs] != nFileWhich; 1412 ++nOfs ) 1413 continue; 1414 1415 if ( pVerInfo->_pMap[nOfs] == nFileWhich ) 1416 nFileWhich = pVerInfo->_nStart + nOfs; 1417 else 1418 return 0; 1419 } 1420 else 1421 break; 1422 } 1423 } 1424 1425 // Which-Id einer neueren Version? 1426 else if ( nDiff < 0 ) 1427 { 1428 // von der File-Version bis zur aktuellen Version stufenweise mappen 1429 for ( size_t nMap = 0; nMap < pImp->aVersions.size(); ++nMap ) 1430 { 1431 SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap]; 1432 if ( pVerInfo->_nVer > pImp->nLoadingVersion ) 1433 { 1434 DBG_ASSERT( nFileWhich >= pVerInfo->_nStart && 1435 nFileWhich <= pVerInfo->_nEnd, 1436 "which-id unknown in version" ); 1437 nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart]; 1438 } 1439 } 1440 } 1441 1442 // originale (nDiff==0) bzw. gemappte (nDiff!=0) Id zur"uckliefern 1443 return nFileWhich; 1444 } 1445 1446 // ----------------------------------------------------------------------- 1447 1448 1449 FASTBOOL SfxItemPool::IsInVersionsRange( sal_uInt16 nWhich ) const 1450 { 1451 return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd; 1452 } 1453 1454 // ----------------------------------------------------------------------- 1455 1456 FASTBOOL SfxItemPool::IsCurrentVersionLoading() const 1457 1458 /* [Beschreibung] 1459 1460 Mit dieser Methode kann festgestellt werden, ob die geladene Pool-Version 1461 dem aktuellen Pool-Aufbau entspricht. 1462 1463 Precondition: Pool mu\s geladen sein 1464 Postcondition: unver"andert 1465 Laufzeit: linear(Anzahl der Sekund"arpools) 1466 1467 1468 [Querverweise] 1469 1470 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1471 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1472 <SfxItemPool::GetVersion()const> 1473 <SfxItemPool::GetLoadingVersion()const> 1474 */ 1475 1476 { 1477 return ( pImp->nVersion == pImp->nLoadingVersion ) && 1478 ( !pSecondary || pSecondary->IsCurrentVersionLoading() ); 1479 } 1480 1481 // ----------------------------------------------------------------------- 1482 1483 sal_uInt16 SfxItemPool::GetVersion() const 1484 1485 /* [Beschreibung] 1486 1487 Diese Methode liefert die aktuelle Versionsnummer des SfxItemPool-Aufbaus 1488 (also des Which-Bereichs). 1489 1490 Precondition: keine 1491 Postcondition: unver"andert 1492 Laufzeit: 2 1493 1494 1495 [Anmerkung] 1496 1497 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools 1498 ber"ucksichtigt werden. 1499 1500 1501 [Querverweise] 1502 1503 <SfxItemPool::IsLoadingVersionCurrent()const> 1504 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1505 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1506 <SfxItemPool::GetLoadingVersion()const> 1507 */ 1508 1509 { 1510 return pImp->nVersion; 1511 } 1512 1513 // ----------------------------------------------------------------------- 1514 1515 sal_uInt16 SfxItemPool::GetLoadingVersion() const 1516 1517 /* [Beschreibung] 1518 1519 Diese Methode liefert die Versionsnummer des SfxItemPool-Aufbaus 1520 (also des Which-Bereichs), die bei Laden vorgefunden wurde. 1521 1522 Precondition: Pool mu\s geladen sein 1523 Postcondition: unver"andert 1524 Laufzeit: 2 1525 1526 1527 [Anmerkung] 1528 1529 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools 1530 ber"ucksichtigt werden. 1531 1532 1533 [Querverweise] 1534 1535 <SfxItemPool::IsLoadingVersionCurrent()const> 1536 <SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)> 1537 <SfxItemPool::GetNewWhich(sal_uInt16)const> 1538 <SfxItemPool::GetVersion()const> 1539 */ 1540 1541 { 1542 return pImp->nLoadingVersion; 1543 } 1544 1545 //------------------------------------------------------------------------- 1546 1547 FASTBOOL SfxItemPool::IsVer2_Impl() const 1548 { 1549 return pMaster->pImp->nMajorVer >= 2; 1550 } 1551 1552 //------------------------------------------------------------------------- 1553 1554 1555 FASTBOOL SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem, 1556 FASTBOOL bDirect ) const 1557 1558 /* [Beschreibung] 1559 1560 Speichert das <SfxPoolItem> 'rItem' in den <SvStream> 'rStream' 1561 entweder als Surrogat ('bDirect == sal_False') oder direkt mit 'rItem.Store()'. 1562 Nicht poolable Items werden immer direkt gespeichert. Items ohne Which-Id, 1563 also SID-Items, werden nicht gespeichert, ebenso wenn Items, die in der 1564 File-Format-Version noch nicht vorhanden waren (return sal_False). 1565 1566 Das Item wird im Stream wie folgt abgelegt: 1567 1568 sal_uInt16 rItem.Which() 1569 sal_uInt16 GetSlotId( rItem.Which() ) bzw. 0 falls nicht verf"urbar 1570 sal_uInt16 GetSurrogate( &rItem ) bzw. SFX_ITEM_DIRECT bei '!SFX_ITEM_POOLBLE' 1571 1572 optional (falls 'bDirect == sal_True' oder '!rItem.IsPoolable()': 1573 1574 sal_uInt16 rItem.GetVersion() 1575 sal_uLong Size 1576 Size rItem.Store() 1577 1578 1579 [Querverweise] 1580 1581 <SfxItemPool::LoadItem(SvStream&,FASTBOOL)const> 1582 */ 1583 1584 { 1585 DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" ); 1586 1587 if ( IsSlot( rItem.Which() ) ) 1588 return sal_False; 1589 const SfxItemPool *pPool = this; 1590 while ( !pPool->IsInStoringRange(rItem.Which()) ) 1591 if ( 0 == ( pPool = pPool->pSecondary ) ) 1592 return sal_False; 1593 1594 DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem), 1595 "SetItem contains ItemSet with SetItem" ); 1596 1597 sal_uInt16 nSlotId = pPool->GetSlotId( rItem.Which(), sal_True ); 1598 sal_uInt16 nItemVersion = rItem.GetVersion(_nFileFormatVersion); 1599 if ( USHRT_MAX == nItemVersion ) 1600 return sal_False; 1601 1602 rStream << rItem.Which() << nSlotId; 1603 if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) ) 1604 { 1605 rStream << nItemVersion; 1606 rStream << (sal_uInt32) 0L; // Platz fuer Laenge in Bytes 1607 sal_uLong nIStart = rStream.Tell(); 1608 rItem.Store(rStream, nItemVersion); 1609 sal_uLong nIEnd = rStream.Tell(); 1610 rStream.Seek( nIStart-4 ); 1611 rStream << (sal_Int32) ( nIEnd-nIStart ); 1612 rStream.Seek( nIEnd ); 1613 } 1614 1615 return sal_True; 1616 } 1617 1618 //------------------------------------------------------------------------- 1619 1620 1621 const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, FASTBOOL bDirect, 1622 const SfxItemPool *pRefPool ) 1623 1624 // pRefPool==-1 => nicht putten! 1625 1626 { 1627 sal_uInt16 nWhich(0), nSlot(0); // nSurrogate; 1628 rStream >> nWhich >> nSlot; 1629 1630 sal_Bool bDontPut = (SfxItemPool*)-1 == pRefPool; 1631 if ( bDontPut || !pRefPool ) 1632 pRefPool = this; 1633 1634 // richtigen Sekund"ar-Pool finden 1635 while ( !pRefPool->IsInVersionsRange(nWhich) ) 1636 { 1637 if ( pRefPool->pSecondary ) 1638 pRefPool = pRefPool->pSecondary; 1639 else 1640 { 1641 // WID in der Version nicht vorhanden => ueberspringen 1642 sal_uInt32 nSurro(0); 1643 sal_uInt16 nVersion(0), nLen(0); 1644 rStream >> nSurro; 1645 if ( SFX_ITEMS_DIRECT == nSurro ) 1646 { 1647 rStream >> nVersion >> nLen; 1648 rStream.SeekRel( nLen ); 1649 } 1650 return 0; 1651 } 1652 } 1653 1654 // wird eine andere Version geladen? 1655 FASTBOOL bCurVersion = pRefPool->IsCurrentVersionLoading(); 1656 if ( !bCurVersion ) 1657 // Which-Id auf neue Version mappen 1658 nWhich = pRefPool->GetNewWhich( nWhich ); 1659 1660 DBG_ASSERT( !nWhich || !pImp->bInSetItem || 1661 !pRefPool->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem), 1662 "loading SetItem in ItemSet of SetItem" ); 1663 1664 // soll "uber Surrogat geladen werden? 1665 const SfxPoolItem *pItem = 0; 1666 if ( !bDirect ) 1667 { 1668 // Which-Id in dieser Version bekannt? 1669 if ( nWhich ) 1670 // Surrogat laden, reagieren falls keins vorhanden 1671 pItem = LoadSurrogate( rStream, nWhich, nSlot, pRefPool ); 1672 else 1673 // sonst "uberspringen 1674 rStream.SeekRel( sizeof(sal_uInt16) ); 1675 } 1676 1677 // wird direkt, also nicht "uber Surrogat geladen? 1678 if ( bDirect || ( nWhich && !pItem ) ) 1679 { 1680 // bDirekt bzw. nicht IsPoolable() => Item direkt laden 1681 sal_uInt16 nVersion(0); 1682 sal_uInt32 nLen(0); 1683 rStream >> nVersion >> nLen; 1684 sal_uLong nIStart = rStream.Tell(); 1685 1686 // Which-Id in dieser Version bekannt? 1687 if ( nWhich ) 1688 { 1689 // Item direkt laden 1690 SfxPoolItem *pNewItem = 1691 pRefPool->GetDefaultItem(nWhich).Create(rStream, nVersion); 1692 if ( bDontPut ) 1693 pItem = pNewItem; 1694 else 1695 if ( pNewItem ) 1696 { 1697 pItem = &Put(*pNewItem); 1698 delete pNewItem; 1699 } 1700 else 1701 pItem = 0; 1702 sal_uLong nIEnd = rStream.Tell(); 1703 DBG_ASSERT( nIEnd <= (nIStart+nLen), "read past end of item" ); 1704 if ( (nIStart+nLen) != nIEnd ) 1705 rStream.Seek( nIStart+nLen ); 1706 } 1707 else 1708 // Item "uberspringen 1709 rStream.Seek( nIStart+nLen ); 1710 } 1711 1712 return pItem; 1713 } 1714 1715 1716