merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / items1 / poolio.cxx
blob636319a81e566722d605b587465fa8f24984ddab
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: poolio.cxx,v $
10 * $Revision: 1.11 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
34 #include <string.h>
35 #include <stdio.h>
37 #ifndef GCC
38 #endif
40 #include <tools/solar.h>
41 #include <svtools/itempool.hxx>
42 #include "whassert.hxx"
43 #include <svtools/brdcst.hxx>
44 #include <svtools/filerec.hxx>
45 #include <svtools/svtdata.hxx>
46 #include "poolio.hxx"
48 // STATIC DATA -----------------------------------------------------------
50 DBG_NAME(SfxItemPool);
52 //========================================================================
54 void SfxItemPool::SetStoringPool( const SfxItemPool *pStoringPool )
56 /* [Beschreibung]
58 Diese Methode setzt den <SfxItemPool>, der gerade gespeichert wird.
59 Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format-
60 Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines
61 <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen
62 Pool mit <SfxItemPool::GetStoringPool()> zu besorgen.
64 Sie wird von <SfxItemPool::Store()> bedient, kann jedoch f"ur nicht
65 poolable Items auch direkt gerufen werden. Bitte m"oglichst nicht
66 f"ur jedes Item einzeln, da 2 Calls!
70 ImpSvtData::GetSvtData().pStoringPool = pStoringPool;
73 //-------------------------------------------------------------------------
75 const SfxItemPool* SfxItemPool::GetStoringPool()
77 /* [Beschreibung]
79 Diese Methode liefert den <SfxItemPool>, der gerade gespeichert wird.
80 Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format-
81 Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines
82 <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen
83 Pool zu besorgen.
87 return ImpSvtData::GetSvtData().pStoringPool;
90 //-------------------------------------------------------------------------
92 SvStream &SfxItemPool::Store(SvStream &rStream) const
94 /* [Beschreibung]
96 Der SfxItemPool wird inklusive aller seiner Sekund"arpools mit
97 Pool-Defaults und gepoolten Items in dem angegebenen Stream gespeichert.
98 Die statischen Defaults werden nicht gespeichert.
101 [Fileformat]
103 ;zun"achst ein Kompatiblit"ats-Header-Block
104 Start: 0x1111 SFX_ITEMPOOL_TAG_STARTPOOLS(_4/_5)
105 BYTE MAJOR_VER ;SfxItemPool-Version
106 BYTE MINOR_VER ;"
107 0xFFFF SFX_ITEMPOOL_TAG_TRICK4OLD ;ex. GetVersion()
108 USHORT 0x0000 ;Pseudo-StyleSheetPool
109 USHORT 0x0000 ;Pseudo-StyleSheetPool
111 ;den ganzen Pool in einen Record
112 record SfxMiniRecod(SFX_ITEMPOOL_REC)
114 ;je ein Header vorweg
115 Header: record SfxMiniRecord(SFX_ITEMPOOL_REC_HEADER)
116 USHORT GetVersion() ;Which-Ranges etc.
117 String GetName() ;Pool-Name
119 ;die Versions-Map, um WhichIds neuer File-Versionen mappen zu k"onnen
120 Versions: record SfxMultiRecord(SFX_ITEMPOOL_REC_VERSIONS, 0)
121 USHORT OldVersion
122 USHORT OldStartWhich
123 USHORT OldEndWhich
124 USHORT[] NewWhich (OldEndWhich-OldStartWhich+1)
126 ;jetzt die gepoolten Items (zuerst nicht-SfxSetItems)
127 Items: record SfxMultiRecord(SFX_ITEMPOOL_REC_WHICHIDS, 0)
128 content SlotId, 0
129 USHORT WhichId
130 USHORT pItem->GetVersion()
131 USHORT Array-Size
132 record SfxMultiRecord(SFX_, 0)
133 content Surrogate
134 USHORT RefCount
135 unknown pItem->Store()
137 ;jetzt die gesetzten Pool-Defaults
138 Defaults: record SfxMultiRecord(SFX_ITEMPOOL_REC_DEFAULTS, 0)
139 content SlotId, 0
140 USHORT WhichId
141 USHORT pPoolDef->GetVersion()
142 unknown pPoolDef->Store();
144 ;dahinter folgt ggf. der Secondary ohne Kompatiblit"ats-Header-Block
148 DBG_CHKTHIS(SfxItemPool, 0);
150 // Store-Master finden
151 SfxItemPool *pStoreMaster = pMaster != this ? pMaster : 0;
152 while ( pStoreMaster && !pStoreMaster->pImp->bStreaming )
153 pStoreMaster = pStoreMaster->pSecondary;
155 // Alter-Header (Version des Pools an sich und Inhalts-Version 0xffff)
156 pImp->bStreaming = TRUE;
157 if ( !pStoreMaster )
159 rStream << ( rStream.GetVersion() >= SOFFICE_FILEFORMAT_50
160 ? SFX_ITEMPOOL_TAG_STARTPOOL_5
161 : SFX_ITEMPOOL_TAG_STARTPOOL_4 );
162 rStream << SFX_ITEMPOOL_VER_MAJOR << SFX_ITEMPOOL_VER_MINOR;
163 rStream << SFX_ITEMPOOL_TAG_TRICK4OLD;
165 // SfxStyleSheet-Bug umgehen
166 rStream << UINT16(0); // Version
167 rStream << UINT16(0); // Count (2. Schleife f"allt sonst auf die Fresse)
170 // jeder Pool ist als ganzes ein Record
171 SfxMiniRecordWriter aPoolRec( &rStream, SFX_ITEMPOOL_REC );
172 ImpSvtData::GetSvtData().pStoringPool = this;
174 // Einzel-Header (Version des Inhalts und Name)
176 SfxMiniRecordWriter aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER);
177 rStream << pImp->nVersion;
178 SfxPoolItem::writeByteString(rStream, aName);
181 // Version-Maps
183 SfxMultiVarRecordWriter aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP, 0 );
184 for ( USHORT nVerNo = 0; nVerNo < pImp->aVersions.Count(); ++nVerNo )
186 aVerRec.NewContent();
187 SfxPoolVersion_Impl *pVer = pImp->aVersions[nVerNo];
188 rStream << pVer->_nVer << pVer->_nStart << pVer->_nEnd;
189 USHORT nCount = pVer->_nEnd - pVer->_nStart + 1;
190 USHORT nNewWhich = 0;
191 for ( USHORT n = 0; n < nCount; ++n )
193 nNewWhich = pVer->_pMap[n];
194 rStream << nNewWhich;
197 // Workaround gegen Bug in SetVersionMap der 312
198 if ( SOFFICE_FILEFORMAT_31 == _nFileFormatVersion )
199 rStream << USHORT(nNewWhich+1);
203 // gepoolte Items
205 SfxMultiMixRecordWriter aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS, 0 );
207 // erst Atomaren-Items und dann die Sets schreiben (wichtig beim Laden)
208 for ( pImp->bInSetItem = FALSE; pImp->bInSetItem <= TRUE && !rStream.GetError(); ++pImp->bInSetItem )
210 SfxPoolItemArray_Impl **pArr = pImp->ppPoolItems;
211 SfxPoolItem **ppDefItem = ppStaticDefaults;
212 const USHORT nSize = GetSize_Impl();
213 for ( USHORT i = 0; i < nSize && !rStream.GetError(); ++i, ++pArr, ++ppDefItem )
215 // Version des Items feststellen
216 USHORT nItemVersion = (*ppDefItem)->GetVersion( _nFileFormatVersion );
217 if ( USHRT_MAX == nItemVersion )
218 // => kam in zu exportierender Version gar nicht vor
219 continue;
221 // !poolable wird gar nicht im Pool gespeichert
222 // und itemsets/plain-items je nach Runde
223 #ifdef TF_POOLABLE
224 if ( *pArr && IsItemFlag(**ppDefItem, SFX_ITEM_POOLABLE) &&
225 #else
226 if ( *pArr && (*ppDefItem)->IsPoolable() &&
227 #endif
228 pImp->bInSetItem == (*ppDefItem)->ISA(SfxSetItem) )
230 // eigene Kennung, globale Which-Id und Item-Version
231 USHORT nSlotId = GetSlotId( (*ppDefItem)->Which(), FALSE );
232 aWhichIdsRec.NewContent(nSlotId, 0);
233 rStream << (*ppDefItem)->Which();
234 rStream << nItemVersion;
235 const USHORT nCount = (*pArr)->Count();
236 DBG_ASSERT(nCount, "ItemArr ist leer");
237 rStream << nCount;
239 // Items an sich schreiben
240 SfxMultiMixRecordWriter aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS, 0 );
241 for ( USHORT j = 0; j < nCount; ++j )
243 // Item selbst besorgen
244 const SfxPoolItem *pItem = (*pArr)->GetObject(j);
245 if ( pItem && pItem->GetRefCount() ) //! siehe anderes MI-REF
247 aItemsRec.NewContent(j, 'X' );
249 if ( pItem->GetRefCount() == SFX_ITEMS_SPECIAL )
250 rStream << (USHORT) pItem->GetKind();
251 else
253 rStream << (USHORT) pItem->GetRefCount();
254 if( pItem->GetRefCount() > SFX_ITEMS_OLD_MAXREF )
255 rStream.SetError( ERRCODE_IO_NOTSTORABLEINBINARYFORMAT );
258 if ( !rStream.GetError() )
259 pItem->Store(rStream, nItemVersion);
260 else
261 break;
262 #ifdef DBG_UTIL_MI
263 if ( !pItem->ISA(SfxSetItem) )
265 ULONG nMark = rStream.Tell();
266 rStream.Seek( nItemStartPos + sizeof(USHORT) );
267 SfxPoolItem *pClone = pItem->Create(rStream, nItemVersion );
268 USHORT nWh = pItem->Which();
269 SFX_ASSERT( rStream.Tell() == nMark, nWh,"asymmetric store/create" );
270 SFX_ASSERT( *pClone == *pItem, nWh, "unequal after store/create" );
271 delete pClone;
273 #endif
280 pImp->bInSetItem = FALSE;
283 // die gesetzten Defaults speichern (Pool-Defaults)
284 if ( !rStream.GetError() )
286 SfxMultiMixRecordWriter aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS, 0 );
287 USHORT nCount = GetSize_Impl();
288 for ( USHORT n = 0; n < nCount; ++n )
290 const SfxPoolItem* pDefaultItem = ppPoolDefaults[n];
291 if ( pDefaultItem )
293 // Version ermitteln
294 USHORT nItemVersion = pDefaultItem->GetVersion( _nFileFormatVersion );
295 if ( USHRT_MAX == nItemVersion )
296 // => gab es in der Version noch nicht
297 continue;
299 // eigene Kennung, globale Kennung, Version
300 USHORT nSlotId = GetSlotId( pDefaultItem->Which(), FALSE );
301 aDefsRec.NewContent( nSlotId, 0 );
302 rStream << pDefaultItem->Which();
303 rStream << nItemVersion;
305 // Item an sich
306 pDefaultItem->Store( rStream, nItemVersion );
311 // weitere Pools rausschreiben
312 ImpSvtData::GetSvtData().pStoringPool = 0;
313 aPoolRec.Close();
314 if ( !rStream.GetError() && pSecondary )
315 pSecondary->Store( rStream );
317 pImp->bStreaming = FALSE;
318 return rStream;
321 // -----------------------------------------------------------------------
323 void SfxItemPool::LoadCompleted()
325 /* [Beschreibung]
327 Wurde der SfxItemPool mit 'bRefCounts' == FALSE geladen, mu\s das
328 Laden der Dokumentinhalte mit einem Aufruf dieser Methode beendet
329 werden. Ansonsten hat der Aufruf dieser Methode keine Funktion.
332 [Anmerkung]
334 Beim Laden ohne Ref-Counts werden diese tats"achlich auf 1 gesetzt,
335 damit nicht w"ahrend des Ladevorgangs SfxPoolItems gel"oscht werden,
336 die danach, aber auch noch beim Ladevorgang, ben"otigt werden. Diese
337 Methode setzt den Ref-Count wieder zur"uck und entfernt dabei
338 gleichzeitig alle nicht mehr ben"otigten Items.
341 [Querverweise]
343 <SfxItemPool::Load()>
347 // wurden keine Ref-Counts mitgeladen?
348 if ( pImp->nInitRefCount > 1 )
351 // "uber alle Which-Werte iterieren
352 SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
353 for( USHORT nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr )
355 // ist "uberhaupt ein Item mit dem Which-Wert da?
356 if ( *ppItemArr )
358 // "uber alle Items mit dieser Which-Id iterieren
359 SfxPoolItem** ppHtArr = (SfxPoolItem**)(*ppItemArr)->GetData();
360 for( USHORT n = (*ppItemArr)->Count(); n; --n, ++ppHtArr )
361 if (*ppHtArr)
363 #ifdef DBG_UTIL
364 const SfxPoolItem &rItem = **ppHtArr;
365 DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
366 0 != &((const SfxSetItem&)rItem).GetItemSet(),
367 "SetItem without ItemSet" );
368 #endif
370 if ( !ReleaseRef( **ppHtArr, 1 ) )
371 DELETEZ( *ppHtArr );
376 // from now on normal initial ref count
377 pImp->nInitRefCount = 1;
380 // notify secondary pool
381 if ( pSecondary )
382 pSecondary->LoadCompleted();
385 //============================================================================
386 // This had to be moved to a method of its own to keep Solaris GCC happy:
387 void SfxItemPool::readTheItems (
388 SvStream & rStream, USHORT nItemCount, USHORT nVersion,
389 SfxPoolItem * pDefItem, SfxPoolItemArray_Impl ** ppArr)
391 SfxMultiRecordReader aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS );
393 SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl( nItemCount );
394 SfxPoolItem *pItem = 0;
396 USHORT n, nLastSurrogate = USHORT(-1);
397 while (aItemsRec.GetContent())
399 // n"achstes Surrogat holen
400 USHORT nSurrogate = aItemsRec.GetContentTag();
401 DBG_ASSERT( aItemsRec.GetContentVersion() == 'X',
402 "not an item content" );
404 // fehlende auff"ullen
405 for ( pItem = 0, n = nLastSurrogate+1; n < nSurrogate; ++n )
406 pNewArr->C40_INSERT(SfxPoolItem, pItem, n);
407 nLastSurrogate = nSurrogate;
409 // Ref-Count und Item laden
410 USHORT nRef;
411 rStream >> nRef;
413 pItem = pDefItem->Create(rStream, nVersion);
414 pNewArr->C40_INSERT(SfxPoolItem, pItem, nSurrogate);
416 if ( !bPersistentRefCounts )
417 // bis <SfxItemPool::LoadCompleted()> festhalten
418 AddRef(*pItem, 1);
419 else
421 if ( nRef > SFX_ITEMS_OLD_MAXREF )
422 pItem->SetKind( nRef );
423 else
424 AddRef(*pItem, nRef);
428 // fehlende auff"ullen
429 for ( pItem = 0, n = nLastSurrogate+1; n < nItemCount; ++n )
430 pNewArr->C40_INSERT(SfxPoolItem, pItem, n);
432 SfxPoolItemArray_Impl *pOldArr = *ppArr;
433 *ppArr = pNewArr;
435 // die Items merken, die schon im Pool sind
436 int bEmpty = TRUE;
437 if ( 0 != pOldArr )
438 for ( n = 0; bEmpty && n < pOldArr->Count(); ++n )
439 bEmpty = pOldArr->GetObject(n) == 0;
440 DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
441 if ( !bEmpty )
443 // f"ur alle alten suchen, ob ein gleiches neues existiert
444 for ( USHORT nOld = 0; nOld < pOldArr->Count(); ++nOld )
446 SfxPoolItem *pOldItem = (*pOldArr)[nOld];
447 if ( pOldItem )
449 USHORT nFree = USHRT_MAX;
450 int bFound = FALSE;
451 USHORT nCount = (*ppArr)->Count();
452 for ( USHORT nNew = nCount; !bFound && nNew--; )
454 // geladenes Item
455 SfxPoolItem *&rpNewItem =
456 (SfxPoolItem*&)(*ppArr)->GetData()[nNew];
458 // surrogat unbenutzt?
459 if ( !rpNewItem )
460 nFree = nNew;
462 // gefunden?
463 else if ( *rpNewItem == *pOldItem )
465 // wiederverwenden
466 AddRef( *pOldItem, rpNewItem->GetRefCount() );
467 SetRefCount( *rpNewItem, 0 );
468 delete rpNewItem;
469 rpNewItem = pOldItem;
470 bFound = TRUE;
474 // vorhervorhandene, nicht geladene uebernehmen
475 if ( !bFound )
477 if ( nFree != USHRT_MAX )
478 (SfxPoolItem*&)(*ppArr)->GetData()[nFree] = pOldItem;
479 else
480 (*ppArr)->C40_INSERT( SfxPoolItem, pOldItem, nCount );
485 delete pOldArr;
488 // -----------------------------------------------------------------------
490 SvStream &SfxItemPool::Load(SvStream &rStream)
492 DBG_CHKTHIS(SfxItemPool, 0);
493 DBG_ASSERT(ppStaticDefaults, "kein DefaultArray");
495 // protect items by increasing ref count
496 if ( !bPersistentRefCounts )
499 // "uber alle Which-Werte iterieren
500 SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
501 for( USHORT nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr )
503 // ist "uberhaupt ein Item mit dem Which-Wert da?
504 if ( *ppItemArr )
506 // "uber alle Items mit dieser Which-Id iterieren
507 SfxPoolItem** ppHtArr = (SfxPoolItem**)(*ppItemArr)->GetData();
508 for( USHORT n = (*ppItemArr)->Count(); n; --n, ++ppHtArr )
509 if (*ppHtArr)
511 #ifdef DBG_UTIL
512 const SfxPoolItem &rItem = **ppHtArr;
513 DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
514 0 != &((const SfxSetItem&)rItem).GetItemSet(),
515 "SetItem without ItemSet" );
516 DBG_WARNING( "loading non-empty ItemPool" );
517 #endif
519 AddRef( **ppHtArr, 1 );
524 // during loading (until LoadCompleted()) protect all items
525 pImp->nInitRefCount = 2;
528 // Load-Master finden
529 SfxItemPool *pLoadMaster = pMaster != this ? pMaster : 0;
530 while ( pLoadMaster && !pLoadMaster->pImp->bStreaming )
531 pLoadMaster = pLoadMaster->pSecondary;
533 // Gesamt Header einlesen
534 pImp->bStreaming = TRUE;
535 if ( !pLoadMaster )
537 // Format-Version laden
538 CHECK_FILEFORMAT2( rStream,
539 SFX_ITEMPOOL_TAG_STARTPOOL_5, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
540 rStream >> pImp->nMajorVer >> pImp->nMinorVer;
542 // Format-Version in Master-Pool "ubertragen
543 pMaster->pImp->nMajorVer = pImp->nMajorVer;
544 pMaster->pImp->nMinorVer = pImp->nMinorVer;
546 // altes Format?
547 if ( pImp->nMajorVer < 2 )
548 // pImp->bStreaming wird von Load1_Impl() zur"uckgesetzt
549 return Load1_Impl( rStream );
551 // zu neues Format?
552 if ( pImp->nMajorVer > SFX_ITEMPOOL_VER_MAJOR )
554 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
555 pImp->bStreaming = FALSE;
556 return rStream;
559 // Version 1.2-Trick-Daten "uberspringen
560 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_TRICK4OLD );
561 rStream.SeekRel( 4 ); // Hack-Daten wegen SfxStyleSheetPool-Bug skippen
564 // neues Record-orientiertes Format
565 SfxMiniRecordReader aPoolRec( &rStream, SFX_ITEMPOOL_REC );
566 if ( rStream.GetError() )
568 pImp->bStreaming = FALSE;
569 return rStream;
572 // Einzel-Header
573 int bOwnPool = TRUE;
574 UniString aExternName;
576 // Header-Record suchen
577 SfxMiniRecordReader aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER );
578 if ( rStream.GetError() )
580 pImp->bStreaming = FALSE;
581 return rStream;
584 // Header-lesen
585 rStream >> pImp->nLoadingVersion;
586 SfxPoolItem::readByteString(rStream, aExternName);
587 bOwnPool = aExternName == aName;
589 //! solange wir keine fremden Pools laden k"onnen
590 if ( !bOwnPool )
592 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
593 aPoolRec.Skip();
594 pImp->bStreaming = FALSE;
595 return rStream;
599 // Version-Maps
601 SfxMultiRecordReader aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP );
602 if ( rStream.GetError() )
604 pImp->bStreaming = FALSE;
605 return rStream;
608 // Versions-Maps einlesen
609 USHORT nOwnVersion = pImp->nVersion;
610 for ( USHORT nVerNo = 0; aVerRec.GetContent(); ++nVerNo )
612 // Header f"ur einzelne Version einlesen
613 USHORT nVersion, nHStart, nHEnd;
614 rStream >> nVersion >> nHStart >> nHEnd;
615 USHORT nCount = nHEnd - nHStart + 1;
617 // Version neuer als bekannt?
618 if ( nVerNo >= pImp->aVersions.Count() )
620 // neue Version hinzufuegen
621 USHORT *pMap = new USHORT[nCount];
622 for ( USHORT n = 0; n < nCount; ++n )
623 rStream >> pMap[n];
624 SetVersionMap( nVersion, nHStart, nHEnd, pMap );
627 pImp->nVersion = nOwnVersion;
630 // Items laden
631 FASTBOOL bSecondaryLoaded = FALSE;
632 long nSecondaryEnd = 0;
634 SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS);
635 while ( aWhichIdsRec.GetContent() )
637 // SlotId, Which-Id und Item-Version besorgen
638 USHORT nCount, nVersion, nWhich;
639 //!USHORT nSlotId = aWhichIdsRec.GetContentTag();
640 rStream >> nWhich;
641 if ( pImp->nLoadingVersion != pImp->nVersion )
642 // Which-Id aus File-Version in Pool-Version verschieben
643 nWhich = GetNewWhich( nWhich );
645 // unbekanntes Item aus neuerer Version
646 if ( !IsInRange(nWhich) )
647 continue;
649 rStream >> nVersion;
650 rStream >> nCount;
651 //!SFX_ASSERTWARNING( !nSlotId || !HasMap() ||
652 //! ( nSlotId == GetSlotId( nWhich, FALSE ) ) ||
653 //! !GetSlotId( nWhich, FALSE ),
654 //! nWhich, "Slot/Which mismatch" );
656 USHORT nIndex = GetIndex_Impl(nWhich);
657 SfxPoolItemArray_Impl **ppArr = pImp->ppPoolItems + nIndex;
659 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten
660 SfxPoolItem *pDefItem = *(ppStaticDefaults + nIndex);
661 pImp->bInSetItem = pDefItem->ISA(SfxSetItem);
662 if ( !bSecondaryLoaded && pSecondary && pImp->bInSetItem )
664 // an das Ende des eigenen Pools seeken
665 ULONG nLastPos = rStream.Tell();
666 aPoolRec.Skip();
668 // Sekund"arpool einlesen
669 pSecondary->Load( rStream );
670 bSecondaryLoaded = TRUE;
671 nSecondaryEnd = rStream.Tell();
673 // zur"uck zu unseren eigenen Items
674 rStream.Seek(nLastPos);
677 // Items an sich lesen
678 readTheItems(rStream, nCount, nVersion, pDefItem, ppArr);
680 pImp->bInSetItem = FALSE;
684 // Pool-Defaults lesen
686 SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS );
688 while ( aDefsRec.GetContent() )
690 // SlotId, Which-Id und Item-Version besorgen
691 USHORT nVersion, nWhich;
692 //!USHORT nSlotId = aDefsRec.GetContentTag();
693 rStream >> nWhich;
694 if ( pImp->nLoadingVersion != pImp->nVersion )
695 // Which-Id aus File-Version in Pool-Version verschieben
696 nWhich = GetNewWhich( nWhich );
698 // unbekanntes Item aus neuerer Version
699 if ( !IsInRange(nWhich) )
700 continue;
702 rStream >> nVersion;
703 //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, FALSE ) ),
704 //! nWhich, "Slot/Which mismatch" );
706 // Pool-Default-Item selbst laden
707 SfxPoolItem *pItem =
708 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
709 ->Create( rStream, nVersion );
710 pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
711 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
715 // ggf. Secondary-Pool laden
716 aPoolRec.Skip();
717 if ( pSecondary )
719 if ( !bSecondaryLoaded )
720 pSecondary->Load( rStream );
721 else
722 rStream.Seek( nSecondaryEnd );
725 // wenn nicht own-Pool, dann kein Name
726 if ( aExternName != aName )
727 aName.Erase();
729 pImp->bStreaming = FALSE;
730 return rStream;
733 // -----------------------------------------------------------------------
735 SvStream &SfxItemPool::Load1_Impl(SvStream &rStream)
737 // beim Master ist der Header schon von <Load()> geladen worden
738 if ( !pImp->bStreaming )
740 // Header des Secondary lesen
741 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
742 rStream >> pImp->nMajorVer >> pImp->nMinorVer;
744 sal_uInt32 nAttribSize;
745 int bOwnPool = TRUE;
746 UniString aExternName;
747 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 2 )
748 rStream >> pImp->nLoadingVersion;
749 SfxPoolItem::readByteString(rStream, aExternName);
750 bOwnPool = aExternName == aName;
751 pImp->bStreaming = TRUE;
753 //! solange wir keine fremden laden k"onnen
754 if ( !bOwnPool )
756 rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
757 pImp->bStreaming = FALSE;
758 return rStream;
761 // Versionen bis 1.3 k"onnen noch keine Which-Verschiebungen lesen
762 if ( pImp->nMajorVer == 1 && pImp->nMinorVer <= 2 &&
763 pImp->nVersion < pImp->nLoadingVersion )
765 rStream.SetError(ERRCODE_IO_WRONGVERSION);
766 pImp->bStreaming = FALSE;
767 return rStream;
770 // Size-Table liegt hinter den eigentlichen Attributen
771 rStream >> nAttribSize;
773 // Size-Table einlesen
774 ULONG nStartPos = rStream.Tell();
775 rStream.SeekRel( nAttribSize );
776 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_SIZES );
777 sal_uInt32 nSizeTableLen;
778 rStream >> nSizeTableLen;
779 sal_Char *pBuf = new sal_Char[nSizeTableLen];
780 rStream.Read( pBuf, nSizeTableLen );
781 ULONG nEndOfSizes = rStream.Tell();
782 SvMemoryStream aSizeTable( pBuf, nSizeTableLen, STREAM_READ );
784 // ab Version 1.3 steht in der Size-Table eine Versions-Map
785 if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 3 )
787 // Version-Map finden (letztes ULONG der Size-Table gibt Pos an)
788 rStream.Seek( nEndOfSizes - sizeof(sal_uInt32) );
789 sal_uInt32 nVersionMapPos;
790 rStream >> nVersionMapPos;
791 rStream.Seek( nVersionMapPos );
793 // Versions-Maps einlesen
794 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_VERSIONMAP );
795 USHORT nVerCount;
796 rStream >> nVerCount;
797 for ( USHORT nVerNo = 0; nVerNo < nVerCount; ++nVerNo )
799 // Header f"ur einzelne Version einlesen
800 USHORT nVersion, nHStart, nHEnd;
801 rStream >> nVersion >> nHStart >> nHEnd;
802 USHORT nCount = nHEnd - nHStart + 1;
803 USHORT nBytes = (nCount)*sizeof(USHORT);
805 // Version neuer als bekannt?
806 if ( nVerNo >= pImp->aVersions.Count() )
808 // neue Version hinzufuegen
809 USHORT *pMap = new USHORT[nCount];
810 for ( USHORT n = 0; n < nCount; ++n )
811 rStream >> pMap[n];
812 SetVersionMap( nVersion, nHStart, nHEnd, pMap );
814 else
815 // Version schon bekannt => "uberspringen
816 rStream.SeekRel( nBytes );
820 // Items laden
821 rStream.Seek( nStartPos );
822 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ITEMS );
823 FASTBOOL bSecondaryLoaded = FALSE;
824 long nSecondaryEnd = 0;
825 USHORT nWhich, nSlot;
826 while ( rStream >> nWhich, nWhich )
828 // ggf. Which-Id aus alter Version verschieben?
829 if ( pImp->nLoadingVersion != pImp->nVersion )
830 nWhich = GetNewWhich( nWhich );
832 rStream >> nSlot;
833 USHORT nMappedWhich = GetWhich(nSlot, FALSE);
834 int bKnownItem = bOwnPool || IsWhich(nMappedWhich);
836 USHORT nRef, nCount, nVersion;
837 sal_uInt32 nAttrSize;
838 rStream >> nVersion >> nCount;
840 SfxPoolItemArray_Impl **ppArr = 0;
841 SfxPoolItemArray_Impl *pNewArr = 0;
842 SfxPoolItem *pDefItem = 0;
843 if ( bKnownItem )
845 if ( !bOwnPool )
846 nWhich = nMappedWhich;
848 //!SFX_ASSERTWARNING( !nSlot || !HasMap() ||
849 //! ( nSlot == GetSlotId( nWhich, FALSE ) ) ||
850 //! !GetSlotId( nWhich, FALSE ),
851 //! nWhich, "Slot/Which mismatch" );
853 USHORT nIndex = GetIndex_Impl(nWhich);
854 ppArr = pImp->ppPoolItems + nIndex;
855 pNewArr = new SfxPoolItemArray_Impl( nCount );
856 pDefItem = *(ppStaticDefaults + nIndex);
859 // Position vor ersten Item merken
860 ULONG nLastPos = rStream.Tell();
862 // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten
863 if ( !bSecondaryLoaded && pSecondary && pDefItem->ISA(SfxSetItem) )
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 );
870 // Sekund"arpool einlesen
871 pSecondary->Load1_Impl( rStream );
872 bSecondaryLoaded = TRUE;
873 nSecondaryEnd = rStream.Tell();
875 // zur"uck zu unseren eigenen Items
876 rStream.Seek(nLastPos);
879 // Items an sich lesen
880 for ( USHORT j = 0; j < nCount; ++j )
882 ULONG nPos = nLastPos;
883 rStream >> nRef;
885 if ( bKnownItem )
887 SfxPoolItem *pItem = 0;
888 if ( nRef )
890 pItem = pDefItem->Create(rStream, nVersion);
892 if ( !bPersistentRefCounts )
893 // bis <SfxItemPool::LoadCompleted()> festhalten
894 AddRef(*pItem, 1);
895 else
897 if ( nRef > SFX_ITEMS_OLD_MAXREF )
898 pItem->SetKind( nRef );
899 else
900 AddRef(*pItem, nRef);
904 pNewArr->C40_INSERT( SfxPoolItem, pItem, j);
906 // restliche gespeicherte Laenge skippen (neueres Format)
907 nLastPos = rStream.Tell();
910 aSizeTable >> nAttrSize;
911 SFX_ASSERT( !bKnownItem || ( nPos + nAttrSize) >= nLastPos,
912 nPos,
913 "too many bytes read - version mismatch?" );
915 if ( !bKnownItem || ( nLastPos < (nPos + nAttrSize) ) )
917 nLastPos = nPos + nAttrSize;
918 rStream.Seek( nLastPos );
922 if ( bKnownItem )
924 SfxPoolItemArray_Impl *pOldArr = *ppArr;
925 *ppArr = pNewArr;
927 // die Items merken, die schon im Pool sind
928 int bEmpty = TRUE;
929 if ( 0 != pOldArr )
930 for ( USHORT n = 0; bEmpty && n < pOldArr->Count(); ++n )
931 bEmpty = pOldArr->GetObject(n) == 0;
932 DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
933 if ( !bEmpty )
935 // f"ur alle alten suchen, ob ein gleiches neues existiert
936 for ( USHORT nOld = 0; nOld < pOldArr->Count(); ++nOld )
938 SfxPoolItem *pOldItem = (*pOldArr)[nOld];
939 if ( pOldItem )
941 int bFound = FALSE;
942 for ( USHORT nNew = 0;
943 !bFound && nNew < (*ppArr)->Count();
944 ++nNew )
946 SfxPoolItem *&rpNewItem =
947 (SfxPoolItem*&)(*ppArr)->GetData()[nNew];
949 if ( rpNewItem && *rpNewItem == *pOldItem )
951 AddRef( *pOldItem, rpNewItem->GetRefCount() );
952 SetRefCount( *rpNewItem, 0 );
953 delete rpNewItem;
954 rpNewItem = pOldItem;
955 bFound = TRUE;
956 SFX_TRACE( "reusing item", pOldItem );
959 //! DBG_ASSERT( bFound, "old-item not found in file" );
960 if ( !bFound )
962 SFX_TRACE( "item not found: ", pOldItem );
967 delete pOldArr; /* @@@ */
971 // Pool-Defaults lesen
972 if ( pImp->nMajorVer > 1 || pImp->nMinorVer > 0 )
973 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_DEFAULTS );
975 ULONG nLastPos = rStream.Tell();
976 while ( rStream >> nWhich, nWhich )
978 // ggf. Which-Id aus alter Version verschieben?
979 if ( pImp->nLoadingVersion != pImp->nVersion )
980 nWhich = GetNewWhich( nWhich );
982 rStream >> nSlot;
983 USHORT nMappedWhich = GetWhich(nSlot, FALSE);
984 int bKnownItem = bOwnPool || IsWhich(nMappedWhich);
986 ULONG nPos = nLastPos;
987 sal_uInt32 nSize;
988 USHORT nVersion;
989 rStream >> nVersion;
991 if ( bKnownItem )
993 if ( !bOwnPool )
994 nWhich = nMappedWhich;
995 SfxPoolItem *pItem =
996 ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
997 ->Create( rStream, nVersion );
998 pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
999 *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
1002 nLastPos = rStream.Tell();
1003 aSizeTable >> nSize;
1004 SFX_ASSERT( ( nPos + nSize) >= nLastPos, nPos,
1005 "too many bytes read - version mismatch?" );
1006 if ( nLastPos < (nPos + nSize) )
1007 rStream.Seek( nPos + nSize );
1010 delete[] pBuf;
1011 rStream.Seek(nEndOfSizes);
1012 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
1013 CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
1015 if ( pSecondary )
1017 if ( !bSecondaryLoaded )
1018 pSecondary->Load1_Impl( rStream );
1019 else
1020 rStream.Seek( nSecondaryEnd );
1023 if ( aExternName != aName )
1024 aName.Erase();
1026 pImp->bStreaming = FALSE;
1027 return rStream;
1030 // -----------------------------------------------------------------------
1032 const SfxPoolItem* SfxItemPool::LoadSurrogate
1034 SvStream& rStream, // vor einem Surrogat positionierter Stream
1035 USHORT& rWhich, // Which-Id des zu ladenden <SfxPoolItem>s
1036 USHORT nSlotId, // Slot-Id des zu ladenden <SfxPoolItem>s
1037 const SfxItemPool* pRefPool // <SfxItemPool> in dem das Surrogat gilt
1040 /* [Beschreibung]
1042 L"adt Surrogat aus 'rStream' und liefert das dadurch in 'rRefPool'
1043 repr"asentierte SfxPoolItem zu"ruck. Ist das im Stream befindliche
1044 Surrogat == SFX_ITEMS_DIRECT (!SFX_ITEM_POOLABLE) wird 0 zur"uckgegeben,
1045 das Item ist direkt aus dem Stream zu laden. Bei 0xfff0 (SFX_ITEMS_NULL)
1046 wird auch 0 zurueckgegeben und rWhich auf 0 gesetzt, das Item ist nicht
1047 verfuegbar.
1049 Ansonsten wird ber"ucksichtigt, ob der betroffene Pool ohne Ref-Counts
1050 geladen wird, ob aus einem neuen Pool nachgeladen wird (&rRefPool != this)
1051 oder ob aus einem g"anzlich anders aufgebauten Pool geladen wird.
1053 Wird aus einem anders aufgebauten Pool geladen und die 'nSlotId' kann
1054 nicht in eine Which-Id dieses Pools gemappt werden, wird ebenfalls 0
1055 zur"uckgeliefert.
1057 Preconditions: - Pool mu\s geladen sein
1058 - LoadCompleted darf noch nicht gerufen worden sein
1059 - 'rStream' steht genau an der Position, an der ein
1060 Surrogat f"ur ein Item mit der SlotId 'nSlotId' und
1061 der WhichId 'rWhichId' mit StoreSurrogate gepeichert
1062 wurde
1064 Postconditions: - 'rStream' ist so positioniert, wie auch StoreSurrogate
1065 sein speichern beendet hatte
1066 - konnte ein Item geladen werden, befindet es sich
1067 in diesem SfxItemPool
1068 - 'rWhichId' enth"alt die ggf. gemappte Which-Id
1069 Laufzeit: Tiefe des Ziel Sekund"arpools * 10 + 10
1071 [Querverweise]
1073 <SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const>
1077 // erstmal das Surrogat lesen
1078 USHORT nSurrogat;
1079 rStream >> nSurrogat;
1081 // direkt gespeichertes Item?
1082 if ( SFX_ITEMS_DIRECT == nSurrogat )
1083 return 0;
1085 // nicht vorhandenes Item?
1086 if ( SFX_ITEMS_NULL == nSurrogat )
1088 rWhich = 0;
1089 return 0;
1092 // Bei einem identisch aufgebauten Pool (im Stream) kann das Surrogat
1093 // auf jeden Fall aufgel"ost werden.
1094 if ( !pRefPool )
1095 pRefPool = this;
1096 FASTBOOL bResolvable = pRefPool->GetName().Len() > 0;
1097 if ( !bResolvable )
1099 // Bei einem anders aufgebauten Pool im Stream, mu\s die SlotId
1100 // aus dem Stream in eine Which-Id gemappt werden k"onnen.
1101 USHORT nMappedWhich = nSlotId ? GetWhich(nSlotId, TRUE) : 0;
1102 if ( IsWhich(nMappedWhich) )
1104 // gemappte SlotId kann "ubernommen werden
1105 rWhich = nMappedWhich;
1106 bResolvable = TRUE;
1110 // kann Surrogat aufgel"ost werden?
1111 const SfxPoolItem *pItem = 0;
1112 if ( bResolvable )
1114 for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pSecondary )
1116 // richtigen (Folge-) Pool gefunden?
1117 if ( pTarget->IsInRange(rWhich) )
1119 // dflt-Attribut?
1120 if ( SFX_ITEMS_STATICDEFAULT == nSurrogat )
1121 return *(pTarget->ppStaticDefaults +
1122 pTarget->GetIndex_Impl(rWhich));
1124 SfxPoolItemArray_Impl* pItemArr = *(pTarget->pImp->ppPoolItems +
1125 pTarget->GetIndex_Impl(rWhich));
1126 pItem = pItemArr && nSurrogat < pItemArr->Count()
1127 ? (*pItemArr)[nSurrogat]
1128 : 0;
1129 if ( !pItem )
1131 DBG_ERROR( "can't resolve surrogate" );
1132 rWhich = 0; // nur zur Sicherheit fuer richtige Stream-Pos
1133 return 0;
1136 // Nachladen aus Ref-Pool?
1137 if ( pRefPool != pMaster )
1138 return &pTarget->Put( *pItem );
1140 // Referenzen sind NICHT schon mit Pool geladen worden?
1141 if ( !pTarget->HasPersistentRefCounts() )
1142 AddRef( *pItem, 1 );
1143 else
1144 return pItem;
1146 return pItem;
1150 SFX_ASSERT( FALSE, rWhich, "can't resolve Which-Id in LoadSurrogate" );
1153 return 0;
1156 //-------------------------------------------------------------------------
1159 FASTBOOL SfxItemPool::StoreSurrogate
1161 SvStream& rStream,
1162 const SfxPoolItem* pItem
1163 ) const
1165 /* [Beschreibung]
1167 Speichert ein Surrogat f"ur '*pItem' in 'rStream'.
1170 [R"uckgabewert]
1172 FASTBOOL TRUE
1173 es wurde ein echtes Surrogat gespeichert, auch
1174 SFX_ITEMS_NULL bei 'pItem==0',
1175 SFX_ITEMS_STATICDEFAULT und SFX_ITEMS_POOLDEFAULT
1176 gelten als 'echte' Surrogate
1178 FALSE
1179 es wurde ein Dummy-Surrogat (SFX_ITEMS_DIRECT)
1180 gespeichert, das eigentliche Item mu\s direkt
1181 hinterher selbst gespeichert werden
1185 if ( pItem )
1187 FASTBOOL bRealSurrogate = IsItemFlag(*pItem, SFX_ITEM_POOLABLE);
1188 rStream << ( bRealSurrogate
1189 ? GetSurrogate( pItem )
1190 : (UINT16) SFX_ITEMS_DIRECT );
1191 return bRealSurrogate;
1194 rStream << (UINT16) SFX_ITEMS_NULL;
1195 return TRUE;
1198 // -----------------------------------------------------------------------
1200 USHORT SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const
1202 DBG_CHKTHIS(SfxItemPool, 0);
1203 DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
1204 DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
1205 DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );
1207 if ( !IsInRange(pItem->Which()) )
1209 if ( pSecondary )
1210 return pSecondary->GetSurrogate( pItem );
1211 SFX_ASSERT( 0, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" );
1214 // Pointer auf static- oder pool-dflt-Attribut?
1215 if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
1216 return SFX_ITEMS_STATICDEFAULT;
1218 SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(pItem->Which()));
1219 DBG_ASSERT(pItemArr, "ItemArr nicht vorhanden");
1220 const USHORT nCount = pItemArr->Count();
1221 for ( USHORT i = 0; i < nCount; ++i )
1223 const SfxPoolItem *p = (*pItemArr)[i];
1224 if ( p == pItem )
1225 return i;
1227 SFX_ASSERT( 0, pItem->Which(), "Item nicht im Pool");
1228 return SFX_ITEMS_NULL;
1231 // -----------------------------------------------------------------------
1233 FASTBOOL SfxItemPool::IsInStoringRange( USHORT nWhich ) const
1235 return nWhich >= pImp->nStoringStart &&
1236 nWhich <= pImp->nStoringEnd;
1239 //------------------------------------------------------------------------
1241 void SfxItemPool::SetStoringRange( USHORT nFrom, USHORT nTo )
1243 /* [Beschreibung]
1245 Mit dieser Methode kann der Which-Bereich eingeengt werden, der
1246 von ItemSets dieses Pool (und dem Pool selbst) gespeichert wird.
1247 Die Methode muss dazu vor <SfxItemPool::Store()> gerufen werden
1248 und die Werte muessen auch noch gesetzt sein, wenn das eigentliche
1249 Dokument (also die ItemSets gespeicher werden).
1251 Ein Zuruecksetzen ist dann nicht noetig, wenn dieser Range vor
1252 JEDEM Speichern richtig gesetzt wird, da er nur beim Speichern
1253 beruecksichtigt wird.
1255 Dieses muss fuer das 3.1-Format gemacht werden, da dort eine
1256 Bug in der Pool-Lade-Methode vorliegt.
1260 pImp->nStoringStart = nFrom;
1261 pImp->nStoringEnd = nTo;
1264 // -----------------------------------------------------------------------
1266 void SfxItemPool::SetVersionMap
1268 USHORT nVer, /* neue Versionsnummer */
1269 USHORT nOldStart, /* alte erste Which-Id */
1270 USHORT nOldEnd, /* alte letzte Which-Id */
1271 USHORT* pOldWhichIdTab /* Array mit genau dem Aufbau der Which-Ids
1272 der vorhergehenden Version, in denen
1273 die jeweils neue Which-Id steht. */
1276 /* [Beschreibung]
1278 Mit dieser Methode k"onnen neue, inkompatible Which-Id-Folgen oder
1279 Verteilungen realisiert werden. Pools, die noch mit alten Versionen
1280 gespeichert wurden, werden dann "uber die angegebene Tabelle solange
1281 gemappt, bis die aktuelle Version erreicht ist. Neuere Pools k"onnen
1282 unter Verlust neuer Attribute geladen werden, da die Map mit dem Pool
1283 gespeichert wird.
1285 Precondition: Pool darf noch nicht geladen sein
1286 Postcondition: Which-Ids aus fr"uheren Versionen k"onnen bei Laden auf
1287 Version 'nVer' gemappt werden
1288 Laufzeit: 1.5 * new + 10
1290 [Anmerkung]
1292 F"ur neue Which-Ranges (nStart,nEnd) m"ssen im Vergleich zur Vorg"anger-
1293 Version (nOldStart,nOldEnd) immer gelten, da\s (nOldStart,nOldEnd)
1294 vollst"andig in (nStart,nEnd) enthalten ist. Es ist also zul"assig, den
1295 Which-Range in beide Richtungen zu erweitern, auch durch Einf"ugung
1296 von Which-Ids, nicht aber ihn zu beschneiden.
1298 Diese Methode sollte nur im oder direkt nach Aufruf des Konstruktors
1299 gerufen werden.
1301 Das Array mu\s statisch sein, da es nicht kopiert wird und au\serdem
1302 im Copy-Ctor des SfxItemPool wiederverwendet wird.
1305 [Beispiel]
1307 Urspr"unglich (Version 0) hatte der Pool folgende Which-Ids:
1309 1:A, 2:B, 3:C, 4:D
1311 Nun soll eine neue Version (Version 1) zwei zus"atzliche Ids X und Y
1312 zwischen B und C erhalten, also wie folgt aussehen:
1314 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D
1316 Dabei haben sich also die Ids 3 und 4 ge"andert. F"ur die neue Version
1317 m"u\ste am Pool folgendes gesetzt werden:
1319 static USHORT nVersion1Map = { 1, 2, 5, 6 };
1320 pPool->SetVersionMap( 1, 1, 4, &nVersion1Map );
1323 [Querverweise]
1325 <SfxItemPool::IsLoadingVersionCurrent()const>
1326 <SfxItemPool::GetNewWhich(USHORT)>
1327 <SfxItemPool::GetVersion()const>
1328 <SfxItemPool::GetLoadingVersion()const>
1332 // neuen Map-Eintrag erzeugen und einf"ugen
1333 const SfxPoolVersion_Impl *pVerMap = new SfxPoolVersion_Impl(
1334 nVer, nOldStart, nOldEnd, pOldWhichIdTab );
1335 pImp->aVersions.Insert( pVerMap, pImp->aVersions.Count() );
1337 DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" );
1338 pImp->nVersion = nVer;
1340 // Versions-Range anpassen
1341 for ( USHORT n = 0; n < nOldEnd-nOldStart+1; ++n )
1343 USHORT nWhich = pOldWhichIdTab[n];
1344 if ( nWhich < pImp->nVerStart )
1346 if ( !nWhich )
1347 nWhich = 0;
1348 pImp->nVerStart = nWhich;
1350 else if ( nWhich > pImp->nVerEnd )
1351 pImp->nVerEnd = nWhich;
1355 // -----------------------------------------------------------------------
1357 USHORT SfxItemPool::GetNewWhich
1359 USHORT nFileWhich // die aus dem Stream geladene Which-Id
1360 ) const
1362 /* [Beschreibung]
1364 Diese Methoden rechnet Which-Ids aus einem File-Format in die der
1365 aktuellen Pool-Version um. Ist das File-Format "alter, werden die vom
1366 Pool-Entwickler mit SetVersion() gesetzten Tabellen verwendet,
1367 ist das File-Format neuer, dann die aus dem File geladenen Tabellen.
1368 Im letzteren Fall kann ggf. nicht jede Which-Id gemappt werden,
1369 so da\s 0 zur"uckgeliefert wird.
1371 Die Berechnung ist nur f"ur Which-Ids definiert, die in der betreffenden
1372 File-Version unterst"utzt wurden. Dies ist per Assertion abgesichert.
1374 Precondition: Pool mu\s geladen sein
1375 Postcondition: unver"andert
1376 Laufzeit: linear(Anzahl der Sekund"arpools) +
1377 linear(Differenz zwischen alter und neuer Version)
1380 [Querverweise]
1382 <SfxItemPool::IsLoadingVersionCurrent()const>
1383 <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
1384 <SfxItemPool::GetVersion()const>
1385 <SfxItemPool::GetLoadingVersion()const>
1389 // (Sekund"ar-) Pool bestimmen
1390 if ( !IsInVersionsRange(nFileWhich) )
1392 if ( pSecondary )
1393 return pSecondary->GetNewWhich( nFileWhich );
1394 SFX_ASSERT( 0, nFileWhich, "unknown which in GetNewWhich()" );
1397 // Version neuer/gleich/"alter?
1398 short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion;
1400 // Which-Id einer neueren Version?
1401 if ( nDiff > 0 )
1403 // von der Top-Version bis runter zur File-Version stufenweise mappen
1404 for ( USHORT nMap = pImp->aVersions.Count(); nMap > 0; --nMap )
1406 SfxPoolVersion_Impl *pVerInfo = pImp->aVersions[nMap-1];
1407 if ( pVerInfo->_nVer > pImp->nVersion )
1408 { USHORT nOfs;
1409 USHORT nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1;
1410 for ( nOfs = 0;
1411 nOfs <= nCount &&
1412 pVerInfo->_pMap[nOfs] != nFileWhich;
1413 ++nOfs )
1414 continue;
1416 if ( pVerInfo->_pMap[nOfs] == nFileWhich )
1417 nFileWhich = pVerInfo->_nStart + nOfs;
1418 else
1419 return 0;
1421 else
1422 break;
1426 // Which-Id einer neueren Version?
1427 else if ( nDiff < 0 )
1429 // von der File-Version bis zur aktuellen Version stufenweise mappen
1430 for ( USHORT nMap = 0; nMap < pImp->aVersions.Count(); ++nMap )
1432 SfxPoolVersion_Impl *pVerInfo = pImp->aVersions[nMap];
1433 if ( pVerInfo->_nVer > pImp->nLoadingVersion )
1435 DBG_ASSERT( nFileWhich >= pVerInfo->_nStart &&
1436 nFileWhich <= pVerInfo->_nEnd,
1437 "which-id unknown in version" );
1438 nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart];
1443 // originale (nDiff==0) bzw. gemappte (nDiff!=0) Id zur"uckliefern
1444 return nFileWhich;
1447 // -----------------------------------------------------------------------
1450 FASTBOOL SfxItemPool::IsInVersionsRange( USHORT nWhich ) const
1452 return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd;
1455 // -----------------------------------------------------------------------
1457 FASTBOOL SfxItemPool::IsCurrentVersionLoading() const
1459 /* [Beschreibung]
1461 Mit dieser Methode kann festgestellt werden, ob die geladene Pool-Version
1462 dem aktuellen Pool-Aufbau entspricht.
1464 Precondition: Pool mu\s geladen sein
1465 Postcondition: unver"andert
1466 Laufzeit: linear(Anzahl der Sekund"arpools)
1469 [Querverweise]
1471 <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
1472 <SfxItemPool::GetNewWhich(USHORT)const>
1473 <SfxItemPool::GetVersion()const>
1474 <SfxItemPool::GetLoadingVersion()const>
1478 return ( pImp->nVersion == pImp->nLoadingVersion ) &&
1479 ( !pSecondary || pSecondary->IsCurrentVersionLoading() );
1482 // -----------------------------------------------------------------------
1484 USHORT SfxItemPool::GetVersion() const
1486 /* [Beschreibung]
1488 Diese Methode liefert die aktuelle Versionsnummer des SfxItemPool-Aufbaus
1489 (also des Which-Bereichs).
1491 Precondition: keine
1492 Postcondition: unver"andert
1493 Laufzeit: 2
1496 [Anmerkung]
1498 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools
1499 ber"ucksichtigt werden.
1502 [Querverweise]
1504 <SfxItemPool::IsLoadingVersionCurrent()const>
1505 <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
1506 <SfxItemPool::GetNewWhich(USHORT)const>
1507 <SfxItemPool::GetLoadingVersion()const>
1511 return pImp->nVersion;
1514 // -----------------------------------------------------------------------
1516 USHORT SfxItemPool::GetLoadingVersion() const
1518 /* [Beschreibung]
1520 Diese Methode liefert die Versionsnummer des SfxItemPool-Aufbaus
1521 (also des Which-Bereichs), die bei Laden vorgefunden wurde.
1523 Precondition: Pool mu\s geladen sein
1524 Postcondition: unver"andert
1525 Laufzeit: 2
1528 [Anmerkung]
1530 Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools
1531 ber"ucksichtigt werden.
1534 [Querverweise]
1536 <SfxItemPool::IsLoadingVersionCurrent()const>
1537 <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
1538 <SfxItemPool::GetNewWhich(USHORT)const>
1539 <SfxItemPool::GetVersion()const>
1543 return pImp->nLoadingVersion;
1546 //-------------------------------------------------------------------------
1548 FASTBOOL SfxItemPool::IsVer2_Impl() const
1550 return pMaster->pImp->nMajorVer >= 2;
1553 //-------------------------------------------------------------------------
1556 FASTBOOL SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem,
1557 FASTBOOL bDirect ) const
1559 /* [Beschreibung]
1561 Speichert das <SfxPoolItem> 'rItem' in den <SvStream> 'rStream'
1562 entweder als Surrogat ('bDirect == FALSE') oder direkt mit 'rItem.Store()'.
1563 Nicht poolable Items werden immer direkt gespeichert. Items ohne Which-Id,
1564 also SID-Items, werden nicht gespeichert, ebenso wenn Items, die in der
1565 File-Format-Version noch nicht vorhanden waren (return FALSE).
1567 Das Item wird im Stream wie folgt abgelegt:
1569 USHORT rItem.Which()
1570 USHORT GetSlotId( rItem.Which() ) bzw. 0 falls nicht verf"urbar
1571 USHORT GetSurrogate( &rItem ) bzw. SFX_ITEM_DIRECT bei '!SFX_ITEM_POOLBLE'
1573 optional (falls 'bDirect == TRUE' oder '!rItem.IsPoolable()':
1575 USHORT rItem.GetVersion()
1576 ULONG Size
1577 Size rItem.Store()
1580 [Querverweise]
1582 <SfxItemPool::LoadItem(SvStream&,FASTBOOL)const>
1586 DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" );
1588 if ( IsSlot( rItem.Which() ) )
1589 return FALSE;
1590 const SfxItemPool *pPool = this;
1591 while ( !pPool->IsInStoringRange(rItem.Which()) )
1592 if ( 0 == ( pPool = pPool->pSecondary ) )
1593 return FALSE;
1595 DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem),
1596 "SetItem contains ItemSet with SetItem" );
1598 USHORT nSlotId = pPool->GetSlotId( rItem.Which(), TRUE );
1599 USHORT nItemVersion = rItem.GetVersion(_nFileFormatVersion);
1600 if ( USHRT_MAX == nItemVersion )
1601 return FALSE;
1603 rStream << rItem.Which() << nSlotId;
1604 if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) )
1606 rStream << nItemVersion;
1607 rStream << (UINT32) 0L; // Platz fuer Laenge in Bytes
1608 ULONG nIStart = rStream.Tell();
1609 rItem.Store(rStream, nItemVersion);
1610 ULONG nIEnd = rStream.Tell();
1611 rStream.Seek( nIStart-4 );
1612 rStream << (INT32) ( nIEnd-nIStart );
1613 rStream.Seek( nIEnd );
1616 return TRUE;
1619 //-------------------------------------------------------------------------
1622 const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, FASTBOOL bDirect,
1623 const SfxItemPool *pRefPool )
1625 // pRefPool==-1 => nicht putten!
1628 USHORT nWhich, nSlot; // nSurrogate;
1629 rStream >> nWhich >> nSlot;
1631 BOOL bDontPut = (SfxItemPool*)-1 == pRefPool;
1632 if ( bDontPut || !pRefPool )
1633 pRefPool = this;
1635 // richtigen Sekund"ar-Pool finden
1636 while ( !pRefPool->IsInVersionsRange(nWhich) )
1638 if ( pRefPool->pSecondary )
1639 pRefPool = pRefPool->pSecondary;
1640 else
1642 // WID in der Version nicht vorhanden => ueberspringen
1643 USHORT nSurro, nVersion, nLen;
1644 rStream >> nSurro;
1645 if ( SFX_ITEMS_DIRECT == nSurro )
1647 rStream >> nVersion >> nLen;
1648 rStream.SeekRel( nLen );
1650 return 0;
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 );
1660 DBG_ASSERT( !nWhich || !pImp->bInSetItem ||
1661 !pRefPool->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem),
1662 "loading SetItem in ItemSet of SetItem" );
1664 // soll "uber Surrogat geladen werden?
1665 const SfxPoolItem *pItem = 0;
1666 if ( !bDirect )
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(USHORT) );
1677 // wird direkt, also nicht "uber Surrogat geladen?
1678 if ( bDirect || ( nWhich && !pItem ) )
1680 // bDirekt bzw. nicht IsPoolable() => Item direkt laden
1681 USHORT nVersion;
1682 sal_uInt32 nLen;
1683 rStream >> nVersion >> nLen;
1684 ULONG nIStart = rStream.Tell();
1686 // Which-Id in dieser Version bekannt?
1687 if ( nWhich )
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 )
1697 pItem = &Put(*pNewItem);
1698 delete pNewItem;
1700 else
1701 pItem = 0;
1702 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 );
1707 else
1708 // Item "uberspringen
1709 rStream.Seek( nIStart+nLen );
1712 return pItem;