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