xref: /AOO41X/main/svl/source/items/poolio.cxx (revision 40df464ee80f942fd2baf5effc726656f4be12a0)
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