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
SetStoringPool(const SfxItemPool * pStoringPool)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
GetStoringPool()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
Store(SvStream & rStream) const85 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
LoadCompleted()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:
readTheItems(SvStream & rStream,sal_uInt32 nItemCount,sal_uInt16 nVersion,SfxPoolItem * pDefItem,SfxPoolItemArray_Impl ** ppArr)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
Load(SvStream & rStream)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
Load1_Impl(SvStream & rStream)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
LoadSurrogate(SvStream & rStream,sal_uInt16 & rWhich,sal_uInt16 nSlotId,const SfxItemPool * pRefPool)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
StoreSurrogate(SvStream & rStream,const SfxPoolItem * pItem) const1154 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
GetSurrogate(const SfxPoolItem * pItem) const1195 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
IsInStoringRange(sal_uInt16 nWhich) const1228 FASTBOOL SfxItemPool::IsInStoringRange( sal_uInt16 nWhich ) const
1229 {
1230 return nWhich >= pImp->nStoringStart &&
1231 nWhich <= pImp->nStoringEnd;
1232 }
1233
1234 //------------------------------------------------------------------------
1235
SetStoringRange(sal_uInt16 nFrom,sal_uInt16 nTo)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
SetVersionMap(sal_uInt16 nVer,sal_uInt16 nOldStart,sal_uInt16 nOldEnd,sal_uInt16 * pOldWhichIdTab)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
GetNewWhich(sal_uInt16 nFileWhich) const1352 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
IsInVersionsRange(sal_uInt16 nWhich) const1445 FASTBOOL SfxItemPool::IsInVersionsRange( sal_uInt16 nWhich ) const
1446 {
1447 return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd;
1448 }
1449
1450 // -----------------------------------------------------------------------
1451
IsCurrentVersionLoading() const1452 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
GetVersion() const1479 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
GetLoadingVersion() const1511 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
IsVer2_Impl() const1543 FASTBOOL SfxItemPool::IsVer2_Impl() const
1544 {
1545 return pMaster->pImp->nMajorVer >= 2;
1546 }
1547
1548 //-------------------------------------------------------------------------
1549
1550
StoreItem(SvStream & rStream,const SfxPoolItem & rItem,FASTBOOL bDirect) const1551 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
LoadItem(SvStream & rStream,FASTBOOL bDirect,const SfxItemPool * pRefPool)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