summaryrefslogtreecommitdiff
path: root/svl/source/items/poolio.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svl/source/items/poolio.cxx')
-rw-r--r--svl/source/items/poolio.cxx1715
1 files changed, 1715 insertions, 0 deletions
diff --git a/svl/source/items/poolio.cxx b/svl/source/items/poolio.cxx
new file mode 100644
index 000000000000..4383ac99d2ed
--- /dev/null
+++ b/svl/source/items/poolio.cxx
@@ -0,0 +1,1715 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: poolio.cxx,v $
+ * $Revision: 1.11 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svl.hxx"
+
+#include <string.h>
+#include <stdio.h>
+
+#ifndef GCC
+#endif
+
+#include <tools/solar.h>
+#include <svl/itempool.hxx>
+#include "whassert.hxx"
+#include <svl/brdcst.hxx>
+#include <svl/filerec.hxx>
+#include <svl/svldata.hxx>
+#include "poolio.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+DBG_NAME(SfxItemPool);
+
+//========================================================================
+
+void SfxItemPool::SetStoringPool( const SfxItemPool *pStoringPool )
+
+/* [Beschreibung]
+
+ Diese Methode setzt den <SfxItemPool>, der gerade gespeichert wird.
+ Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format-
+ Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines
+ <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen
+ Pool mit <SfxItemPool::GetStoringPool()> zu besorgen.
+
+ Sie wird von <SfxItemPool::Store()> bedient, kann jedoch f"ur nicht
+ poolable Items auch direkt gerufen werden. Bitte m"oglichst nicht
+ f"ur jedes Item einzeln, da 2 Calls!
+*/
+
+{
+ ImpSvlData::GetSvlData().pStoringPool = pStoringPool;
+}
+
+//-------------------------------------------------------------------------
+
+const SfxItemPool* SfxItemPool::GetStoringPool()
+
+/* [Beschreibung]
+
+ Diese Methode liefert den <SfxItemPool>, der gerade gespeichert wird.
+ Sie sollte nur in Notf"allen verwendet werden, um z.B. File-Format-
+ Kompatibilit"at zu gew"ahrleisten o."o. - z.B. in der "uberladung eines
+ <SfxPoolItem::Store()> zus"atzliche Daten aus dem dazuge"horigen
+ Pool zu besorgen.
+*/
+
+{
+ return ImpSvlData::GetSvlData().pStoringPool;
+}
+
+//-------------------------------------------------------------------------
+
+SvStream &SfxItemPool::Store(SvStream &rStream) const
+
+/* [Beschreibung]
+
+ Der SfxItemPool wird inklusive aller seiner Sekund"arpools mit
+ Pool-Defaults und gepoolten Items in dem angegebenen Stream gespeichert.
+ Die statischen Defaults werden nicht gespeichert.
+
+
+ [Fileformat]
+
+ ;zun"achst ein Kompatiblit"ats-Header-Block
+ Start: 0x1111 SFX_ITEMPOOL_TAG_STARTPOOLS(_4/_5)
+ BYTE MAJOR_VER ;SfxItemPool-Version
+ BYTE MINOR_VER ;"
+ 0xFFFF SFX_ITEMPOOL_TAG_TRICK4OLD ;ex. GetVersion()
+ USHORT 0x0000 ;Pseudo-StyleSheetPool
+ USHORT 0x0000 ;Pseudo-StyleSheetPool
+
+ ;den ganzen Pool in einen Record
+ record SfxMiniRecod(SFX_ITEMPOOL_REC)
+
+ ;je ein Header vorweg
+ Header: record SfxMiniRecord(SFX_ITEMPOOL_REC_HEADER)
+ USHORT GetVersion() ;Which-Ranges etc.
+ String GetName() ;Pool-Name
+
+ ;die Versions-Map, um WhichIds neuer File-Versionen mappen zu k"onnen
+ Versions: record SfxMultiRecord(SFX_ITEMPOOL_REC_VERSIONS, 0)
+ USHORT OldVersion
+ USHORT OldStartWhich
+ USHORT OldEndWhich
+ USHORT[] NewWhich (OldEndWhich-OldStartWhich+1)
+
+ ;jetzt die gepoolten Items (zuerst nicht-SfxSetItems)
+ Items: record SfxMultiRecord(SFX_ITEMPOOL_REC_WHICHIDS, 0)
+ content SlotId, 0
+ USHORT WhichId
+ USHORT pItem->GetVersion()
+ USHORT Array-Size
+ record SfxMultiRecord(SFX_, 0)
+ content Surrogate
+ USHORT RefCount
+ unknown pItem->Store()
+
+ ;jetzt die gesetzten Pool-Defaults
+ Defaults: record SfxMultiRecord(SFX_ITEMPOOL_REC_DEFAULTS, 0)
+ content SlotId, 0
+ USHORT WhichId
+ USHORT pPoolDef->GetVersion()
+ unknown pPoolDef->Store();
+
+ ;dahinter folgt ggf. der Secondary ohne Kompatiblit"ats-Header-Block
+*/
+
+{
+ DBG_CHKTHIS(SfxItemPool, 0);
+
+ // Store-Master finden
+ SfxItemPool *pStoreMaster = pMaster != this ? pMaster : 0;
+ while ( pStoreMaster && !pStoreMaster->pImp->bStreaming )
+ pStoreMaster = pStoreMaster->pSecondary;
+
+ // Alter-Header (Version des Pools an sich und Inhalts-Version 0xffff)
+ pImp->bStreaming = TRUE;
+ if ( !pStoreMaster )
+ {
+ rStream << ( rStream.GetVersion() >= SOFFICE_FILEFORMAT_50
+ ? SFX_ITEMPOOL_TAG_STARTPOOL_5
+ : SFX_ITEMPOOL_TAG_STARTPOOL_4 );
+ rStream << SFX_ITEMPOOL_VER_MAJOR << SFX_ITEMPOOL_VER_MINOR;
+ rStream << SFX_ITEMPOOL_TAG_TRICK4OLD;
+
+ // SfxStyleSheet-Bug umgehen
+ rStream << UINT16(0); // Version
+ rStream << UINT16(0); // Count (2. Schleife f"allt sonst auf die Fresse)
+ }
+
+ // jeder Pool ist als ganzes ein Record
+ SfxMiniRecordWriter aPoolRec( &rStream, SFX_ITEMPOOL_REC );
+ ImpSvlData::GetSvlData().pStoringPool = this;
+
+ // Einzel-Header (Version des Inhalts und Name)
+ {
+ SfxMiniRecordWriter aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER);
+ rStream << pImp->nVersion;
+ SfxPoolItem::writeByteString(rStream, aName);
+ }
+
+ // Version-Maps
+ {
+ SfxMultiVarRecordWriter aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP, 0 );
+ for ( USHORT nVerNo = 0; nVerNo < pImp->aVersions.Count(); ++nVerNo )
+ {
+ aVerRec.NewContent();
+ SfxPoolVersion_Impl *pVer = pImp->aVersions[nVerNo];
+ rStream << pVer->_nVer << pVer->_nStart << pVer->_nEnd;
+ USHORT nCount = pVer->_nEnd - pVer->_nStart + 1;
+ USHORT nNewWhich = 0;
+ for ( USHORT n = 0; n < nCount; ++n )
+ {
+ nNewWhich = pVer->_pMap[n];
+ rStream << nNewWhich;
+ }
+
+ // Workaround gegen Bug in SetVersionMap der 312
+ if ( SOFFICE_FILEFORMAT_31 == _nFileFormatVersion )
+ rStream << USHORT(nNewWhich+1);
+ }
+ }
+
+ // gepoolte Items
+ {
+ SfxMultiMixRecordWriter aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS, 0 );
+
+ // erst Atomaren-Items und dann die Sets schreiben (wichtig beim Laden)
+ for ( pImp->bInSetItem = FALSE; pImp->bInSetItem <= TRUE && !rStream.GetError(); ++pImp->bInSetItem )
+ {
+ SfxPoolItemArray_Impl **pArr = pImp->ppPoolItems;
+ SfxPoolItem **ppDefItem = ppStaticDefaults;
+ const USHORT nSize = GetSize_Impl();
+ for ( USHORT i = 0; i < nSize && !rStream.GetError(); ++i, ++pArr, ++ppDefItem )
+ {
+ // Version des Items feststellen
+ USHORT nItemVersion = (*ppDefItem)->GetVersion( _nFileFormatVersion );
+ if ( USHRT_MAX == nItemVersion )
+ // => kam in zu exportierender Version gar nicht vor
+ continue;
+
+ // !poolable wird gar nicht im Pool gespeichert
+ // und itemsets/plain-items je nach Runde
+#ifdef TF_POOLABLE
+ if ( *pArr && IsItemFlag(**ppDefItem, SFX_ITEM_POOLABLE) &&
+#else
+ if ( *pArr && (*ppDefItem)->IsPoolable() &&
+#endif
+ pImp->bInSetItem == (*ppDefItem)->ISA(SfxSetItem) )
+ {
+ // eigene Kennung, globale Which-Id und Item-Version
+ USHORT nSlotId = GetSlotId( (*ppDefItem)->Which(), FALSE );
+ aWhichIdsRec.NewContent(nSlotId, 0);
+ rStream << (*ppDefItem)->Which();
+ rStream << nItemVersion;
+ const USHORT nCount = (*pArr)->Count();
+ DBG_ASSERT(nCount, "ItemArr ist leer");
+ rStream << nCount;
+
+ // Items an sich schreiben
+ SfxMultiMixRecordWriter aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS, 0 );
+ for ( USHORT j = 0; j < nCount; ++j )
+ {
+ // Item selbst besorgen
+ const SfxPoolItem *pItem = (*pArr)->GetObject(j);
+ if ( pItem && pItem->GetRefCount() ) //! siehe anderes MI-REF
+ {
+ aItemsRec.NewContent(j, 'X' );
+
+ if ( pItem->GetRefCount() == SFX_ITEMS_SPECIAL )
+ rStream << (USHORT) pItem->GetKind();
+ else
+ {
+ rStream << (USHORT) pItem->GetRefCount();
+ if( pItem->GetRefCount() > SFX_ITEMS_OLD_MAXREF )
+ rStream.SetError( ERRCODE_IO_NOTSTORABLEINBINARYFORMAT );
+ }
+
+ if ( !rStream.GetError() )
+ pItem->Store(rStream, nItemVersion);
+ else
+ break;
+#ifdef DBG_UTIL_MI
+ if ( !pItem->ISA(SfxSetItem) )
+ {
+ ULONG nMark = rStream.Tell();
+ rStream.Seek( nItemStartPos + sizeof(USHORT) );
+ SfxPoolItem *pClone = pItem->Create(rStream, nItemVersion );
+ USHORT nWh = pItem->Which();
+ SFX_ASSERT( rStream.Tell() == nMark, nWh,"asymmetric store/create" );
+ SFX_ASSERT( *pClone == *pItem, nWh, "unequal after store/create" );
+ delete pClone;
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+
+ pImp->bInSetItem = FALSE;
+ }
+
+ // die gesetzten Defaults speichern (Pool-Defaults)
+ if ( !rStream.GetError() )
+ {
+ SfxMultiMixRecordWriter aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS, 0 );
+ USHORT nCount = GetSize_Impl();
+ for ( USHORT n = 0; n < nCount; ++n )
+ {
+ const SfxPoolItem* pDefaultItem = ppPoolDefaults[n];
+ if ( pDefaultItem )
+ {
+ // Version ermitteln
+ USHORT nItemVersion = pDefaultItem->GetVersion( _nFileFormatVersion );
+ if ( USHRT_MAX == nItemVersion )
+ // => gab es in der Version noch nicht
+ continue;
+
+ // eigene Kennung, globale Kennung, Version
+ USHORT nSlotId = GetSlotId( pDefaultItem->Which(), FALSE );
+ aDefsRec.NewContent( nSlotId, 0 );
+ rStream << pDefaultItem->Which();
+ rStream << nItemVersion;
+
+ // Item an sich
+ pDefaultItem->Store( rStream, nItemVersion );
+ }
+ }
+ }
+
+ // weitere Pools rausschreiben
+ ImpSvlData::GetSvlData().pStoringPool = 0;
+ aPoolRec.Close();
+ if ( !rStream.GetError() && pSecondary )
+ pSecondary->Store( rStream );
+
+ pImp->bStreaming = FALSE;
+ return rStream;
+}
+
+// -----------------------------------------------------------------------
+
+void SfxItemPool::LoadCompleted()
+
+/* [Beschreibung]
+
+ Wurde der SfxItemPool mit 'bRefCounts' == FALSE geladen, mu\s das
+ Laden der Dokumentinhalte mit einem Aufruf dieser Methode beendet
+ werden. Ansonsten hat der Aufruf dieser Methode keine Funktion.
+
+
+ [Anmerkung]
+
+ Beim Laden ohne Ref-Counts werden diese tats"achlich auf 1 gesetzt,
+ damit nicht w"ahrend des Ladevorgangs SfxPoolItems gel"oscht werden,
+ die danach, aber auch noch beim Ladevorgang, ben"otigt werden. Diese
+ Methode setzt den Ref-Count wieder zur"uck und entfernt dabei
+ gleichzeitig alle nicht mehr ben"otigten Items.
+
+
+ [Querverweise]
+
+ <SfxItemPool::Load()>
+*/
+
+{
+ // wurden keine Ref-Counts mitgeladen?
+ if ( pImp->nInitRefCount > 1 )
+ {
+
+ // "uber alle Which-Werte iterieren
+ SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
+ for( USHORT nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr )
+ {
+ // ist "uberhaupt ein Item mit dem Which-Wert da?
+ if ( *ppItemArr )
+ {
+ // "uber alle Items mit dieser Which-Id iterieren
+ SfxPoolItem** ppHtArr = (SfxPoolItem**)(*ppItemArr)->GetData();
+ for( USHORT n = (*ppItemArr)->Count(); n; --n, ++ppHtArr )
+ if (*ppHtArr)
+ {
+ #ifdef DBG_UTIL
+ const SfxPoolItem &rItem = **ppHtArr;
+ DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
+ 0 != &((const SfxSetItem&)rItem).GetItemSet(),
+ "SetItem without ItemSet" );
+ #endif
+
+ if ( !ReleaseRef( **ppHtArr, 1 ) )
+ DELETEZ( *ppHtArr );
+ }
+ }
+ }
+
+ // from now on normal initial ref count
+ pImp->nInitRefCount = 1;
+ }
+
+ // notify secondary pool
+ if ( pSecondary )
+ pSecondary->LoadCompleted();
+}
+
+//============================================================================
+// This had to be moved to a method of its own to keep Solaris GCC happy:
+void SfxItemPool::readTheItems (
+ SvStream & rStream, USHORT nItemCount, USHORT nVersion,
+ SfxPoolItem * pDefItem, SfxPoolItemArray_Impl ** ppArr)
+{
+ SfxMultiRecordReader aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS );
+
+ SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl( nItemCount );
+ SfxPoolItem *pItem = 0;
+
+ USHORT n, nLastSurrogate = USHORT(-1);
+ while (aItemsRec.GetContent())
+ {
+ // n"achstes Surrogat holen
+ USHORT nSurrogate = aItemsRec.GetContentTag();
+ DBG_ASSERT( aItemsRec.GetContentVersion() == 'X',
+ "not an item content" );
+
+ // fehlende auff"ullen
+ for ( pItem = 0, n = nLastSurrogate+1; n < nSurrogate; ++n )
+ pNewArr->C40_INSERT(SfxPoolItem, pItem, n);
+ nLastSurrogate = nSurrogate;
+
+ // Ref-Count und Item laden
+ USHORT nRef;
+ rStream >> nRef;
+
+ pItem = pDefItem->Create(rStream, nVersion);
+ pNewArr->C40_INSERT(SfxPoolItem, pItem, nSurrogate);
+
+ if ( !bPersistentRefCounts )
+ // bis <SfxItemPool::LoadCompleted()> festhalten
+ AddRef(*pItem, 1);
+ else
+ {
+ if ( nRef > SFX_ITEMS_OLD_MAXREF )
+ pItem->SetKind( nRef );
+ else
+ AddRef(*pItem, nRef);
+ }
+ }
+
+ // fehlende auff"ullen
+ for ( pItem = 0, n = nLastSurrogate+1; n < nItemCount; ++n )
+ pNewArr->C40_INSERT(SfxPoolItem, pItem, n);
+
+ SfxPoolItemArray_Impl *pOldArr = *ppArr;
+ *ppArr = pNewArr;
+
+ // die Items merken, die schon im Pool sind
+ int bEmpty = TRUE;
+ if ( 0 != pOldArr )
+ for ( n = 0; bEmpty && n < pOldArr->Count(); ++n )
+ bEmpty = pOldArr->GetObject(n) == 0;
+ DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
+ if ( !bEmpty )
+ {
+ // f"ur alle alten suchen, ob ein gleiches neues existiert
+ for ( USHORT nOld = 0; nOld < pOldArr->Count(); ++nOld )
+ {
+ SfxPoolItem *pOldItem = (*pOldArr)[nOld];
+ if ( pOldItem )
+ {
+ USHORT nFree = USHRT_MAX;
+ int bFound = FALSE;
+ USHORT nCount = (*ppArr)->Count();
+ for ( USHORT nNew = nCount; !bFound && nNew--; )
+ {
+ // geladenes Item
+ SfxPoolItem *&rpNewItem =
+ (SfxPoolItem*&)(*ppArr)->GetData()[nNew];
+
+ // surrogat unbenutzt?
+ if ( !rpNewItem )
+ nFree = nNew;
+
+ // gefunden?
+ else if ( *rpNewItem == *pOldItem )
+ {
+ // wiederverwenden
+ AddRef( *pOldItem, rpNewItem->GetRefCount() );
+ SetRefCount( *rpNewItem, 0 );
+ delete rpNewItem;
+ rpNewItem = pOldItem;
+ bFound = TRUE;
+ }
+ }
+
+ // vorhervorhandene, nicht geladene uebernehmen
+ if ( !bFound )
+ {
+ if ( nFree != USHRT_MAX )
+ (SfxPoolItem*&)(*ppArr)->GetData()[nFree] = pOldItem;
+ else
+ (*ppArr)->C40_INSERT( SfxPoolItem, pOldItem, nCount );
+ }
+ }
+ }
+ }
+ delete pOldArr;
+}
+
+// -----------------------------------------------------------------------
+
+SvStream &SfxItemPool::Load(SvStream &rStream)
+{
+ DBG_CHKTHIS(SfxItemPool, 0);
+ DBG_ASSERT(ppStaticDefaults, "kein DefaultArray");
+
+ // protect items by increasing ref count
+ if ( !bPersistentRefCounts )
+ {
+
+ // "uber alle Which-Werte iterieren
+ SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
+ for( USHORT nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++ppItemArr )
+ {
+ // ist "uberhaupt ein Item mit dem Which-Wert da?
+ if ( *ppItemArr )
+ {
+ // "uber alle Items mit dieser Which-Id iterieren
+ SfxPoolItem** ppHtArr = (SfxPoolItem**)(*ppItemArr)->GetData();
+ for( USHORT n = (*ppItemArr)->Count(); n; --n, ++ppHtArr )
+ if (*ppHtArr)
+ {
+ #ifdef DBG_UTIL
+ const SfxPoolItem &rItem = **ppHtArr;
+ DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
+ 0 != &((const SfxSetItem&)rItem).GetItemSet(),
+ "SetItem without ItemSet" );
+ DBG_WARNING( "loading non-empty ItemPool" );
+ #endif
+
+ AddRef( **ppHtArr, 1 );
+ }
+ }
+ }
+
+ // during loading (until LoadCompleted()) protect all items
+ pImp->nInitRefCount = 2;
+ }
+
+ // Load-Master finden
+ SfxItemPool *pLoadMaster = pMaster != this ? pMaster : 0;
+ while ( pLoadMaster && !pLoadMaster->pImp->bStreaming )
+ pLoadMaster = pLoadMaster->pSecondary;
+
+ // Gesamt Header einlesen
+ pImp->bStreaming = TRUE;
+ if ( !pLoadMaster )
+ {
+ // Format-Version laden
+ CHECK_FILEFORMAT2( rStream,
+ SFX_ITEMPOOL_TAG_STARTPOOL_5, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
+ rStream >> pImp->nMajorVer >> pImp->nMinorVer;
+
+ // Format-Version in Master-Pool "ubertragen
+ pMaster->pImp->nMajorVer = pImp->nMajorVer;
+ pMaster->pImp->nMinorVer = pImp->nMinorVer;
+
+ // altes Format?
+ if ( pImp->nMajorVer < 2 )
+ // pImp->bStreaming wird von Load1_Impl() zur"uckgesetzt
+ return Load1_Impl( rStream );
+
+ // zu neues Format?
+ if ( pImp->nMajorVer > SFX_ITEMPOOL_VER_MAJOR )
+ {
+ rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Version 1.2-Trick-Daten "uberspringen
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_TRICK4OLD );
+ rStream.SeekRel( 4 ); // Hack-Daten wegen SfxStyleSheetPool-Bug skippen
+ }
+
+ // neues Record-orientiertes Format
+ SfxMiniRecordReader aPoolRec( &rStream, SFX_ITEMPOOL_REC );
+ if ( rStream.GetError() )
+ {
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Einzel-Header
+ int bOwnPool = TRUE;
+ UniString aExternName;
+ {
+ // Header-Record suchen
+ SfxMiniRecordReader aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER );
+ if ( rStream.GetError() )
+ {
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Header-lesen
+ rStream >> pImp->nLoadingVersion;
+ SfxPoolItem::readByteString(rStream, aExternName);
+ bOwnPool = aExternName == aName;
+
+ //! solange wir keine fremden Pools laden k"onnen
+ if ( !bOwnPool )
+ {
+ rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ aPoolRec.Skip();
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+ }
+
+ // Version-Maps
+ {
+ SfxMultiRecordReader aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP );
+ if ( rStream.GetError() )
+ {
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Versions-Maps einlesen
+ USHORT nOwnVersion = pImp->nVersion;
+ for ( USHORT nVerNo = 0; aVerRec.GetContent(); ++nVerNo )
+ {
+ // Header f"ur einzelne Version einlesen
+ USHORT nVersion, nHStart, nHEnd;
+ rStream >> nVersion >> nHStart >> nHEnd;
+ USHORT nCount = nHEnd - nHStart + 1;
+
+ // Version neuer als bekannt?
+ if ( nVerNo >= pImp->aVersions.Count() )
+ {
+ // neue Version hinzufuegen
+ USHORT *pMap = new USHORT[nCount];
+ for ( USHORT n = 0; n < nCount; ++n )
+ rStream >> pMap[n];
+ SetVersionMap( nVersion, nHStart, nHEnd, pMap );
+ }
+ }
+ pImp->nVersion = nOwnVersion;
+ }
+
+ // Items laden
+ FASTBOOL bSecondaryLoaded = FALSE;
+ long nSecondaryEnd = 0;
+ {
+ SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS);
+ while ( aWhichIdsRec.GetContent() )
+ {
+ // SlotId, Which-Id und Item-Version besorgen
+ USHORT nCount, nVersion, nWhich;
+ //!USHORT nSlotId = aWhichIdsRec.GetContentTag();
+ rStream >> nWhich;
+ if ( pImp->nLoadingVersion != pImp->nVersion )
+ // Which-Id aus File-Version in Pool-Version verschieben
+ nWhich = GetNewWhich( nWhich );
+
+ // unbekanntes Item aus neuerer Version
+ if ( !IsInRange(nWhich) )
+ continue;
+
+ rStream >> nVersion;
+ rStream >> nCount;
+ //!SFX_ASSERTWARNING( !nSlotId || !HasMap() ||
+ //! ( nSlotId == GetSlotId( nWhich, FALSE ) ) ||
+ //! !GetSlotId( nWhich, FALSE ),
+ //! nWhich, "Slot/Which mismatch" );
+
+ USHORT nIndex = GetIndex_Impl(nWhich);
+ SfxPoolItemArray_Impl **ppArr = pImp->ppPoolItems + nIndex;
+
+ // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten
+ SfxPoolItem *pDefItem = *(ppStaticDefaults + nIndex);
+ pImp->bInSetItem = pDefItem->ISA(SfxSetItem);
+ if ( !bSecondaryLoaded && pSecondary && pImp->bInSetItem )
+ {
+ // an das Ende des eigenen Pools seeken
+ ULONG nLastPos = rStream.Tell();
+ aPoolRec.Skip();
+
+ // Sekund"arpool einlesen
+ pSecondary->Load( rStream );
+ bSecondaryLoaded = TRUE;
+ nSecondaryEnd = rStream.Tell();
+
+ // zur"uck zu unseren eigenen Items
+ rStream.Seek(nLastPos);
+ }
+
+ // Items an sich lesen
+ readTheItems(rStream, nCount, nVersion, pDefItem, ppArr);
+
+ pImp->bInSetItem = FALSE;
+ }
+ }
+
+ // Pool-Defaults lesen
+ {
+ SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS );
+
+ while ( aDefsRec.GetContent() )
+ {
+ // SlotId, Which-Id und Item-Version besorgen
+ USHORT nVersion, nWhich;
+ //!USHORT nSlotId = aDefsRec.GetContentTag();
+ rStream >> nWhich;
+ if ( pImp->nLoadingVersion != pImp->nVersion )
+ // Which-Id aus File-Version in Pool-Version verschieben
+ nWhich = GetNewWhich( nWhich );
+
+ // unbekanntes Item aus neuerer Version
+ if ( !IsInRange(nWhich) )
+ continue;
+
+ rStream >> nVersion;
+ //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, FALSE ) ),
+ //! nWhich, "Slot/Which mismatch" );
+
+ // Pool-Default-Item selbst laden
+ SfxPoolItem *pItem =
+ ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
+ ->Create( rStream, nVersion );
+ pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
+ *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
+ }
+ }
+
+ // ggf. Secondary-Pool laden
+ aPoolRec.Skip();
+ if ( pSecondary )
+ {
+ if ( !bSecondaryLoaded )
+ pSecondary->Load( rStream );
+ else
+ rStream.Seek( nSecondaryEnd );
+ }
+
+ // wenn nicht own-Pool, dann kein Name
+ if ( aExternName != aName )
+ aName.Erase();
+
+ pImp->bStreaming = FALSE;
+ return rStream;
+};
+
+// -----------------------------------------------------------------------
+
+SvStream &SfxItemPool::Load1_Impl(SvStream &rStream)
+{
+ // beim Master ist der Header schon von <Load()> geladen worden
+ if ( !pImp->bStreaming )
+ {
+ // Header des Secondary lesen
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
+ rStream >> pImp->nMajorVer >> pImp->nMinorVer;
+ }
+ sal_uInt32 nAttribSize;
+ int bOwnPool = TRUE;
+ UniString aExternName;
+ if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 2 )
+ rStream >> pImp->nLoadingVersion;
+ SfxPoolItem::readByteString(rStream, aExternName);
+ bOwnPool = aExternName == aName;
+ pImp->bStreaming = TRUE;
+
+ //! solange wir keine fremden laden k"onnen
+ if ( !bOwnPool )
+ {
+ rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Versionen bis 1.3 k"onnen noch keine Which-Verschiebungen lesen
+ if ( pImp->nMajorVer == 1 && pImp->nMinorVer <= 2 &&
+ pImp->nVersion < pImp->nLoadingVersion )
+ {
+ rStream.SetError(ERRCODE_IO_WRONGVERSION);
+ pImp->bStreaming = FALSE;
+ return rStream;
+ }
+
+ // Size-Table liegt hinter den eigentlichen Attributen
+ rStream >> nAttribSize;
+
+ // Size-Table einlesen
+ ULONG nStartPos = rStream.Tell();
+ rStream.SeekRel( nAttribSize );
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_SIZES );
+ sal_uInt32 nSizeTableLen;
+ rStream >> nSizeTableLen;
+ sal_Char *pBuf = new sal_Char[nSizeTableLen];
+ rStream.Read( pBuf, nSizeTableLen );
+ ULONG nEndOfSizes = rStream.Tell();
+ SvMemoryStream aSizeTable( pBuf, nSizeTableLen, STREAM_READ );
+
+ // ab Version 1.3 steht in der Size-Table eine Versions-Map
+ if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 3 )
+ {
+ // Version-Map finden (letztes ULONG der Size-Table gibt Pos an)
+ rStream.Seek( nEndOfSizes - sizeof(sal_uInt32) );
+ sal_uInt32 nVersionMapPos;
+ rStream >> nVersionMapPos;
+ rStream.Seek( nVersionMapPos );
+
+ // Versions-Maps einlesen
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_VERSIONMAP );
+ USHORT nVerCount;
+ rStream >> nVerCount;
+ for ( USHORT nVerNo = 0; nVerNo < nVerCount; ++nVerNo )
+ {
+ // Header f"ur einzelne Version einlesen
+ USHORT nVersion, nHStart, nHEnd;
+ rStream >> nVersion >> nHStart >> nHEnd;
+ USHORT nCount = nHEnd - nHStart + 1;
+ USHORT nBytes = (nCount)*sizeof(USHORT);
+
+ // Version neuer als bekannt?
+ if ( nVerNo >= pImp->aVersions.Count() )
+ {
+ // neue Version hinzufuegen
+ USHORT *pMap = new USHORT[nCount];
+ for ( USHORT n = 0; n < nCount; ++n )
+ rStream >> pMap[n];
+ SetVersionMap( nVersion, nHStart, nHEnd, pMap );
+ }
+ else
+ // Version schon bekannt => "uberspringen
+ rStream.SeekRel( nBytes );
+ }
+ }
+
+ // Items laden
+ rStream.Seek( nStartPos );
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ITEMS );
+ FASTBOOL bSecondaryLoaded = FALSE;
+ long nSecondaryEnd = 0;
+ USHORT nWhich, nSlot;
+ while ( rStream >> nWhich, nWhich )
+ {
+ // ggf. Which-Id aus alter Version verschieben?
+ if ( pImp->nLoadingVersion != pImp->nVersion )
+ nWhich = GetNewWhich( nWhich );
+
+ rStream >> nSlot;
+ USHORT nMappedWhich = GetWhich(nSlot, FALSE);
+ int bKnownItem = bOwnPool || IsWhich(nMappedWhich);
+
+ USHORT nRef, nCount, nVersion;
+ sal_uInt32 nAttrSize;
+ rStream >> nVersion >> nCount;
+
+ SfxPoolItemArray_Impl **ppArr = 0;
+ SfxPoolItemArray_Impl *pNewArr = 0;
+ SfxPoolItem *pDefItem = 0;
+ if ( bKnownItem )
+ {
+ if ( !bOwnPool )
+ nWhich = nMappedWhich;
+
+ //!SFX_ASSERTWARNING( !nSlot || !HasMap() ||
+ //! ( nSlot == GetSlotId( nWhich, FALSE ) ) ||
+ //! !GetSlotId( nWhich, FALSE ),
+ //! nWhich, "Slot/Which mismatch" );
+
+ USHORT nIndex = GetIndex_Impl(nWhich);
+ ppArr = pImp->ppPoolItems + nIndex;
+ pNewArr = new SfxPoolItemArray_Impl( nCount );
+ pDefItem = *(ppStaticDefaults + nIndex);
+ }
+
+ // Position vor ersten Item merken
+ ULONG nLastPos = rStream.Tell();
+
+ // SfxSetItems k"onnten Items aus Sekund"arpools beinhalten
+ if ( !bSecondaryLoaded && pSecondary && pDefItem->ISA(SfxSetItem) )
+ {
+ // an das Ende des eigenen Pools seeken
+ rStream.Seek(nEndOfSizes);
+ CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr );
+ CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr );
+
+ // Sekund"arpool einlesen
+ pSecondary->Load1_Impl( rStream );
+ bSecondaryLoaded = TRUE;
+ nSecondaryEnd = rStream.Tell();
+
+ // zur"uck zu unseren eigenen Items
+ rStream.Seek(nLastPos);
+ }
+
+ // Items an sich lesen
+ for ( USHORT j = 0; j < nCount; ++j )
+ {
+ ULONG nPos = nLastPos;
+ rStream >> nRef;
+
+ if ( bKnownItem )
+ {
+ SfxPoolItem *pItem = 0;
+ if ( nRef )
+ {
+ pItem = pDefItem->Create(rStream, nVersion);
+
+ if ( !bPersistentRefCounts )
+ // bis <SfxItemPool::LoadCompleted()> festhalten
+ AddRef(*pItem, 1);
+ else
+ {
+ if ( nRef > SFX_ITEMS_OLD_MAXREF )
+ pItem->SetKind( nRef );
+ else
+ AddRef(*pItem, nRef);
+ }
+ }
+
+ pNewArr->C40_INSERT( SfxPoolItem, pItem, j);
+
+ // restliche gespeicherte Laenge skippen (neueres Format)
+ nLastPos = rStream.Tell();
+ }
+
+ aSizeTable >> nAttrSize;
+ SFX_ASSERT( !bKnownItem || ( nPos + nAttrSize) >= nLastPos,
+ nPos,
+ "too many bytes read - version mismatch?" );
+
+ if ( !bKnownItem || ( nLastPos < (nPos + nAttrSize) ) )
+ {
+ nLastPos = nPos + nAttrSize;
+ rStream.Seek( nLastPos );
+ }
+ }
+
+ if ( bKnownItem )
+ {
+ SfxPoolItemArray_Impl *pOldArr = *ppArr;
+ *ppArr = pNewArr;
+
+ // die Items merken, die schon im Pool sind
+ int bEmpty = TRUE;
+ if ( 0 != pOldArr )
+ for ( USHORT n = 0; bEmpty && n < pOldArr->Count(); ++n )
+ bEmpty = pOldArr->GetObject(n) == 0;
+ DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
+ if ( !bEmpty )
+ {
+ // f"ur alle alten suchen, ob ein gleiches neues existiert
+ for ( USHORT nOld = 0; nOld < pOldArr->Count(); ++nOld )
+ {
+ SfxPoolItem *pOldItem = (*pOldArr)[nOld];
+ if ( pOldItem )
+ {
+ int bFound = FALSE;
+ for ( USHORT nNew = 0;
+ !bFound && nNew < (*ppArr)->Count();
+ ++nNew )
+ {
+ SfxPoolItem *&rpNewItem =
+ (SfxPoolItem*&)(*ppArr)->GetData()[nNew];
+
+ if ( rpNewItem && *rpNewItem == *pOldItem )
+ {
+ AddRef( *pOldItem, rpNewItem->GetRefCount() );
+ SetRefCount( *rpNewItem, 0 );
+ delete rpNewItem;
+ rpNewItem = pOldItem;
+ bFound = TRUE;
+ SFX_TRACE( "reusing item", pOldItem );
+ }
+ }
+ //! DBG_ASSERT( bFound, "old-item not found in file" );
+ if ( !bFound )
+ {
+ SFX_TRACE( "item not found: ", pOldItem );
+ }
+ }
+ }
+ }
+ delete pOldArr; /* @@@ */
+ }
+ }
+
+ // Pool-Defaults lesen
+ if ( pImp->nMajorVer > 1 || pImp->nMinorVer > 0 )
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_DEFAULTS );
+
+ ULONG nLastPos = rStream.Tell();
+ while ( rStream >> nWhich, nWhich )
+ {
+ // ggf. Which-Id aus alter Version verschieben?
+ if ( pImp->nLoadingVersion != pImp->nVersion )
+ nWhich = GetNewWhich( nWhich );
+
+ rStream >> nSlot;
+ USHORT nMappedWhich = GetWhich(nSlot, FALSE);
+ int bKnownItem = bOwnPool || IsWhich(nMappedWhich);
+
+ ULONG nPos = nLastPos;
+ sal_uInt32 nSize;
+ USHORT nVersion;
+ rStream >> nVersion;
+
+ if ( bKnownItem )
+ {
+ if ( !bOwnPool )
+ nWhich = nMappedWhich;
+ SfxPoolItem *pItem =
+ ( *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
+ ->Create( rStream, nVersion );
+ pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
+ *( ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
+ }
+
+ nLastPos = rStream.Tell();
+ aSizeTable >> nSize;
+ SFX_ASSERT( ( nPos + nSize) >= nLastPos, nPos,
+ "too many bytes read - version mismatch?" );
+ if ( nLastPos < (nPos + nSize) )
+ rStream.Seek( nPos + nSize );
+ }
+
+ delete[] pBuf;
+ rStream.Seek(nEndOfSizes);
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
+ CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
+
+ if ( pSecondary )
+ {
+ if ( !bSecondaryLoaded )
+ pSecondary->Load1_Impl( rStream );
+ else
+ rStream.Seek( nSecondaryEnd );
+ }
+
+ if ( aExternName != aName )
+ aName.Erase();
+
+ pImp->bStreaming = FALSE;
+ return rStream;
+}
+
+// -----------------------------------------------------------------------
+
+const SfxPoolItem* SfxItemPool::LoadSurrogate
+(
+ SvStream& rStream, // vor einem Surrogat positionierter Stream
+ USHORT& rWhich, // Which-Id des zu ladenden <SfxPoolItem>s
+ USHORT nSlotId, // Slot-Id des zu ladenden <SfxPoolItem>s
+ const SfxItemPool* pRefPool // <SfxItemPool> in dem das Surrogat gilt
+)
+
+/* [Beschreibung]
+
+ L"adt Surrogat aus 'rStream' und liefert das dadurch in 'rRefPool'
+ repr"asentierte SfxPoolItem zu"ruck. Ist das im Stream befindliche
+ Surrogat == SFX_ITEMS_DIRECT (!SFX_ITEM_POOLABLE) wird 0 zur"uckgegeben,
+ das Item ist direkt aus dem Stream zu laden. Bei 0xfff0 (SFX_ITEMS_NULL)
+ wird auch 0 zurueckgegeben und rWhich auf 0 gesetzt, das Item ist nicht
+ verfuegbar.
+
+ Ansonsten wird ber"ucksichtigt, ob der betroffene Pool ohne Ref-Counts
+ geladen wird, ob aus einem neuen Pool nachgeladen wird (&rRefPool != this)
+ oder ob aus einem g"anzlich anders aufgebauten Pool geladen wird.
+
+ Wird aus einem anders aufgebauten Pool geladen und die 'nSlotId' kann
+ nicht in eine Which-Id dieses Pools gemappt werden, wird ebenfalls 0
+ zur"uckgeliefert.
+
+ Preconditions: - Pool mu\s geladen sein
+ - LoadCompleted darf noch nicht gerufen worden sein
+ - 'rStream' steht genau an der Position, an der ein
+ Surrogat f"ur ein Item mit der SlotId 'nSlotId' und
+ der WhichId 'rWhichId' mit StoreSurrogate gepeichert
+ wurde
+
+ Postconditions: - 'rStream' ist so positioniert, wie auch StoreSurrogate
+ sein speichern beendet hatte
+ - konnte ein Item geladen werden, befindet es sich
+ in diesem SfxItemPool
+ - 'rWhichId' enth"alt die ggf. gemappte Which-Id
+ Laufzeit: Tiefe des Ziel Sekund"arpools * 10 + 10
+
+ [Querverweise]
+
+ <SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const>
+*/
+
+{
+ // erstmal das Surrogat lesen
+ USHORT nSurrogat;
+ rStream >> nSurrogat;
+
+ // direkt gespeichertes Item?
+ if ( SFX_ITEMS_DIRECT == nSurrogat )
+ return 0;
+
+ // nicht vorhandenes Item?
+ if ( SFX_ITEMS_NULL == nSurrogat )
+ {
+ rWhich = 0;
+ return 0;
+ }
+
+ // Bei einem identisch aufgebauten Pool (im Stream) kann das Surrogat
+ // auf jeden Fall aufgel"ost werden.
+ if ( !pRefPool )
+ pRefPool = this;
+ FASTBOOL bResolvable = pRefPool->GetName().Len() > 0;
+ if ( !bResolvable )
+ {
+ // Bei einem anders aufgebauten Pool im Stream, mu\s die SlotId
+ // aus dem Stream in eine Which-Id gemappt werden k"onnen.
+ USHORT nMappedWhich = nSlotId ? GetWhich(nSlotId, TRUE) : 0;
+ if ( IsWhich(nMappedWhich) )
+ {
+ // gemappte SlotId kann "ubernommen werden
+ rWhich = nMappedWhich;
+ bResolvable = TRUE;
+ }
+ }
+
+ // kann Surrogat aufgel"ost werden?
+ const SfxPoolItem *pItem = 0;
+ if ( bResolvable )
+ {
+ for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pSecondary )
+ {
+ // richtigen (Folge-) Pool gefunden?
+ if ( pTarget->IsInRange(rWhich) )
+ {
+ // dflt-Attribut?
+ if ( SFX_ITEMS_STATICDEFAULT == nSurrogat )
+ return *(pTarget->ppStaticDefaults +
+ pTarget->GetIndex_Impl(rWhich));
+
+ SfxPoolItemArray_Impl* pItemArr = *(pTarget->pImp->ppPoolItems +
+ pTarget->GetIndex_Impl(rWhich));
+ pItem = pItemArr && nSurrogat < pItemArr->Count()
+ ? (*pItemArr)[nSurrogat]
+ : 0;
+ if ( !pItem )
+ {
+ DBG_ERROR( "can't resolve surrogate" );
+ rWhich = 0; // nur zur Sicherheit fuer richtige Stream-Pos
+ return 0;
+ }
+
+ // Nachladen aus Ref-Pool?
+ if ( pRefPool != pMaster )
+ return &pTarget->Put( *pItem );
+
+ // Referenzen sind NICHT schon mit Pool geladen worden?
+ if ( !pTarget->HasPersistentRefCounts() )
+ AddRef( *pItem, 1 );
+ else
+ return pItem;
+
+ return pItem;
+ }
+ }
+
+ SFX_ASSERT( FALSE, rWhich, "can't resolve Which-Id in LoadSurrogate" );
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+
+
+FASTBOOL SfxItemPool::StoreSurrogate
+(
+ SvStream& rStream,
+ const SfxPoolItem* pItem
+) const
+
+/* [Beschreibung]
+
+ Speichert ein Surrogat f"ur '*pItem' in 'rStream'.
+
+
+ [R"uckgabewert]
+
+ FASTBOOL TRUE
+ es wurde ein echtes Surrogat gespeichert, auch
+ SFX_ITEMS_NULL bei 'pItem==0',
+ SFX_ITEMS_STATICDEFAULT und SFX_ITEMS_POOLDEFAULT
+ gelten als 'echte' Surrogate
+
+ FALSE
+ es wurde ein Dummy-Surrogat (SFX_ITEMS_DIRECT)
+ gespeichert, das eigentliche Item mu\s direkt
+ hinterher selbst gespeichert werden
+*/
+
+{
+ if ( pItem )
+ {
+ FASTBOOL bRealSurrogate = IsItemFlag(*pItem, SFX_ITEM_POOLABLE);
+ rStream << ( bRealSurrogate
+ ? GetSurrogate( pItem )
+ : (UINT16) SFX_ITEMS_DIRECT );
+ return bRealSurrogate;
+ }
+
+ rStream << (UINT16) SFX_ITEMS_NULL;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const
+{
+ DBG_CHKTHIS(SfxItemPool, 0);
+ DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
+ DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
+ DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );
+
+ if ( !IsInRange(pItem->Which()) )
+ {
+ if ( pSecondary )
+ return pSecondary->GetSurrogate( pItem );
+ SFX_ASSERT( 0, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" );
+ }
+
+ // Pointer auf static- oder pool-dflt-Attribut?
+ if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
+ return SFX_ITEMS_STATICDEFAULT;
+
+ SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(pItem->Which()));
+ DBG_ASSERT(pItemArr, "ItemArr nicht vorhanden");
+ const USHORT nCount = pItemArr->Count();
+ for ( USHORT i = 0; i < nCount; ++i )
+ {
+ const SfxPoolItem *p = (*pItemArr)[i];
+ if ( p == pItem )
+ return i;
+ }
+ SFX_ASSERT( 0, pItem->Which(), "Item nicht im Pool");
+ return SFX_ITEMS_NULL;
+}
+
+// -----------------------------------------------------------------------
+
+FASTBOOL SfxItemPool::IsInStoringRange( USHORT nWhich ) const
+{
+ return nWhich >= pImp->nStoringStart &&
+ nWhich <= pImp->nStoringEnd;
+}
+
+//------------------------------------------------------------------------
+
+void SfxItemPool::SetStoringRange( USHORT nFrom, USHORT nTo )
+
+/* [Beschreibung]
+
+ Mit dieser Methode kann der Which-Bereich eingeengt werden, der
+ von ItemSets dieses Pool (und dem Pool selbst) gespeichert wird.
+ Die Methode muss dazu vor <SfxItemPool::Store()> gerufen werden
+ und die Werte muessen auch noch gesetzt sein, wenn das eigentliche
+ Dokument (also die ItemSets gespeicher werden).
+
+ Ein Zuruecksetzen ist dann nicht noetig, wenn dieser Range vor
+ JEDEM Speichern richtig gesetzt wird, da er nur beim Speichern
+ beruecksichtigt wird.
+
+ Dieses muss fuer das 3.1-Format gemacht werden, da dort eine
+ Bug in der Pool-Lade-Methode vorliegt.
+*/
+
+{
+ pImp->nStoringStart = nFrom;
+ pImp->nStoringEnd = nTo;
+}
+
+// -----------------------------------------------------------------------
+
+void SfxItemPool::SetVersionMap
+(
+ USHORT nVer, /* neue Versionsnummer */
+ USHORT nOldStart, /* alte erste Which-Id */
+ USHORT nOldEnd, /* alte letzte Which-Id */
+ USHORT* pOldWhichIdTab /* Array mit genau dem Aufbau der Which-Ids
+ der vorhergehenden Version, in denen
+ die jeweils neue Which-Id steht. */
+)
+
+/* [Beschreibung]
+
+ Mit dieser Methode k"onnen neue, inkompatible Which-Id-Folgen oder
+ Verteilungen realisiert werden. Pools, die noch mit alten Versionen
+ gespeichert wurden, werden dann "uber die angegebene Tabelle solange
+ gemappt, bis die aktuelle Version erreicht ist. Neuere Pools k"onnen
+ unter Verlust neuer Attribute geladen werden, da die Map mit dem Pool
+ gespeichert wird.
+
+ Precondition: Pool darf noch nicht geladen sein
+ Postcondition: Which-Ids aus fr"uheren Versionen k"onnen bei Laden auf
+ Version 'nVer' gemappt werden
+ Laufzeit: 1.5 * new + 10
+
+ [Anmerkung]
+
+ F"ur neue Which-Ranges (nStart,nEnd) m"ssen im Vergleich zur Vorg"anger-
+ Version (nOldStart,nOldEnd) immer gelten, da\s (nOldStart,nOldEnd)
+ vollst"andig in (nStart,nEnd) enthalten ist. Es ist also zul"assig, den
+ Which-Range in beide Richtungen zu erweitern, auch durch Einf"ugung
+ von Which-Ids, nicht aber ihn zu beschneiden.
+
+ Diese Methode sollte nur im oder direkt nach Aufruf des Konstruktors
+ gerufen werden.
+
+ Das Array mu\s statisch sein, da es nicht kopiert wird und au\serdem
+ im Copy-Ctor des SfxItemPool wiederverwendet wird.
+
+
+ [Beispiel]
+
+ Urspr"unglich (Version 0) hatte der Pool folgende Which-Ids:
+
+ 1:A, 2:B, 3:C, 4:D
+
+ Nun soll eine neue Version (Version 1) zwei zus"atzliche Ids X und Y
+ zwischen B und C erhalten, also wie folgt aussehen:
+
+ 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D
+
+ Dabei haben sich also die Ids 3 und 4 ge"andert. F"ur die neue Version
+ m"u\ste am Pool folgendes gesetzt werden:
+
+ static USHORT nVersion1Map = { 1, 2, 5, 6 };
+ pPool->SetVersionMap( 1, 1, 4, &nVersion1Map );
+
+
+ [Querverweise]
+
+ <SfxItemPool::IsLoadingVersionCurrent()const>
+ <SfxItemPool::GetNewWhich(USHORT)>
+ <SfxItemPool::GetVersion()const>
+ <SfxItemPool::GetLoadingVersion()const>
+*/
+
+{
+ // neuen Map-Eintrag erzeugen und einf"ugen
+ const SfxPoolVersion_Impl *pVerMap = new SfxPoolVersion_Impl(
+ nVer, nOldStart, nOldEnd, pOldWhichIdTab );
+ pImp->aVersions.Insert( pVerMap, pImp->aVersions.Count() );
+
+ DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" );
+ pImp->nVersion = nVer;
+
+ // Versions-Range anpassen
+ for ( USHORT n = 0; n < nOldEnd-nOldStart+1; ++n )
+ {
+ USHORT nWhich = pOldWhichIdTab[n];
+ if ( nWhich < pImp->nVerStart )
+ {
+ if ( !nWhich )
+ nWhich = 0;
+ pImp->nVerStart = nWhich;
+ }
+ else if ( nWhich > pImp->nVerEnd )
+ pImp->nVerEnd = nWhich;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SfxItemPool::GetNewWhich
+(
+ USHORT nFileWhich // die aus dem Stream geladene Which-Id
+) const
+
+/* [Beschreibung]
+
+ Diese Methoden rechnet Which-Ids aus einem File-Format in die der
+ aktuellen Pool-Version um. Ist das File-Format "alter, werden die vom
+ Pool-Entwickler mit SetVersion() gesetzten Tabellen verwendet,
+ ist das File-Format neuer, dann die aus dem File geladenen Tabellen.
+ Im letzteren Fall kann ggf. nicht jede Which-Id gemappt werden,
+ so da\s 0 zur"uckgeliefert wird.
+
+ Die Berechnung ist nur f"ur Which-Ids definiert, die in der betreffenden
+ File-Version unterst"utzt wurden. Dies ist per Assertion abgesichert.
+
+ Precondition: Pool mu\s geladen sein
+ Postcondition: unver"andert
+ Laufzeit: linear(Anzahl der Sekund"arpools) +
+ linear(Differenz zwischen alter und neuer Version)
+
+
+ [Querverweise]
+
+ <SfxItemPool::IsLoadingVersionCurrent()const>
+ <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
+ <SfxItemPool::GetVersion()const>
+ <SfxItemPool::GetLoadingVersion()const>
+*/
+
+{
+ // (Sekund"ar-) Pool bestimmen
+ if ( !IsInVersionsRange(nFileWhich) )
+ {
+ if ( pSecondary )
+ return pSecondary->GetNewWhich( nFileWhich );
+ SFX_ASSERT( 0, nFileWhich, "unknown which in GetNewWhich()" );
+ }
+
+ // Version neuer/gleich/"alter?
+ short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion;
+
+ // Which-Id einer neueren Version?
+ if ( nDiff > 0 )
+ {
+ // von der Top-Version bis runter zur File-Version stufenweise mappen
+ for ( USHORT nMap = pImp->aVersions.Count(); nMap > 0; --nMap )
+ {
+ SfxPoolVersion_Impl *pVerInfo = pImp->aVersions[nMap-1];
+ if ( pVerInfo->_nVer > pImp->nVersion )
+ { USHORT nOfs;
+ USHORT nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1;
+ for ( nOfs = 0;
+ nOfs <= nCount &&
+ pVerInfo->_pMap[nOfs] != nFileWhich;
+ ++nOfs )
+ continue;
+
+ if ( pVerInfo->_pMap[nOfs] == nFileWhich )
+ nFileWhich = pVerInfo->_nStart + nOfs;
+ else
+ return 0;
+ }
+ else
+ break;
+ }
+ }
+
+ // Which-Id einer neueren Version?
+ else if ( nDiff < 0 )
+ {
+ // von der File-Version bis zur aktuellen Version stufenweise mappen
+ for ( USHORT nMap = 0; nMap < pImp->aVersions.Count(); ++nMap )
+ {
+ SfxPoolVersion_Impl *pVerInfo = pImp->aVersions[nMap];
+ if ( pVerInfo->_nVer > pImp->nLoadingVersion )
+ {
+ DBG_ASSERT( nFileWhich >= pVerInfo->_nStart &&
+ nFileWhich <= pVerInfo->_nEnd,
+ "which-id unknown in version" );
+ nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart];
+ }
+ }
+ }
+
+ // originale (nDiff==0) bzw. gemappte (nDiff!=0) Id zur"uckliefern
+ return nFileWhich;
+}
+
+// -----------------------------------------------------------------------
+
+
+FASTBOOL SfxItemPool::IsInVersionsRange( USHORT nWhich ) const
+{
+ return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd;
+}
+
+// -----------------------------------------------------------------------
+
+FASTBOOL SfxItemPool::IsCurrentVersionLoading() const
+
+/* [Beschreibung]
+
+ Mit dieser Methode kann festgestellt werden, ob die geladene Pool-Version
+ dem aktuellen Pool-Aufbau entspricht.
+
+ Precondition: Pool mu\s geladen sein
+ Postcondition: unver"andert
+ Laufzeit: linear(Anzahl der Sekund"arpools)
+
+
+ [Querverweise]
+
+ <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
+ <SfxItemPool::GetNewWhich(USHORT)const>
+ <SfxItemPool::GetVersion()const>
+ <SfxItemPool::GetLoadingVersion()const>
+*/
+
+{
+ return ( pImp->nVersion == pImp->nLoadingVersion ) &&
+ ( !pSecondary || pSecondary->IsCurrentVersionLoading() );
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SfxItemPool::GetVersion() const
+
+/* [Beschreibung]
+
+ Diese Methode liefert die aktuelle Versionsnummer des SfxItemPool-Aufbaus
+ (also des Which-Bereichs).
+
+ Precondition: keine
+ Postcondition: unver"andert
+ Laufzeit: 2
+
+
+ [Anmerkung]
+
+ Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools
+ ber"ucksichtigt werden.
+
+
+ [Querverweise]
+
+ <SfxItemPool::IsLoadingVersionCurrent()const>
+ <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
+ <SfxItemPool::GetNewWhich(USHORT)const>
+ <SfxItemPool::GetLoadingVersion()const>
+*/
+
+{
+ return pImp->nVersion;
+}
+
+// -----------------------------------------------------------------------
+
+USHORT SfxItemPool::GetLoadingVersion() const
+
+/* [Beschreibung]
+
+ Diese Methode liefert die Versionsnummer des SfxItemPool-Aufbaus
+ (also des Which-Bereichs), die bei Laden vorgefunden wurde.
+
+ Precondition: Pool mu\s geladen sein
+ Postcondition: unver"andert
+ Laufzeit: 2
+
+
+ [Anmerkung]
+
+ Achtung: Es mu\s ggf. die Versionsnummer von Sekund"arpools
+ ber"ucksichtigt werden.
+
+
+ [Querverweise]
+
+ <SfxItemPool::IsLoadingVersionCurrent()const>
+ <SfxItemPool::SetVersionMap(USHORT,USHORT,USHORT,USHORT*)>
+ <SfxItemPool::GetNewWhich(USHORT)const>
+ <SfxItemPool::GetVersion()const>
+*/
+
+{
+ return pImp->nLoadingVersion;
+}
+
+//-------------------------------------------------------------------------
+
+FASTBOOL SfxItemPool::IsVer2_Impl() const
+{
+ return pMaster->pImp->nMajorVer >= 2;
+}
+
+//-------------------------------------------------------------------------
+
+
+FASTBOOL SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem,
+ FASTBOOL bDirect ) const
+
+/* [Beschreibung]
+
+ Speichert das <SfxPoolItem> 'rItem' in den <SvStream> 'rStream'
+ entweder als Surrogat ('bDirect == FALSE') oder direkt mit 'rItem.Store()'.
+ Nicht poolable Items werden immer direkt gespeichert. Items ohne Which-Id,
+ also SID-Items, werden nicht gespeichert, ebenso wenn Items, die in der
+ File-Format-Version noch nicht vorhanden waren (return FALSE).
+
+ Das Item wird im Stream wie folgt abgelegt:
+
+ USHORT rItem.Which()
+ USHORT GetSlotId( rItem.Which() ) bzw. 0 falls nicht verf"urbar
+ USHORT GetSurrogate( &rItem ) bzw. SFX_ITEM_DIRECT bei '!SFX_ITEM_POOLBLE'
+
+ optional (falls 'bDirect == TRUE' oder '!rItem.IsPoolable()':
+
+ USHORT rItem.GetVersion()
+ ULONG Size
+ Size rItem.Store()
+
+
+ [Querverweise]
+
+ <SfxItemPool::LoadItem(SvStream&,FASTBOOL)const>
+*/
+
+{
+ DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" );
+
+ if ( IsSlot( rItem.Which() ) )
+ return FALSE;
+ const SfxItemPool *pPool = this;
+ while ( !pPool->IsInStoringRange(rItem.Which()) )
+ if ( 0 == ( pPool = pPool->pSecondary ) )
+ return FALSE;
+
+ DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem),
+ "SetItem contains ItemSet with SetItem" );
+
+ USHORT nSlotId = pPool->GetSlotId( rItem.Which(), TRUE );
+ USHORT nItemVersion = rItem.GetVersion(_nFileFormatVersion);
+ if ( USHRT_MAX == nItemVersion )
+ return FALSE;
+
+ rStream << rItem.Which() << nSlotId;
+ if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) )
+ {
+ rStream << nItemVersion;
+ rStream << (UINT32) 0L; // Platz fuer Laenge in Bytes
+ ULONG nIStart = rStream.Tell();
+ rItem.Store(rStream, nItemVersion);
+ ULONG nIEnd = rStream.Tell();
+ rStream.Seek( nIStart-4 );
+ rStream << (INT32) ( nIEnd-nIStart );
+ rStream.Seek( nIEnd );
+ }
+
+ return TRUE;
+}
+
+//-------------------------------------------------------------------------
+
+
+const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, FASTBOOL bDirect,
+ const SfxItemPool *pRefPool )
+
+// pRefPool==-1 => nicht putten!
+
+{
+ USHORT nWhich, nSlot; // nSurrogate;
+ rStream >> nWhich >> nSlot;
+
+ BOOL bDontPut = (SfxItemPool*)-1 == pRefPool;
+ if ( bDontPut || !pRefPool )
+ pRefPool = this;
+
+ // richtigen Sekund"ar-Pool finden
+ while ( !pRefPool->IsInVersionsRange(nWhich) )
+ {
+ if ( pRefPool->pSecondary )
+ pRefPool = pRefPool->pSecondary;
+ else
+ {
+ // WID in der Version nicht vorhanden => ueberspringen
+ USHORT nSurro, nVersion, nLen;
+ rStream >> nSurro;
+ if ( SFX_ITEMS_DIRECT == nSurro )
+ {
+ rStream >> nVersion >> nLen;
+ rStream.SeekRel( nLen );
+ }
+ return 0;
+ }
+ }
+
+ // wird eine andere Version geladen?
+ FASTBOOL bCurVersion = pRefPool->IsCurrentVersionLoading();
+ if ( !bCurVersion )
+ // Which-Id auf neue Version mappen
+ nWhich = pRefPool->GetNewWhich( nWhich );
+
+ DBG_ASSERT( !nWhich || !pImp->bInSetItem ||
+ !pRefPool->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem),
+ "loading SetItem in ItemSet of SetItem" );
+
+ // soll "uber Surrogat geladen werden?
+ const SfxPoolItem *pItem = 0;
+ if ( !bDirect )
+ {
+ // Which-Id in dieser Version bekannt?
+ if ( nWhich )
+ // Surrogat laden, reagieren falls keins vorhanden
+ pItem = LoadSurrogate( rStream, nWhich, nSlot, pRefPool );
+ else
+ // sonst "uberspringen
+ rStream.SeekRel( sizeof(USHORT) );
+ }
+
+ // wird direkt, also nicht "uber Surrogat geladen?
+ if ( bDirect || ( nWhich && !pItem ) )
+ {
+ // bDirekt bzw. nicht IsPoolable() => Item direkt laden
+ USHORT nVersion;
+ sal_uInt32 nLen;
+ rStream >> nVersion >> nLen;
+ ULONG nIStart = rStream.Tell();
+
+ // Which-Id in dieser Version bekannt?
+ if ( nWhich )
+ {
+ // Item direkt laden
+ SfxPoolItem *pNewItem =
+ pRefPool->GetDefaultItem(nWhich).Create(rStream, nVersion);
+ if ( bDontPut )
+ pItem = pNewItem;
+ else
+ if ( pNewItem )
+ {
+ pItem = &Put(*pNewItem);
+ delete pNewItem;
+ }
+ else
+ pItem = 0;
+ ULONG nIEnd = rStream.Tell();
+ DBG_ASSERT( nIEnd <= (nIStart+nLen), "read past end of item" );
+ if ( (nIStart+nLen) != nIEnd )
+ rStream.Seek( nIStart+nLen );
+ }
+ else
+ // Item "uberspringen
+ rStream.Seek( nIStart+nLen );
+ }
+
+ return pItem;
+}
+
+