Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <string.h>
22 : #include <stdio.h>
23 :
24 : #include <sal/log.hxx>
25 : #include <tools/solar.h>
26 : #include <svl/itempool.hxx>
27 : #include "whassert.hxx"
28 : #include <svl/SfxBroadcaster.hxx>
29 : #include <svl/filerec.hxx>
30 : #include "poolio.hxx"
31 : #include <boost/scoped_ptr.hpp>
32 : #include <boost/scoped_array.hpp>
33 :
34 : /**
35 : * Returns the <SfxItemPool> that is being saved.
36 : * This should only be used in very exceptional cases e.g.
37 : * when guaranteeing file format compatibility:
38 : * When overloading a <SfxPoolItem::Store()> getting additional data from the Pool
39 : */
40 0 : const SfxItemPool* SfxItemPool::GetStoringPool()
41 : {
42 0 : return pStoringPool_;
43 : }
44 :
45 0 : static sal_uInt16 convertSfxItemKindToUInt16(SfxItemKind x)
46 : {
47 0 : if ( x == SFX_ITEMS_NONE )
48 0 : return 0;
49 0 : if ( x == SFX_ITEMS_DELETEONIDLE )
50 0 : return 0xfffd;
51 0 : if ( x == SFX_ITEMS_STATICDEFAULT )
52 0 : return 0xfffe;
53 0 : if ( x == SFX_ITEMS_POOLDEFAULT )
54 0 : return 0xffff;
55 : assert(false);
56 0 : abort();
57 : }
58 :
59 0 : static SfxItemKind convertUInt16ToSfxItemKind(sal_uInt16 x)
60 : {
61 0 : if ( x == 0 )
62 0 : return SFX_ITEMS_NONE;
63 0 : if ( x == 0xfffd )
64 0 : return SFX_ITEMS_DELETEONIDLE;
65 0 : if ( x == 0xfffe )
66 0 : return SFX_ITEMS_STATICDEFAULT;
67 0 : if ( x == 0xffff )
68 0 : return SFX_ITEMS_POOLDEFAULT;
69 : assert(false);
70 0 : abort();
71 : }
72 :
73 :
74 :
75 : /**
76 : * The SfxItemPool is saved to the specified Stream (together with all its
77 : * secondary Pools) using its Pool Defaults and pooled Items.
78 : * The static defaults are not saved.
79 : * [Fileformat]
80 : *
81 : * ;First, a compatibility header section
82 : * Start: 0x1111 SFX_ITEMPOOL_TAG_STARTPOOLS(_4/_5)
83 : * sal_uInt8 MAJOR_VER ;SfxItemPool version
84 : * sal_uInt8 MINOR_VER ;"
85 : * 0xFFFF SFX_ITEMPOOL_TAG_TRICK4OLD ;ex. GetVersion()
86 : * sal_uInt16 0x0000 ;Pseudo StyleSheetPool
87 : * sal_uInt16 0x0000 ;Pseudo StyleSheetPool
88 : *
89 : * ;The whole Pool into a record
90 : * record SfxMiniRecod(SFX_ITEMPOOL_REC)
91 : *
92 : * ;Start with a Header for each
93 : * Header: record SfxMiniRecord(SFX_ITEMPOOL_REC_HEADER)
94 : * sal_uInt16 GetVersion() ;Which-Ranges etc.
95 : * String GetName() ;Pool name
96 : *
97 : * ;The version map: in order to be able to map WhichIds of new file version
98 : * Versions: record SfxMultiRecord(SFX_ITEMPOOL_REC_VERSIONS, 0)
99 : * sal_uInt16 OldVersion
100 : * sal_uInt16 OldStartWhich
101 : * sal_uInt16 OldEndWhich
102 : * sal_uInt16[] NewWhich (OldEndWhich-OldStartWhich+1)
103 : *
104 : * ;Now the pooled Items (first the non-SfxSetItems)
105 : * Items: record SfxMultiRecord(SFX_ITEMPOOL_REC_WHICHIDS, 0)
106 : * content SlotId, 0
107 : * sal_uInt16 WhichId
108 : * sal_uInt16 pItem->GetVersion()
109 : * sal_uInt16 Array-Size
110 : * record SfxMultiRecord(SFX_, 0)
111 : * content Surrogate
112 : * sal_uInt16 RefCount
113 : * unknown pItem->Store()
114 : *
115 : * ;Now the set Pool defaults
116 : * Defaults: record SfxMultiRecord(SFX_ITEMPOOL_REC_DEFAULTS, 0)
117 : * content SlotId, 0
118 : * sal_uInt16 WhichId
119 : * sal_uInt16 pPoolDef->GetVersion()
120 : * unknown pPoolDef->Store();
121 : *
122 : * ;Hereafter the secondary follows (if present) without compatibility header section
123 : */
124 10704 : SvStream &SfxItemPool::Store(SvStream &rStream) const
125 : {
126 : // Find StoreMaster
127 10704 : SfxItemPool *pStoreMaster = pImp->mpMaster != this ? pImp->mpMaster : 0;
128 21408 : while ( pStoreMaster && !pStoreMaster->pImp->bStreaming )
129 0 : pStoreMaster = pStoreMaster->pImp->mpSecondary;
130 :
131 : // Old header (version of the Pool and content version is 0xffff by default)
132 10704 : pImp->bStreaming = true;
133 10704 : if ( !pStoreMaster )
134 : {
135 10704 : rStream.WriteUInt16( rStream.GetVersion() >= SOFFICE_FILEFORMAT_50
136 : ? SFX_ITEMPOOL_TAG_STARTPOOL_5
137 10704 : : SFX_ITEMPOOL_TAG_STARTPOOL_4 );
138 10704 : rStream.WriteUInt8( SFX_ITEMPOOL_VER_MAJOR ).WriteUInt8( SFX_ITEMPOOL_VER_MINOR );
139 10704 : rStream.WriteUInt16( SFX_ITEMPOOL_TAG_TRICK4OLD );
140 :
141 : // Work around SfxStyleSheet bug
142 10704 : rStream.WriteUInt16( 0 ); // Version
143 10704 : rStream.WriteUInt16( 0 ); // Count (or else 2nd loop breaks)
144 : }
145 :
146 : // Every Pool as a whole is a record
147 10704 : SfxMiniRecordWriter aPoolRec( &rStream, SFX_ITEMPOOL_REC );
148 10704 : pStoringPool_ = this;
149 :
150 : // Single header (content version and name)
151 : {
152 10704 : SfxMiniRecordWriter aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER);
153 10704 : rStream.WriteUInt16( pImp->nVersion );
154 10704 : writeByteString(rStream, pImp->aName);
155 : }
156 :
157 : // VersionMaps
158 : {
159 10704 : SfxMultiVarRecordWriter aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP, 0 );
160 74928 : for ( size_t nVerNo = 0; nVerNo < pImp->aVersions.size(); ++nVerNo )
161 : {
162 64224 : aVerRec.NewContent();
163 64224 : SfxPoolVersion_ImplPtr pVer = pImp->aVersions[nVerNo];
164 64224 : rStream.WriteUInt16( pVer->_nVer ).WriteUInt16( pVer->_nStart ).WriteUInt16( pVer->_nEnd );
165 64224 : sal_uInt16 nCount = pVer->_nEnd - pVer->_nStart + 1;
166 64224 : sal_uInt16 nNewWhich = 0;
167 1990944 : for ( sal_uInt16 n = 0; n < nCount; ++n )
168 : {
169 1926720 : nNewWhich = pVer->_pMap[n];
170 1926720 : rStream.WriteUInt16( nNewWhich );
171 : }
172 :
173 : // Workaround for bug in SetVersionMap 312
174 64224 : if ( SOFFICE_FILEFORMAT_31 == pImp->mnFileFormatVersion )
175 0 : rStream.WriteUInt16( nNewWhich+1 );
176 74928 : }
177 : }
178 :
179 : // Pooled Items
180 : {
181 10704 : SfxMultiMixRecordWriter aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS, 0 );
182 :
183 : // First write the atomic Items and then write the Sets (important when loading)
184 32112 : for (int ft = 0 ; ft < 2 && !rStream.GetError(); ft++)
185 : {
186 21408 : pImp->bInSetItem = ft != 0;
187 :
188 21408 : std::vector<SfxPoolItemArray_Impl*>::iterator itrArr = pImp->maPoolItems.begin();
189 21408 : SfxPoolItem **ppDefItem = pImp->ppStaticDefaults;
190 21408 : const sal_uInt16 nSize = GetSize_Impl();
191 1198848 : for ( size_t i = 0; i < nSize && !rStream.GetError(); ++i, ++itrArr, ++ppDefItem )
192 : {
193 : // Get version of the Item
194 1177440 : sal_uInt16 nItemVersion = (*ppDefItem)->GetVersion( pImp->mnFileFormatVersion );
195 1177440 : if ( USHRT_MAX == nItemVersion )
196 : // => Was not present in the version that was supposed to be exported
197 42816 : continue;
198 :
199 : // ! Poolable is not even saved in the Pool
200 : // And itemsets/plain-items depending on the round
201 1171160 : if ( *itrArr && IsItemFlag(**ppDefItem, SFX_ITEM_POOLABLE) &&
202 36536 : pImp->bInSetItem == (bool) (*ppDefItem)->ISA(SfxSetItem) )
203 : {
204 : // Own signature, global WhichId and ItemVersion
205 18268 : sal_uInt16 nSlotId = GetSlotId( (*ppDefItem)->Which(), false );
206 18268 : aWhichIdsRec.NewContent(nSlotId, 0);
207 18268 : rStream.WriteUInt16( (*ppDefItem)->Which() );
208 18268 : rStream.WriteUInt16( nItemVersion );
209 18268 : const sal_uInt32 nCount = ::std::min<size_t>( (*itrArr)->size(), SAL_MAX_UINT32 );
210 : DBG_ASSERT(nCount, "ItemArr is empty");
211 18268 : rStream.WriteUInt32( nCount );
212 :
213 : // Write Items
214 18268 : SfxMultiMixRecordWriter aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS, 0 );
215 38352 : for ( size_t j = 0; j < nCount; ++j )
216 : {
217 : // Get Item
218 20084 : const SfxPoolItem *pItem = (*itrArr)->operator[](j);
219 20084 : if ( pItem && pItem->GetRefCount() ) //! See other MI-REF
220 : {
221 20084 : aItemsRec.NewContent((sal_uInt16)j, 'X' );
222 :
223 20084 : if ( pItem->GetRefCount() == SFX_ITEMS_SPECIAL )
224 0 : rStream.WriteUInt16( convertSfxItemKindToUInt16(pItem->GetKind()) );
225 : else
226 : {
227 20084 : rStream.WriteUInt16( pItem->GetRefCount() );
228 20084 : if( pItem->GetRefCount() > SFX_ITEMS_OLD_MAXREF )
229 0 : rStream.SetError( ERRCODE_IO_NOTSTORABLEINBINARYFORMAT );
230 : }
231 :
232 20084 : if ( !rStream.GetError() )
233 20084 : pItem->Store(rStream, nItemVersion);
234 : else
235 0 : break;
236 : #ifdef DBG_UTIL_MI
237 : if ( !pItem->ISA(SfxSetItem) )
238 : {
239 : sal_uLong nMark = rStream.Tell();
240 : rStream.Seek( nItemStartPos + sizeof(sal_uInt16) );
241 : boost::scoped_ptr<SfxPoolItem> pClone(pItem->Create(rStream, nItemVersion ));
242 : sal_uInt16 nWh = pItem->Which();
243 : SFX_ASSERT( rStream.Tell() == nMark, nWh,"asymmetric store/create" );
244 : SFX_ASSERT( *pClone == *pItem, nWh, "unequal after store/create" );
245 : }
246 : #endif
247 : }
248 18268 : }
249 : }
250 : }
251 : }
252 :
253 10704 : pImp->bInSetItem = false;
254 : }
255 :
256 : // Save the set Defaults (PoolDefaults)
257 10704 : if ( !rStream.GetError() )
258 : {
259 10704 : SfxMultiMixRecordWriter aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS, 0 );
260 10704 : sal_uInt16 nCount = GetSize_Impl();
261 599424 : for ( sal_uInt16 n = 0; n < nCount; ++n )
262 : {
263 588720 : const SfxPoolItem* pDefaultItem = pImp->ppPoolDefaults[n];
264 588720 : if ( pDefaultItem )
265 : {
266 : // Get version
267 0 : sal_uInt16 nItemVersion = pDefaultItem->GetVersion( pImp->mnFileFormatVersion );
268 0 : if ( USHRT_MAX == nItemVersion )
269 : // => Was not present in the version yet
270 0 : continue;
271 :
272 : // Own signature, global signature, version
273 0 : sal_uInt16 nSlotId = GetSlotId( pDefaultItem->Which(), false );
274 0 : aDefsRec.NewContent( nSlotId, 0 );
275 0 : rStream.WriteUInt16( pDefaultItem->Which() );
276 0 : rStream.WriteUInt16( nItemVersion );
277 :
278 : // Item
279 0 : pDefaultItem->Store( rStream, nItemVersion );
280 : }
281 10704 : }
282 : }
283 :
284 : // Write out additional Pools
285 10704 : pStoringPool_ = 0;
286 10704 : aPoolRec.Close();
287 10704 : if ( !rStream.GetError() && pImp->mpSecondary )
288 0 : pImp->mpSecondary->Store( rStream );
289 :
290 10704 : pImp->bStreaming = false;
291 10704 : return rStream;
292 : }
293 :
294 0 : bool SfxItemPool::HasPersistentRefCounts() const
295 : {
296 0 : return pImp->mbPersistentRefCounts;
297 : }
298 :
299 : /**
300 : * If the SfxItemPool was loaded with 'bRefCounts' == sal_False, we need
301 : * to finish the loading of the document contents with a call of this method.
302 : * In any other case calling this function has no meaning.
303 : *
304 : * When loading without RefCounts, they are actually set to 1 so that
305 : * SfxPoolItems that are needed during and after loading are not deleted.
306 : * This method resets the RefCount and also removes all items that are not
307 : * needed anymore.
308 : *
309 : * @see SfxItemPool::Load()
310 : */
311 0 : void SfxItemPool::LoadCompleted()
312 : {
313 : // Did we load without RefCounts?
314 0 : if ( pImp->nInitRefCount > 1 )
315 : {
316 : // Iterate over all Which values
317 0 : std::vector<SfxPoolItemArray_Impl*>::iterator itrItemArr = pImp->maPoolItems.begin();
318 0 : for( sal_uInt16 nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++itrItemArr )
319 : {
320 : // Is there an item with the Which value present at all?
321 0 : if ( *itrItemArr )
322 : {
323 : // Iterate over all items with this WhichId
324 0 : SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*itrItemArr)->begin();
325 0 : for( size_t n = (*itrItemArr)->size(); n; --n, ++ppHtArr )
326 : {
327 0 : if (*ppHtArr)
328 : {
329 0 : if ( !ReleaseRef( **ppHtArr, 1 ) )
330 0 : DELETEZ( *ppHtArr );
331 : }
332 : }
333 0 : (*itrItemArr)->ReHash();
334 : }
335 : }
336 :
337 : // from now on normal initial ref count
338 0 : pImp->nInitRefCount = 1;
339 : }
340 :
341 : // notify secondary pool
342 0 : if ( pImp->mpSecondary )
343 0 : pImp->mpSecondary->LoadCompleted();
344 0 : }
345 :
346 38767 : sal_uInt16 SfxItemPool::GetFirstWhich() const
347 : {
348 38767 : return pImp->mnStart;
349 : }
350 :
351 1876735 : sal_uInt16 SfxItemPool::GetLastWhich() const
352 : {
353 1876735 : return pImp->mnEnd;
354 : }
355 :
356 239519760 : bool SfxItemPool::IsInRange( sal_uInt16 nWhich ) const
357 : {
358 239519760 : return nWhich >= pImp->mnStart && nWhich <= pImp->mnEnd;
359 : }
360 :
361 : // This had to be moved to a method of its own to keep Solaris GCC happy:
362 0 : void SfxItemPool_Impl::readTheItems (
363 : SvStream & rStream, sal_uInt32 nItemCount, sal_uInt16 nVer,
364 : SfxPoolItem * pDefItem, SfxPoolItemArray_Impl ** ppArr)
365 : {
366 0 : SfxMultiRecordReader aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS );
367 :
368 0 : SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl();
369 0 : SfxPoolItem *pItem = 0;
370 :
371 0 : sal_uLong n, nLastSurrogate = sal_uLong(-1);
372 0 : while (aItemsRec.GetContent())
373 : {
374 : // Get next surrogate
375 0 : sal_uInt16 nSurrogate = aItemsRec.GetContentTag();
376 : DBG_ASSERT( aItemsRec.GetContentVersion() == 'X',
377 : "not an item content" );
378 :
379 : // Fill up missing ones
380 0 : for ( pItem = 0, n = nLastSurrogate+1; n < nSurrogate; ++n )
381 0 : pNewArr->push_back( (SfxPoolItem*) pItem );
382 0 : nLastSurrogate = nSurrogate;
383 :
384 : // Load RefCount and Item
385 0 : sal_uInt16 nRef(0);
386 0 : rStream.ReadUInt16( nRef );
387 :
388 0 : pItem = pDefItem->Create(rStream, nVer);
389 0 : pNewArr->push_back( (SfxPoolItem*) pItem );
390 :
391 0 : if ( !mbPersistentRefCounts )
392 : // Hold onto it until SfxItemPool::LoadCompleted()
393 0 : SfxItemPool::AddRef(*pItem, 1);
394 : else
395 : {
396 0 : if ( nRef > SFX_ITEMS_OLD_MAXREF )
397 0 : SfxItemPool::SetKind(*pItem, convertUInt16ToSfxItemKind(nRef));
398 : else
399 0 : SfxItemPool::AddRef(*pItem, nRef);
400 : }
401 : }
402 :
403 : // Fill up missing ones
404 0 : for ( pItem = 0, n = nLastSurrogate+1; n < nItemCount; ++n )
405 0 : pNewArr->push_back( (SfxPoolItem*) pItem );
406 :
407 0 : SfxPoolItemArray_Impl *pOldArr = *ppArr;
408 0 : *ppArr = pNewArr;
409 :
410 : // Remember items that are already in the pool
411 0 : bool bEmpty = true;
412 0 : if ( 0 != pOldArr )
413 0 : for ( n = 0; bEmpty && n < pOldArr->size(); ++n )
414 0 : bEmpty = pOldArr->operator[](n) == 0;
415 : DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
416 0 : if ( !bEmpty )
417 : {
418 : // See if there's a new one for all old ones
419 0 : for ( size_t nOld = 0; nOld < pOldArr->size(); ++nOld )
420 : {
421 0 : SfxPoolItem *pOldItem = (*pOldArr)[nOld];
422 0 : if ( pOldItem )
423 : {
424 0 : sal_uInt32 nFree = SAL_MAX_UINT32;
425 0 : bool bFound = false;
426 0 : for ( size_t nNew = (*ppArr)->size(); nNew--; )
427 : {
428 : // Loaded Item
429 : SfxPoolItem *&rpNewItem =
430 0 : (SfxPoolItem*&)(*ppArr)->operator[](nNew);
431 :
432 : // Unused surrogate?
433 0 : if ( !rpNewItem )
434 0 : nFree = nNew;
435 :
436 : // Found it?
437 0 : else if ( *rpNewItem == *pOldItem )
438 : {
439 : // Reuse
440 0 : SfxItemPool::AddRef( *pOldItem, rpNewItem->GetRefCount() );
441 0 : SfxItemPool::SetRefCount( *rpNewItem, 0 );
442 0 : delete rpNewItem;
443 0 : rpNewItem = pOldItem;
444 0 : bFound = true;
445 0 : break;
446 : }
447 : }
448 :
449 : // Take over the ones that were previously present, but had not been loaded
450 0 : if ( !bFound )
451 : {
452 0 : if ( nFree != SAL_MAX_UINT32 )
453 0 : (SfxPoolItem*&)(*ppArr)->operator[](nFree) = pOldItem;
454 : else
455 0 : (*ppArr)->push_back( (SfxPoolItem*) pOldItem );
456 : }
457 : }
458 : }
459 : }
460 0 : delete pOldArr;
461 :
462 0 : (*ppArr)->ReHash(); // paranoid
463 0 : }
464 :
465 0 : SvStream &SfxItemPool::Load(SvStream &rStream)
466 : {
467 : DBG_ASSERT(pImp->ppStaticDefaults, "No DefaultArray");
468 :
469 : // Protect items by increasing ref count
470 0 : if ( !pImp->mbPersistentRefCounts )
471 : {
472 :
473 : // Iterate over all Which values
474 0 : std::vector<SfxPoolItemArray_Impl*>::iterator itrItemArr = pImp->maPoolItems.begin();
475 0 : for( size_t nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++itrItemArr )
476 : {
477 : // Is there an Item with that Which value present at all?
478 0 : if ( *itrItemArr )
479 : {
480 0 : SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*itrItemArr)->begin();
481 0 : for( size_t n = (*itrItemArr)->size(); n; --n, ++ppHtArr )
482 0 : if (*ppHtArr)
483 : {
484 : DBG_WARNING( "loading non-empty ItemPool" );
485 :
486 0 : AddRef( **ppHtArr, 1 );
487 : }
488 : }
489 : }
490 :
491 : // During loading (until LoadCompleted()) protect all items
492 0 : pImp->nInitRefCount = 2;
493 : }
494 :
495 : // Find LoadMaster
496 0 : SfxItemPool *pLoadMaster = pImp->mpMaster != this ? pImp->mpMaster : 0;
497 0 : while ( pLoadMaster && !pLoadMaster->pImp->bStreaming )
498 0 : pLoadMaster = pLoadMaster->pImp->mpSecondary;
499 :
500 : // Read whole Header
501 0 : pImp->bStreaming = true;
502 0 : if ( !pLoadMaster )
503 : {
504 : // Load format version
505 0 : CHECK_FILEFORMAT2( rStream,
506 : SFX_ITEMPOOL_TAG_STARTPOOL_5, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
507 0 : rStream.ReadUChar( pImp->nMajorVer ).ReadUChar( pImp->nMinorVer );
508 :
509 : // Take over format version to MasterPool
510 0 : pImp->mpMaster->pImp->nMajorVer = pImp->nMajorVer;
511 0 : pImp->mpMaster->pImp->nMinorVer = pImp->nMinorVer;
512 :
513 : // Old Format?
514 0 : if ( pImp->nMajorVer < 2 )
515 : // pImp->bStreaming is reset by Load1_Impl()
516 0 : return Load1_Impl( rStream );
517 :
518 : // New Format?
519 0 : if ( pImp->nMajorVer > SFX_ITEMPOOL_VER_MAJOR )
520 : {
521 0 : rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
522 0 : pImp->bStreaming = false;
523 0 : return rStream;
524 : }
525 :
526 : // Trick for version 1.2: skip data
527 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_TRICK4OLD );
528 0 : rStream.SeekRel( 4 ); // Hack: Skip data due to SfxStyleSheetPool bug
529 : }
530 :
531 : // New record-oriented format
532 0 : SfxMiniRecordReader aPoolRec( &rStream, SFX_ITEMPOOL_REC );
533 0 : if ( rStream.GetError() )
534 : {
535 0 : pImp->bStreaming = false;
536 0 : return rStream;
537 : }
538 :
539 : // Single header
540 0 : OUString aExternName;
541 : {
542 : // Find HeaderRecord
543 0 : SfxMiniRecordReader aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER );
544 0 : if ( rStream.GetError() )
545 : {
546 0 : pImp->bStreaming = false;
547 0 : return rStream;
548 : }
549 :
550 : // Read Header
551 0 : rStream.ReadUInt16( pImp->nLoadingVersion );
552 0 : aExternName = readByteString(rStream);
553 0 : bool bOwnPool = aExternName == pImp->aName;
554 :
555 : //! As long as we cannot read foreign Pools
556 0 : if ( !bOwnPool )
557 : {
558 0 : rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
559 0 : aPoolRec.Skip();
560 0 : pImp->bStreaming = false;
561 0 : return rStream;
562 0 : }
563 : }
564 :
565 : // Version maps
566 : {
567 0 : SfxMultiRecordReader aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP );
568 0 : if ( rStream.GetError() )
569 : {
570 0 : pImp->bStreaming = false;
571 0 : return rStream;
572 : }
573 :
574 : // Version maps einlesen
575 0 : sal_uInt16 nOwnVersion = pImp->nVersion;
576 0 : for ( sal_uInt16 nVerNo = 0; aVerRec.GetContent(); ++nVerNo )
577 : {
578 : // Read header for single versions
579 0 : sal_uInt16 nVersion(0), nHStart(0), nHEnd(0);
580 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nHStart ).ReadUInt16( nHEnd );
581 0 : sal_uInt16 nCount = nHEnd - nHStart + 1;
582 :
583 : // Is new version is known?
584 0 : if ( nVerNo >= pImp->aVersions.size() )
585 : {
586 : // Add new Version
587 0 : sal_uInt16 *pMap = new sal_uInt16[nCount];
588 0 : memset(pMap, 0, nCount * sizeof(sal_uInt16));
589 0 : for ( sal_uInt16 n = 0; n < nCount; ++n )
590 0 : rStream.ReadUInt16( pMap[n] );
591 0 : SetVersionMap( nVersion, nHStart, nHEnd, pMap );
592 : }
593 : }
594 0 : pImp->nVersion = nOwnVersion;
595 : }
596 :
597 : // Load Items
598 0 : bool bSecondaryLoaded = false;
599 0 : long nSecondaryEnd = 0;
600 : {
601 0 : SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS);
602 0 : while ( aWhichIdsRec.GetContent() )
603 : {
604 : // Get SlotId, WhichId and Item version
605 0 : sal_uInt32 nCount(0);
606 0 : sal_uInt16 nVersion(0), nWhich(0);
607 : //!sal_uInt16 nSlotId = aWhichIdsRec.GetContentTag();
608 0 : rStream.ReadUInt16( nWhich );
609 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
610 : // Move WhichId from file version to Pool version
611 0 : nWhich = GetNewWhich( nWhich );
612 :
613 : // Unknown Item from newer version
614 0 : if ( !IsInRange(nWhich) )
615 0 : continue;
616 :
617 0 : rStream.ReadUInt16( nVersion );
618 0 : rStream.ReadUInt32( nCount );
619 : //!SFX_ASSERTWARNING( !nSlotId || !HasMap() ||
620 : //! ( nSlotId == GetSlotId( nWhich, sal_False ) ) ||
621 : //! !GetSlotId( nWhich, sal_False ),
622 : //! nWhich, "Slot/Which mismatch" );
623 :
624 0 : sal_uInt16 nIndex = GetIndex_Impl(nWhich);
625 0 : SfxPoolItemArray_Impl **ppArr = &pImp->maPoolItems[0] + nIndex;
626 :
627 : // SfxSetItems could contain Items from secondary Pools
628 0 : SfxPoolItem *pDefItem = *(pImp->ppStaticDefaults + nIndex);
629 0 : pImp->bInSetItem = pDefItem->ISA(SfxSetItem);
630 0 : if ( !bSecondaryLoaded && pImp->mpSecondary && pImp->bInSetItem )
631 : {
632 : // Seek to end of own Pool
633 0 : sal_uLong nLastPos = rStream.Tell();
634 0 : aPoolRec.Skip();
635 :
636 : // Read secondary Pool
637 0 : pImp->mpSecondary->Load( rStream );
638 0 : bSecondaryLoaded = true;
639 0 : nSecondaryEnd = rStream.Tell();
640 :
641 : // Back to our own Items
642 0 : rStream.Seek(nLastPos);
643 : }
644 :
645 : // Read Items
646 0 : pImp->readTheItems(rStream, nCount, nVersion, pDefItem, ppArr);
647 :
648 0 : pImp->bInSetItem = false;
649 0 : }
650 : }
651 :
652 : // Read Pool defaults
653 : {
654 0 : SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS );
655 :
656 0 : while ( aDefsRec.GetContent() )
657 : {
658 : // Get SlotId, WhichId and Item versions
659 0 : sal_uInt16 nVersion(0), nWhich(0);
660 : //!sal_uInt16 nSlotId = aDefsRec.GetContentTag();
661 0 : rStream.ReadUInt16( nWhich );
662 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
663 : // Move WhichId from file version to Pool version
664 0 : nWhich = GetNewWhich( nWhich );
665 :
666 : // Unknown Item from newer version
667 0 : if ( !IsInRange(nWhich) )
668 0 : continue;
669 :
670 0 : rStream.ReadUInt16( nVersion );
671 : //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, sal_False ) ),
672 : //! nWhich, "Slot/Which mismatch" );
673 :
674 : // Load PoolDefaultItem
675 : SfxPoolItem *pItem =
676 0 : ( *( pImp->ppStaticDefaults + GetIndex_Impl(nWhich) ) )
677 0 : ->Create( rStream, nVersion );
678 0 : pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
679 0 : *( pImp->ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
680 0 : }
681 : }
682 :
683 : // Load secondary Pool if needed
684 0 : aPoolRec.Skip();
685 0 : if ( pImp->mpSecondary )
686 : {
687 0 : if ( !bSecondaryLoaded )
688 0 : pImp->mpSecondary->Load( rStream );
689 : else
690 0 : rStream.Seek( nSecondaryEnd );
691 : }
692 :
693 : // If not own Pool, then no name
694 0 : if ( aExternName != pImp->aName )
695 0 : pImp->aName = OUString();
696 :
697 0 : pImp->bStreaming = false;
698 0 : return rStream;
699 : };
700 :
701 196111717 : sal_uInt16 SfxItemPool::GetIndex_Impl(sal_uInt16 nWhich) const
702 : {
703 : DBG_ASSERT(nWhich >= pImp->mnStart && nWhich <= pImp->mnEnd, "WhichId not within the Pool range");
704 196111717 : return nWhich - pImp->mnStart;
705 : }
706 :
707 240454 : sal_uInt16 SfxItemPool::GetSize_Impl() const
708 : {
709 240454 : return pImp->mnEnd - pImp->mnStart + 1;
710 : }
711 :
712 :
713 0 : SvStream &SfxItemPool::Load1_Impl(SvStream &rStream)
714 : {
715 : // For the Master the Header has already been loaded in Load()
716 0 : if ( !pImp->bStreaming )
717 : {
718 : // Read the secondary's Header
719 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_STARTPOOL_4 );
720 0 : rStream.ReadUChar( pImp->nMajorVer ).ReadUChar( pImp->nMinorVer );
721 : }
722 0 : sal_uInt32 nAttribSize(0);
723 0 : OUString aExternName;
724 0 : if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 2 )
725 0 : rStream.ReadUInt16( pImp->nLoadingVersion );
726 0 : aExternName = readByteString(rStream);
727 0 : bool bOwnPool = aExternName == pImp->aName;
728 0 : pImp->bStreaming = true;
729 :
730 : //! As long as we cannot read foreign ones
731 0 : if ( !bOwnPool )
732 : {
733 0 : rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
734 0 : pImp->bStreaming = false;
735 0 : return rStream;
736 : }
737 :
738 : // Versions up to 1.3 cannot read WhichMoves
739 0 : if ( pImp->nMajorVer == 1 && pImp->nMinorVer <= 2 &&
740 0 : pImp->nVersion < pImp->nLoadingVersion )
741 : {
742 0 : rStream.SetError(ERRCODE_IO_WRONGVERSION);
743 0 : pImp->bStreaming = false;
744 0 : return rStream;
745 : }
746 :
747 : // SizeTable comes after the actual attributes
748 0 : rStream.ReadUInt32( nAttribSize );
749 :
750 : // Read SizeTable
751 0 : sal_uLong nStartPos = rStream.Tell();
752 0 : rStream.SeekRel( nAttribSize );
753 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_SIZES );
754 0 : sal_uInt32 nSizeTableLen(0);
755 0 : rStream.ReadUInt32( nSizeTableLen );
756 0 : boost::scoped_array<sal_Char> pBuf(new sal_Char[nSizeTableLen]);
757 0 : rStream.Read( pBuf.get(), nSizeTableLen );
758 0 : sal_uLong nEndOfSizes = rStream.Tell();
759 0 : SvMemoryStream aSizeTable( pBuf.get(), nSizeTableLen, STREAM_READ );
760 :
761 : // Starting with version 1.3 the SizeTable contains a versions map
762 0 : if ( pImp->nMajorVer > 1 || pImp->nMinorVer >= 3 )
763 : {
764 : // Find version map (last sal_uLong of the SizeTable determines position)
765 0 : rStream.Seek( nEndOfSizes - sizeof(sal_uInt32) );
766 0 : sal_uInt32 nVersionMapPos(0);
767 0 : rStream.ReadUInt32( nVersionMapPos );
768 0 : rStream.Seek( nVersionMapPos );
769 :
770 : // Read version maps
771 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_VERSIONMAP );
772 0 : sal_uInt16 nVerCount(0);
773 0 : rStream.ReadUInt16( nVerCount );
774 0 : for ( sal_uInt16 nVerNo = 0; nVerNo < nVerCount; ++nVerNo )
775 : {
776 : // Read Header for single versions
777 0 : sal_uInt16 nVersion(0), nHStart(0), nHEnd(0);
778 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nHStart ).ReadUInt16( nHEnd );
779 0 : sal_uInt16 nCount = nHEnd - nHStart + 1;
780 0 : sal_uInt16 nBytes = (nCount)*sizeof(sal_uInt16);
781 :
782 : // Is new version known?
783 0 : if ( nVerNo >= pImp->aVersions.size() )
784 : {
785 : // Add new version
786 0 : sal_uInt16 *pMap = new sal_uInt16[nCount];
787 0 : memset(pMap, 0, nCount * sizeof(sal_uInt16));
788 0 : for ( sal_uInt16 n = 0; n < nCount; ++n )
789 0 : rStream.ReadUInt16( pMap[n] );
790 0 : SetVersionMap( nVersion, nHStart, nHEnd, pMap );
791 : }
792 : else
793 : // Skip known versions
794 0 : rStream.SeekRel( nBytes );
795 : }
796 : }
797 :
798 : // Load Items
799 0 : rStream.Seek( nStartPos );
800 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ITEMS );
801 0 : bool bSecondaryLoaded = false;
802 0 : long nSecondaryEnd = 0;
803 0 : sal_uInt16 nWhich(0), nSlot(0);
804 0 : while ( rStream.ReadUInt16( nWhich ), nWhich )
805 : {
806 : // Move WhichId from old version?
807 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
808 0 : nWhich = GetNewWhich( nWhich );
809 :
810 0 : rStream.ReadUInt16( nSlot );
811 :
812 0 : sal_uInt16 nRef(0), nCount(0), nVersion(0);
813 0 : sal_uInt32 nAttrSize(0);
814 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nCount );
815 :
816 : //!SFX_ASSERTWARNING( !nSlot || !HasMap() ||
817 : //! ( nSlot == GetSlotId( nWhich, sal_False ) ) ||
818 : //! !GetSlotId( nWhich, sal_False ),
819 : //! nWhich, "Slot/Which mismatch" );
820 :
821 0 : sal_uInt16 nIndex = GetIndex_Impl(nWhich);
822 0 : std::vector<SfxPoolItemArray_Impl*>::iterator ppArr = pImp->maPoolItems.begin();
823 0 : std::advance(ppArr, nIndex);
824 0 : SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl();
825 0 : SfxPoolItem *pDefItem = *(pImp->ppStaticDefaults + nIndex);
826 :
827 : // Remember position of first Item
828 0 : sal_uLong nLastPos = rStream.Tell();
829 :
830 : // SfxSetItems could contain Items from secondary Pool
831 0 : if ( !bSecondaryLoaded && pImp->mpSecondary && pDefItem->ISA(SfxSetItem) )
832 : {
833 : // Seek to end of own Pool
834 0 : rStream.Seek(nEndOfSizes);
835 0 : CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr );
836 0 : CHECK_FILEFORMAT_RELEASE( rStream, SFX_ITEMPOOL_TAG_ENDPOOL, pNewArr );
837 :
838 : // Read secondary Pool
839 0 : pImp->mpSecondary->Load1_Impl( rStream );
840 0 : bSecondaryLoaded = true;
841 0 : nSecondaryEnd = rStream.Tell();
842 :
843 : // Back to our own Items
844 0 : rStream.Seek(nLastPos);
845 : }
846 :
847 : // Read Items
848 0 : for ( sal_uInt16 j = 0; j < nCount; ++j )
849 : {
850 0 : sal_uLong nPos = nLastPos;
851 0 : rStream.ReadUInt16( nRef );
852 :
853 0 : SfxPoolItem *pItem = 0;
854 0 : if ( nRef )
855 : {
856 0 : pItem = pDefItem->Create(rStream, nVersion);
857 :
858 0 : if ( !pImp->mbPersistentRefCounts )
859 : // Hold onto them until SfxItemPool::LoadCompleted()
860 0 : AddRef(*pItem, 1);
861 : else
862 : {
863 0 : if ( nRef > SFX_ITEMS_OLD_MAXREF )
864 0 : pItem->SetKind( convertUInt16ToSfxItemKind(nRef) );
865 : else
866 0 : AddRef(*pItem, nRef);
867 : }
868 : }
869 : //pNewArr->insert( pItem, j );
870 0 : pNewArr->push_back( (SfxPoolItem*) pItem );
871 :
872 : // Skip the rest of the saved length (newer format)
873 0 : nLastPos = rStream.Tell();
874 :
875 0 : aSizeTable.ReadUInt32( nAttrSize );
876 : SFX_ASSERT( ( nPos + nAttrSize) >= nLastPos,
877 : nPos,
878 : "too many bytes read - version mismatch?" );
879 :
880 0 : if (nLastPos < (nPos + nAttrSize))
881 : {
882 0 : nLastPos = nPos + nAttrSize;
883 0 : rStream.Seek( nLastPos );
884 : }
885 : }
886 :
887 0 : SfxPoolItemArray_Impl *pOldArr = *ppArr;
888 0 : *ppArr = pNewArr;
889 :
890 : // Remember Items already in the Pool
891 0 : bool bEmpty = true;
892 0 : if ( 0 != pOldArr )
893 0 : for ( size_t n = 0; bEmpty && n < pOldArr->size(); ++n )
894 0 : bEmpty = pOldArr->operator[](n) == 0;
895 : DBG_ASSERTWARNING( bEmpty, "loading non-empty pool" );
896 0 : if ( !bEmpty )
897 : {
898 : // Find out for all old ones, whether there's a same new one
899 0 : for ( size_t nOld = 0; nOld < pOldArr->size(); ++nOld )
900 : {
901 0 : SfxPoolItem *pOldItem = (*pOldArr)[nOld];
902 0 : if ( pOldItem )
903 : {
904 0 : bool bFound = false;
905 0 : for ( size_t nNew = 0;
906 0 : nNew < (*ppArr)->size(); ++nNew )
907 : {
908 : SfxPoolItem *&rpNewItem =
909 0 : (SfxPoolItem*&)(*ppArr)->operator[](nNew);
910 :
911 0 : if ( rpNewItem && *rpNewItem == *pOldItem )
912 : {
913 0 : AddRef( *pOldItem, rpNewItem->GetRefCount() );
914 0 : SetRefCount( *rpNewItem, 0 );
915 0 : delete rpNewItem;
916 0 : rpNewItem = pOldItem;
917 0 : bFound = true;
918 : SAL_INFO("svl", "reusing item" << pOldItem);
919 0 : break;
920 : }
921 : }
922 : SAL_INFO_IF(
923 : !bFound, "svl", "item not found: " << pOldItem);
924 : }
925 : }
926 : }
927 0 : delete pOldArr;
928 : }
929 :
930 : // Read Pool defaults
931 0 : if ( pImp->nMajorVer > 1 || pImp->nMinorVer > 0 )
932 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_DEFAULTS );
933 :
934 0 : sal_uLong nLastPos = rStream.Tell();
935 0 : while ( rStream.ReadUInt16( nWhich ), nWhich )
936 : {
937 : // Move WhichId from old version?
938 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
939 0 : nWhich = GetNewWhich( nWhich );
940 :
941 0 : rStream.ReadUInt16( nSlot );
942 :
943 0 : sal_uLong nPos = nLastPos;
944 0 : sal_uInt32 nSize(0);
945 0 : sal_uInt16 nVersion(0);
946 0 : rStream.ReadUInt16( nVersion );
947 :
948 : SfxPoolItem *pItem =
949 0 : ( *( pImp->ppStaticDefaults + GetIndex_Impl(nWhich) ) )
950 0 : ->Create( rStream, nVersion );
951 0 : pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
952 0 : *( pImp->ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
953 :
954 0 : nLastPos = rStream.Tell();
955 0 : aSizeTable.ReadUInt32( nSize );
956 : SFX_ASSERT( ( nPos + nSize) >= nLastPos, nPos,
957 : "too many bytes read - version mismatch?" );
958 0 : if ( nLastPos < (nPos + nSize) )
959 0 : rStream.Seek( nPos + nSize );
960 : }
961 :
962 0 : pBuf.reset();
963 0 : rStream.Seek(nEndOfSizes);
964 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
965 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_ENDPOOL );
966 :
967 0 : if ( pImp->mpSecondary )
968 : {
969 0 : if ( !bSecondaryLoaded )
970 0 : pImp->mpSecondary->Load1_Impl( rStream );
971 : else
972 0 : rStream.Seek( nSecondaryEnd );
973 : }
974 :
975 0 : if ( aExternName != pImp->aName )
976 0 : pImp->aName = OUString();
977 :
978 0 : pImp->bStreaming = false;
979 0 : return rStream;
980 : }
981 :
982 :
983 : /**
984 : * Loads surrogate from 'rStream' and returns the corresponding SfxPoolItem
985 : * from the rRefPool.
986 : * If the surrogate contained within the stream == SFX_ITEMS_DIRECT
987 : * (!SFX_ITEM_POOLABLE), we return 0 and the Item is to be loaded directly
988 : * from the stream.
989 : * We also return 0 for 0xfffffff0 (SFX_ITEMS_NULL) and rWhich is set to 0,
990 : * making the Items unavailable.
991 : *
992 : * Apart from that we also take into account whether the Pool is loaded without
993 : * RefCounts, if we reload from a new Pool (&rRefPool != this) or if we're
994 : * building from a differently constructed Pool.
995 : *
996 : * If we load from a differently constructed Pool and the 'nSlotId' cannot be
997 : * mapped to a WhichId of this Pool, we also return 0.
998 : *
999 : * Preconditions: - Pool must be loaded
1000 : * - LoadCompleted must not have been called yet
1001 : * - 'rStream' is at the position at which a surrogate
1002 : * for an Item with the SlotId 'nSlotId', the WhichId
1003 : * 'rWhichId' was saved with StoreSurrogate
1004 : *
1005 : * Postconditions: - 'rStream' is at the same position as after StoreSurrogate
1006 : * had finished saving
1007 : * - If we were able to load an Item, it's now in this
1008 : * SfxItemPool
1009 : * - 'rWhichId' now contains the mapped WhichId
1010 : *
1011 : * Runtime: Depth of the traget secondary Pool * 10 + 10
1012 : *
1013 : * @see SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const
1014 : */
1015 0 : const SfxPoolItem* SfxItemPool::LoadSurrogate
1016 : (
1017 : SvStream& rStream, // Stream before a surrogate
1018 : sal_uInt16& rWhich, // WhichId of the SfxPoolItem that is to be loaded
1019 : sal_uInt16 nSlotId, // SlotId of the SfxPoolItem that is to be loaded
1020 : const SfxItemPool* pRefPool // SfxItemPool in which the surrogate is valid
1021 : )
1022 : {
1023 : // Read the first surrogate
1024 0 : sal_uInt32 nSurrogat(0);
1025 0 : rStream.ReadUInt32( nSurrogat );
1026 :
1027 : // Is item stored directly?
1028 0 : if ( SFX_ITEMS_DIRECT == nSurrogat )
1029 0 : return 0;
1030 :
1031 : // Item does not exist?
1032 0 : if ( SFX_ITEMS_NULL == nSurrogat )
1033 : {
1034 0 : rWhich = 0;
1035 0 : return 0;
1036 : }
1037 :
1038 : // If the Pool in the stream has the same structure, the surrogate
1039 : // can be resolved in any case
1040 0 : if ( !pRefPool )
1041 0 : pRefPool = this;
1042 :
1043 0 : bool bResolvable = !pRefPool->GetName().isEmpty();
1044 0 : if ( !bResolvable )
1045 : {
1046 : // If the pool in the stream has a different structure, the SlotId
1047 : // from the stream must be mapable to a WhichId
1048 0 : sal_uInt16 nMappedWhich = nSlotId ? GetWhich(nSlotId, true) : 0;
1049 0 : if ( IsWhich(nMappedWhich) )
1050 : {
1051 : // Mapped SlotId can be taken over
1052 0 : rWhich = nMappedWhich;
1053 0 : bResolvable = true;
1054 : }
1055 : }
1056 :
1057 : // Can the surrogate be resolved?
1058 0 : if ( bResolvable )
1059 : {
1060 0 : const SfxPoolItem *pItem = 0;
1061 0 : for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pImp->mpSecondary )
1062 : {
1063 : // Found the right (Range-)Pool?
1064 0 : if ( pTarget->IsInRange(rWhich) )
1065 : {
1066 : // Default attribute?
1067 0 : if ( SFX_ITEMS_DEFAULT == nSurrogat )
1068 0 : return *(pTarget->pImp->ppStaticDefaults +
1069 0 : pTarget->GetIndex_Impl(rWhich));
1070 :
1071 : SfxPoolItemArray_Impl* pItemArr =
1072 0 : pTarget->pImp->maPoolItems[pTarget->GetIndex_Impl(rWhich)];
1073 0 : pItem = pItemArr && nSurrogat < pItemArr->size()
1074 0 : ? (*pItemArr)[nSurrogat]
1075 0 : : 0;
1076 0 : if ( !pItem )
1077 : {
1078 : OSL_FAIL( "can't resolve surrogate" );
1079 0 : rWhich = 0; // Just to be sure; for the right StreamPos
1080 0 : return 0;
1081 : }
1082 :
1083 : // Reload from RefPool?
1084 0 : if ( pRefPool != pImp->mpMaster )
1085 0 : return &pTarget->Put( *pItem );
1086 :
1087 : // References have NOT been loaded together with the pool?
1088 0 : if ( !pTarget->HasPersistentRefCounts() )
1089 0 : AddRef( *pItem, 1 );
1090 : else
1091 0 : return pItem;
1092 :
1093 0 : return pItem;
1094 : }
1095 : }
1096 :
1097 : SFX_ASSERT( false, rWhich, "can't resolve Which-Id in LoadSurrogate" );
1098 : }
1099 :
1100 0 : return 0;
1101 : }
1102 :
1103 :
1104 : /**
1105 : * Saves a surrogate for '*pItem' in 'rStream'
1106 : *
1107 : * @returns sal_True: a real surrogates has been saved
1108 : * SFX_ITEMS_NULL for 'pItem==0', SFX_ITEMS_STATICDEFAULT
1109 : * and SFX_ITEMS_POOLDEFAULT are 'real' surrogates
1110 : *
1111 : * @returns sal_False: a dummy surrogate (SFX_ITEMS_DIRECT) has been saved;
1112 : * the actual Item needs to be saved right after it on
1113 : * its own
1114 : */
1115 28658 : bool SfxItemPool::StoreSurrogate ( SvStream& rStream, const SfxPoolItem* pItem) const
1116 : {
1117 28658 : if ( pItem )
1118 : {
1119 28658 : bool bRealSurrogate = IsItemFlag(*pItem, SFX_ITEM_POOLABLE);
1120 : rStream.WriteUInt32( bRealSurrogate
1121 : ? GetSurrogate( pItem )
1122 28658 : : SFX_ITEMS_DIRECT );
1123 28658 : return bRealSurrogate;
1124 : }
1125 :
1126 0 : rStream.WriteUInt32( SFX_ITEMS_NULL );
1127 0 : return true;
1128 : }
1129 :
1130 :
1131 :
1132 27878 : sal_uInt32 SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const
1133 : {
1134 : DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
1135 : DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
1136 : DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );
1137 :
1138 27878 : if ( !IsInRange(pItem->Which()) )
1139 : {
1140 0 : if ( pImp->mpSecondary )
1141 0 : return pImp->mpSecondary->GetSurrogate( pItem );
1142 : SFX_ASSERT( false, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" );
1143 : }
1144 :
1145 : // Pointer on static or pool-default attribute?
1146 27878 : if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
1147 0 : return SFX_ITEMS_DEFAULT;
1148 :
1149 27878 : SfxPoolItemArray_Impl* pItemArr = pImp->maPoolItems[GetIndex_Impl(pItem->Which())];
1150 : DBG_ASSERT(pItemArr, "ItemArr is not available");
1151 :
1152 29742 : for ( size_t i = 0; i < pItemArr->size(); ++i )
1153 : {
1154 29742 : const SfxPoolItem *p = (*pItemArr)[i];
1155 29742 : if ( p == pItem )
1156 27878 : return i;
1157 : }
1158 : SFX_ASSERT( false, pItem->Which(), "Item not in the pool");
1159 0 : return SFX_ITEMS_NULL;
1160 : }
1161 :
1162 :
1163 17768 : bool SfxItemPool::IsInStoringRange( sal_uInt16 nWhich ) const
1164 : {
1165 35536 : return nWhich >= pImp->nStoringStart &&
1166 35536 : nWhich <= pImp->nStoringEnd;
1167 : }
1168 :
1169 : /**
1170 : * This method allows for restricting the WhichRange, which is saved
1171 : * by ItemSets of this Pool (and the Pool itself).
1172 : * The method must be called before SfxItemPool::Store() and the values
1173 : * must also be still set when the actual document (the ItemSets) is
1174 : * being saved.
1175 : *
1176 : * Resetting it is not necessary, if this range is set correctly before
1177 : * _every_ save, because its only accounted for when saving.
1178 : *
1179 : * We need to do this for the 3.1 format, because there's a bug in the
1180 : * Pool loading method.
1181 : */
1182 10704 : void SfxItemPool::SetStoringRange( sal_uInt16 nFrom, sal_uInt16 nTo )
1183 : {
1184 10704 : pImp->nStoringStart = nFrom;
1185 10704 : pImp->nStoringEnd = nTo;
1186 10704 : }
1187 :
1188 :
1189 : /**
1190 : * This method allows for the creation of new and incompatible WhichId
1191 : * Ranges or distributions. Pools that were saved with old versions
1192 : * are mapped using the provided conversion table until the current
1193 : * version has been reached. Newer pools can be loaded, but will lose
1194 : * newer attributes, because the map is saved in conjunction with the pool.
1195 : *
1196 : * Precondition: Pool must not be loaded yet
1197 : * Postcondition: WhichIds from older versions can be mapped to version 'nVer'
1198 : * Runtime: 1.5 * new + 10
1199 : *
1200 : * For newer WhichRanges (nStart,nEnd) it must hold that older WhichRanges
1201 : * (nOldStart,nOldEnd) are completely contained in the newer WhichRange.
1202 : * It is valid to extend the WhichRange to both sides; also by inserting
1203 : * WhichIds. Moving WhichIds is not permitted.
1204 : * This method should only be called in or right after the ctor.
1205 : *
1206 : * The array must be static, because its not copied and resued in the
1207 : * copy-ctor of the SfxItemPool
1208 : *
1209 : * Example usage:
1210 : * Originally (version 0) the pool had the following WhichIds:
1211 : *
1212 : * 1:A, 2:B, 3:C, 4:D
1213 : *
1214 : * A newer version (version 1) is now supposed to contain two new Ids
1215 : * X and Y between B and C, looking like this:
1216 : *
1217 : * 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D
1218 : *
1219 : * We see that the Ids 3 and 4 have changed. For the new version, we
1220 : * would need to set the following in the new Pool:
1221 : *
1222 : * static sal_uInt16 nVersion1Map = { 1, 2, 5, 6 };
1223 : * pPool->SetVersionMap( 1, 1, 4, &nVersion1Map );
1224 : *
1225 : * @see SfxItemPool::IsLoadingVersionCurrent() const
1226 : * @see SfxItemPool::GetNewWhich(sal_uInt16)
1227 : * @see SfxItemPool::GetVersion() const
1228 : */
1229 596140 : void SfxItemPool::SetVersionMap
1230 : (
1231 : sal_uInt16 nVer, // New version number
1232 : sal_uInt16 nOldStart, // Old first WhichId
1233 : sal_uInt16 nOldEnd, // Old last WhichId
1234 : const sal_uInt16* pOldWhichIdTab /* Array containing the structure of the WhichIds
1235 : of the previous version, in which the new
1236 : corresponding new WhichId is located */
1237 : )
1238 : {
1239 : // Create new map entry to insert
1240 : const SfxPoolVersion_ImplPtr pVerMap = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl(
1241 596140 : nVer, nOldStart, nOldEnd, pOldWhichIdTab ) );
1242 596140 : pImp->aVersions.push_back( pVerMap );
1243 :
1244 : DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" );
1245 596140 : pImp->nVersion = nVer;
1246 :
1247 : // Adapt version range
1248 22504300 : for ( sal_uInt16 n = 0; n < nOldEnd-nOldStart+1; ++n )
1249 : {
1250 21908160 : sal_uInt16 nWhich = pOldWhichIdTab[n];
1251 21908160 : if ( nWhich < pImp->nVerStart )
1252 : {
1253 0 : if ( !nWhich )
1254 0 : nWhich = 0;
1255 0 : pImp->nVerStart = nWhich;
1256 : }
1257 21908160 : else if ( nWhich > pImp->nVerEnd )
1258 2336 : pImp->nVerEnd = nWhich;
1259 596140 : }
1260 596140 : }
1261 :
1262 :
1263 : /**
1264 : * This method converts WhichIds from a file format to the version of the
1265 : * current pool.
1266 : * If the file format is older, the conversion tables (set by the pool developer
1267 : * using SetVersion()) are used. If the file format is newer the conversion tables
1268 : * loaded from the file format are used. In this case, not every WhichId can be
1269 : * mapped in which case we return 0.
1270 : *
1271 : * The calculation is only defined for WhichIds supported by the corresponding
1272 : * file version, which is guarded by an assertion.
1273 : *
1274 : * Precondition: Pool must be loaded
1275 : * Postcondition: Unchanged
1276 : * Runtime: linear(Count of the secondary pools) +
1277 : * linear(Difference of the old and newer version)
1278 : *
1279 : * @see SfxItemPool::IsLoadingVersionCurrent() const
1280 : * @see SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)
1281 : * @see SfxItemPool::GetVersion() const
1282 : */
1283 0 : sal_uInt16 SfxItemPool::GetNewWhich
1284 : (
1285 : sal_uInt16 nFileWhich // The WhichId loaded from the stream
1286 : ) const
1287 : {
1288 : // Determine (secondary) Pool
1289 0 : if ( !IsInVersionsRange(nFileWhich) )
1290 : {
1291 0 : if ( pImp->mpSecondary )
1292 0 : return pImp->mpSecondary->GetNewWhich( nFileWhich );
1293 : SFX_ASSERT( false, nFileWhich, "unknown which in GetNewWhich()" );
1294 : }
1295 :
1296 : // Newer/the same/older version?
1297 0 : short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion;
1298 :
1299 : // WhichId of a newer version?
1300 0 : if ( nDiff > 0 )
1301 : {
1302 : // Map step by step from the top version down to the file version
1303 0 : for ( size_t nMap = pImp->aVersions.size(); nMap > 0; --nMap )
1304 : {
1305 0 : SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap-1];
1306 0 : if ( pVerInfo->_nVer > pImp->nVersion )
1307 : { sal_uInt16 nOfs;
1308 0 : sal_uInt16 nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1;
1309 0 : for ( nOfs = 0;
1310 0 : nOfs <= nCount &&
1311 0 : pVerInfo->_pMap[nOfs] != nFileWhich;
1312 : ++nOfs )
1313 0 : continue;
1314 :
1315 0 : if ( pVerInfo->_pMap[nOfs] == nFileWhich )
1316 0 : nFileWhich = pVerInfo->_nStart + nOfs;
1317 : else
1318 0 : return 0;
1319 : }
1320 : else
1321 0 : break;
1322 0 : }
1323 : }
1324 :
1325 : // WhichId of a newer version?
1326 0 : else if ( nDiff < 0 )
1327 : {
1328 : // Map step by step from the top version down to the file version
1329 0 : for ( size_t nMap = 0; nMap < pImp->aVersions.size(); ++nMap )
1330 : {
1331 0 : SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap];
1332 0 : if ( pVerInfo->_nVer > pImp->nLoadingVersion )
1333 : {
1334 : DBG_ASSERT( nFileWhich >= pVerInfo->_nStart &&
1335 : nFileWhich <= pVerInfo->_nEnd,
1336 : "which-id unknown in version" );
1337 0 : nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart];
1338 : }
1339 0 : }
1340 : }
1341 :
1342 : // Return original (nDiff==0) or mapped (nDiff!=0) Id
1343 0 : return nFileWhich;
1344 : }
1345 :
1346 :
1347 :
1348 :
1349 0 : bool SfxItemPool::IsInVersionsRange( sal_uInt16 nWhich ) const
1350 : {
1351 0 : return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd;
1352 : }
1353 :
1354 :
1355 : /**
1356 : * This method determines whether the loaded Pool version corresponds to the
1357 : * currently loaded Pool structure.
1358 : *
1359 : * Precondition: Pool is loaded
1360 : * Postcondition: Unchanged
1361 : * Runtime: linear(Count of secondary pools)
1362 : *
1363 : * @see SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)
1364 : * @see SfxItemPool::GetNewWhich(sal_uInt16) const
1365 : * @see SfxItemPool::GetVersion() const
1366 : */
1367 0 : bool SfxItemPool::IsCurrentVersionLoading() const
1368 : {
1369 0 : return ( pImp->nVersion == pImp->nLoadingVersion ) &&
1370 0 : ( !pImp->mpSecondary || pImp->mpSecondary->IsCurrentVersionLoading() );
1371 : }
1372 :
1373 :
1374 : /**
1375 : * Saves the SfxPoolItem 'rItem' to the SvStream 'rStream':
1376 : * either as a surrogate ('bDirect == sal_False') or directly with
1377 : * 'rItem.Store()'.
1378 : * Non-poolable Items are always saved directly. Items without WhichId and
1379 : * SID-Items as well as Items that were not yet present in the file format
1380 : * version (return sal_False) are not saved.
1381 : *
1382 : * The Item is saved to the Stream in the following manner:
1383 : * sal_uInt16 rItem.Which()
1384 : * sal_uInt16 GetSlotId( rItem.Which() ) or 0 if not available
1385 : * sal_uInt16 GetSurrogate( &rItem ) or SFX_ITEM_DIRECT fo '!SFX_ITEM_POOLBLE'
1386 : *
1387 : * Optionally (if 'bDirect == sal_True' or '!rItem.IsPoolable()':
1388 : * sal_uInt16 rItem.GetVersion()
1389 : * sal_uLong Size
1390 : * Size rItem.Store()
1391 : *
1392 : * @see SfxItemPool::LoadItem(SvStream&,bool) const
1393 : */
1394 17768 : bool SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem,
1395 : bool bDirect ) const
1396 : {
1397 : DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" );
1398 :
1399 17768 : if ( IsSlot( rItem.Which() ) )
1400 0 : return false;
1401 :
1402 17768 : const SfxItemPool *pPool = this;
1403 35536 : while ( !pPool->IsInStoringRange(rItem.Which()) )
1404 0 : if ( 0 == ( pPool = pPool->pImp->mpSecondary ) )
1405 0 : return false;
1406 :
1407 : DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem),
1408 : "SetItem contains ItemSet with SetItem" );
1409 :
1410 17768 : sal_uInt16 nSlotId = pPool->GetSlotId( rItem.Which(), true );
1411 17768 : sal_uInt16 nItemVersion = rItem.GetVersion(pImp->mnFileFormatVersion);
1412 17768 : if ( USHRT_MAX == nItemVersion )
1413 0 : return false;
1414 :
1415 17768 : rStream.WriteUInt16( rItem.Which() ).WriteUInt16( nSlotId );
1416 17768 : if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) )
1417 : {
1418 0 : rStream.WriteUInt16( nItemVersion );
1419 0 : rStream.WriteUInt32( 0L ); // Room for length in bytes
1420 0 : sal_uLong nIStart = rStream.Tell();
1421 0 : rItem.Store(rStream, nItemVersion);
1422 0 : sal_uLong nIEnd = rStream.Tell();
1423 0 : rStream.Seek( nIStart-4 );
1424 0 : rStream.WriteInt32( ( nIEnd-nIStart ) );
1425 0 : rStream.Seek( nIEnd );
1426 : }
1427 :
1428 17768 : return true;
1429 : }
1430 :
1431 :
1432 : /**
1433 : * If pRefPool==-1 => do not put!
1434 : */
1435 0 : const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, bool bDirect,
1436 : const SfxItemPool *pRefPool )
1437 : {
1438 0 : sal_uInt16 nWhich(0), nSlot(0); // nSurrogate;
1439 0 : rStream.ReadUInt16( nWhich ).ReadUInt16( nSlot );
1440 :
1441 0 : bool bDontPut = reinterpret_cast<SfxItemPool*>(-1) == pRefPool;
1442 0 : if ( bDontPut || !pRefPool )
1443 0 : pRefPool = this;
1444 :
1445 : // Find right secondary Pool
1446 0 : while ( !pRefPool->IsInVersionsRange(nWhich) )
1447 : {
1448 0 : if ( pRefPool->pImp->mpSecondary )
1449 0 : pRefPool = pRefPool->pImp->mpSecondary;
1450 : else
1451 : {
1452 : // WID not present in this version => skip
1453 0 : sal_uInt32 nSurro(0);
1454 0 : sal_uInt16 nVersion(0), nLen(0);
1455 0 : rStream.ReadUInt32( nSurro );
1456 0 : if ( SFX_ITEMS_DIRECT == nSurro )
1457 : {
1458 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nLen );
1459 0 : rStream.SeekRel( nLen );
1460 : }
1461 0 : return 0;
1462 : }
1463 : }
1464 :
1465 : // Are we loading a different version?
1466 0 : bool bCurVersion = pRefPool->IsCurrentVersionLoading();
1467 0 : if ( !bCurVersion )
1468 0 : nWhich = pRefPool->GetNewWhich( nWhich ); // Map WhichId to new version
1469 :
1470 : DBG_ASSERT( !nWhich || !pImp->bInSetItem ||
1471 : !pRefPool->pImp->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem),
1472 : "loading SetItem in ItemSet of SetItem" );
1473 :
1474 : // Are we loading via surrogate?
1475 0 : const SfxPoolItem *pItem = 0;
1476 0 : if ( !bDirect )
1477 : {
1478 : // WhichId known in this version?
1479 0 : if ( nWhich )
1480 : // Load surrogate and react if none present
1481 0 : pItem = LoadSurrogate( rStream, nWhich, nSlot, pRefPool );
1482 : else
1483 : // Else skip it
1484 0 : rStream.SeekRel( sizeof(sal_uInt16) );
1485 : }
1486 :
1487 : // Is loaded directly (not via surrogate)?
1488 0 : if ( bDirect || ( nWhich && !pItem ) )
1489 : {
1490 : // bDirekt or not IsPoolable() => Load Item directly
1491 0 : sal_uInt16 nVersion(0);
1492 0 : sal_uInt32 nLen(0);
1493 0 : rStream.ReadUInt16( nVersion ).ReadUInt32( nLen );
1494 0 : sal_uLong nIStart = rStream.Tell();
1495 :
1496 : // WhichId known in this version?
1497 0 : if ( nWhich )
1498 : {
1499 : // Load Item directly
1500 : SfxPoolItem *pNewItem =
1501 0 : pRefPool->GetDefaultItem(nWhich).Create(rStream, nVersion);
1502 0 : if ( bDontPut )
1503 0 : pItem = pNewItem;
1504 : else
1505 0 : if ( pNewItem )
1506 : {
1507 0 : pItem = &Put(*pNewItem);
1508 0 : delete pNewItem;
1509 : }
1510 : else
1511 0 : pItem = 0;
1512 0 : sal_uLong nIEnd = rStream.Tell();
1513 : DBG_ASSERT( nIEnd <= (nIStart+nLen), "read past end of item" );
1514 0 : if ( (nIStart+nLen) != nIEnd )
1515 0 : rStream.Seek( nIStart+nLen );
1516 : }
1517 : else
1518 : // SKip Item
1519 0 : rStream.Seek( nIStart+nLen );
1520 : }
1521 :
1522 0 : return pItem;
1523 : }
1524 :
1525 :
1526 0 : OUString readByteString(SvStream& rStream)
1527 : {
1528 0 : return rStream.ReadUniOrByteString(rStream.GetStreamCharSet());
1529 : }
1530 :
1531 10704 : void writeByteString(SvStream & rStream, const OUString& rString)
1532 : {
1533 10704 : rStream.WriteUniOrByteString(rString, rStream.GetStreamCharSet());
1534 10704 : }
1535 :
1536 0 : OUString readUnicodeString(SvStream & rStream, bool bUnicode)
1537 : {
1538 : return rStream.ReadUniOrByteString(bUnicode ? RTL_TEXTENCODING_UCS2 :
1539 0 : rStream.GetStreamCharSet());
1540 : }
1541 :
1542 0 : void writeUnicodeString(SvStream & rStream, const OUString& rString)
1543 : {
1544 0 : rStream.WriteUniOrByteString(rString, RTL_TEXTENCODING_UCS2);
1545 0 : }
1546 :
1547 :
1548 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|