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