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 :
23 : #include <sal/log.hxx>
24 : #include <tools/solar.h>
25 : #include <svl/itempool.hxx>
26 : #include "whassert.hxx"
27 : #include <svl/SfxBroadcaster.hxx>
28 : #include <svl/filerec.hxx>
29 : #include "poolio.hxx"
30 : #include <boost/scoped_ptr.hpp>
31 : #include <boost/scoped_array.hpp>
32 :
33 : /**
34 : * Returns the <SfxItemPool> that is being saved.
35 : * This should only be used in very exceptional cases e.g.
36 : * when guaranteeing file format compatibility:
37 : * When overriding a <SfxPoolItem::Store()> getting additional data from the Pool
38 : */
39 0 : const SfxItemPool* SfxItemPool::GetStoringPool()
40 : {
41 0 : return pStoringPool_;
42 : }
43 :
44 0 : static sal_uInt16 convertSfxItemKindToUInt16(SfxItemKind x)
45 : {
46 0 : if ( x == SFX_ITEMS_NONE )
47 0 : return 0;
48 0 : if ( x == SFX_ITEMS_DELETEONIDLE )
49 0 : return 0xfffd;
50 0 : if ( x == SFX_ITEMS_STATICDEFAULT )
51 0 : return 0xfffe;
52 0 : if ( x == SFX_ITEMS_POOLDEFAULT )
53 0 : return 0xffff;
54 : assert(false);
55 0 : abort();
56 : }
57 :
58 0 : static SfxItemKind convertUInt16ToSfxItemKind(sal_uInt16 x)
59 : {
60 0 : if ( x == 0 )
61 0 : return SFX_ITEMS_NONE;
62 0 : if ( x == 0xfffd )
63 0 : return SFX_ITEMS_DELETEONIDLE;
64 0 : if ( x == 0xfffe )
65 0 : return SFX_ITEMS_STATICDEFAULT;
66 0 : if ( x == 0xffff )
67 0 : return SFX_ITEMS_POOLDEFAULT;
68 : assert(false);
69 0 : abort();
70 : }
71 :
72 :
73 :
74 : /**
75 : * The SfxItemPool is saved to the specified Stream (together with all its
76 : * secondary Pools) using its Pool Defaults and pooled Items.
77 : * The static defaults are not saved.
78 : * [Fileformat]
79 : *
80 : * ;First, a compatibility header section
81 : * Start: 0x1111 SFX_ITEMPOOL_TAG_STARTPOOLS(_4/_5)
82 : * sal_uInt8 MAJOR_VER ;SfxItemPool version
83 : * sal_uInt8 MINOR_VER ;"
84 : * 0xFFFF SFX_ITEMPOOL_TAG_TRICK4OLD ;ex. GetVersion()
85 : * sal_uInt16 0x0000 ;Pseudo StyleSheetPool
86 : * sal_uInt16 0x0000 ;Pseudo StyleSheetPool
87 : *
88 : * ;The whole Pool into a record
89 : * record SfxMiniRecod(SFX_ITEMPOOL_REC)
90 : *
91 : * ;Start with a Header for each
92 : * Header: record SfxMiniRecord(SFX_ITEMPOOL_REC_HEADER)
93 : * sal_uInt16 GetVersion() ;Which-Ranges etc.
94 : * String GetName() ;Pool name
95 : *
96 : * ;The version map: in order to be able to map WhichIds of new file version
97 : * Versions: record SfxMultiRecord(SFX_ITEMPOOL_REC_VERSIONS, 0)
98 : * sal_uInt16 OldVersion
99 : * sal_uInt16 OldStartWhich
100 : * sal_uInt16 OldEndWhich
101 : * sal_uInt16[] NewWhich (OldEndWhich-OldStartWhich+1)
102 : *
103 : * ;Now the pooled Items (first the non-SfxSetItems)
104 : * Items: record SfxMultiRecord(SFX_ITEMPOOL_REC_WHICHIDS, 0)
105 : * content SlotId, 0
106 : * sal_uInt16 WhichId
107 : * sal_uInt16 pItem->GetVersion()
108 : * sal_uInt16 Array-Size
109 : * record SfxMultiRecord(SFX_, 0)
110 : * content Surrogate
111 : * sal_uInt16 RefCount
112 : * unknown pItem->Store()
113 : *
114 : * ;Now the set Pool defaults
115 : * Defaults: record SfxMultiRecord(SFX_ITEMPOOL_REC_DEFAULTS, 0)
116 : * content SlotId, 0
117 : * sal_uInt16 WhichId
118 : * sal_uInt16 pPoolDef->GetVersion()
119 : * unknown pPoolDef->Store();
120 : *
121 : * ;Hereafter the secondary follows (if present) without compatibility header section
122 : */
123 6366 : SvStream &SfxItemPool::Store(SvStream &rStream) const
124 : {
125 : // Find StoreMaster
126 6366 : SfxItemPool *pStoreMaster = pImp->mpMaster != this ? pImp->mpMaster : 0;
127 12732 : while ( pStoreMaster && !pStoreMaster->pImp->bStreaming )
128 0 : pStoreMaster = pStoreMaster->pImp->mpSecondary;
129 :
130 : // Old header (version of the Pool and content version is 0xffff by default)
131 6366 : pImp->bStreaming = true;
132 6366 : if ( !pStoreMaster )
133 : {
134 6366 : rStream.WriteUInt16( rStream.GetVersion() >= SOFFICE_FILEFORMAT_50
135 : ? SFX_ITEMPOOL_TAG_STARTPOOL_5
136 6366 : : SFX_ITEMPOOL_TAG_STARTPOOL_4 );
137 6366 : rStream.WriteUInt8( SFX_ITEMPOOL_VER_MAJOR ).WriteUInt8( SFX_ITEMPOOL_VER_MINOR );
138 6366 : rStream.WriteUInt16( SFX_ITEMPOOL_TAG_TRICK4OLD );
139 :
140 : // Work around SfxStyleSheet bug
141 6366 : rStream.WriteUInt16( 0 ); // Version
142 6366 : rStream.WriteUInt16( 0 ); // Count (or else 2nd loop breaks)
143 : }
144 :
145 : // Every Pool as a whole is a record
146 6366 : SfxMiniRecordWriter aPoolRec( &rStream, SFX_ITEMPOOL_REC );
147 6366 : pStoringPool_ = this;
148 :
149 : // Single header (content version and name)
150 : {
151 6366 : SfxMiniRecordWriter aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER);
152 6366 : rStream.WriteUInt16( pImp->nVersion );
153 6366 : writeByteString(rStream, pImp->aName);
154 : }
155 :
156 : // VersionMaps
157 : {
158 6366 : SfxMultiVarRecordWriter aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP, 0 );
159 44562 : for ( size_t nVerNo = 0; nVerNo < pImp->aVersions.size(); ++nVerNo )
160 : {
161 38196 : aVerRec.NewContent();
162 38196 : SfxPoolVersion_ImplPtr pVer = pImp->aVersions[nVerNo];
163 38196 : rStream.WriteUInt16( pVer->_nVer ).WriteUInt16( pVer->_nStart ).WriteUInt16( pVer->_nEnd );
164 38196 : sal_uInt16 nCount = pVer->_nEnd - pVer->_nStart + 1;
165 38196 : sal_uInt16 nNewWhich = 0;
166 1184076 : for ( sal_uInt16 n = 0; n < nCount; ++n )
167 : {
168 1145880 : nNewWhich = pVer->_pMap[n];
169 1145880 : rStream.WriteUInt16( nNewWhich );
170 : }
171 :
172 : // Workaround for bug in SetVersionMap 312
173 38196 : if ( SOFFICE_FILEFORMAT_31 == pImp->mnFileFormatVersion )
174 0 : rStream.WriteUInt16( nNewWhich+1 );
175 44562 : }
176 : }
177 :
178 : // Pooled Items
179 : {
180 6366 : SfxMultiMixRecordWriter aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS, 0 );
181 :
182 : // First write the atomic Items and then write the Sets (important when loading)
183 19098 : for (int ft = 0 ; ft < 2 && !rStream.GetError(); ft++)
184 : {
185 12732 : pImp->bInSetItem = ft != 0;
186 :
187 12732 : std::vector<SfxPoolItemArray_Impl*>::iterator itrArr = pImp->maPoolItems.begin();
188 12732 : SfxPoolItem **ppDefItem = pImp->ppStaticDefaults;
189 12732 : const sal_uInt16 nSize = GetSize_Impl();
190 712992 : for ( size_t i = 0; i < nSize && !rStream.GetError(); ++i, ++itrArr, ++ppDefItem )
191 : {
192 : // Get version of the Item
193 700260 : sal_uInt16 nItemVersion = (*ppDefItem)->GetVersion( pImp->mnFileFormatVersion );
194 700260 : if ( USHRT_MAX == nItemVersion )
195 : // => Was not present in the version that was supposed to be exported
196 25464 : continue;
197 :
198 : // ! Poolable is not even saved in the Pool
199 : // And itemsets/plain-items depending on the round
200 696204 : if ( *itrArr && IsItemFlag(**ppDefItem, SfxItemPoolFlags::POOLABLE) &&
201 21408 : pImp->bInSetItem == (bool) (*ppDefItem)->ISA(SfxSetItem) )
202 : {
203 : // Own signature, global WhichId and ItemVersion
204 10704 : sal_uInt16 nSlotId = GetSlotId( (*ppDefItem)->Which(), false );
205 10704 : aWhichIdsRec.NewContent(nSlotId, 0);
206 10704 : rStream.WriteUInt16( (*ppDefItem)->Which() );
207 10704 : rStream.WriteUInt16( nItemVersion );
208 10704 : const sal_uInt32 nCount = ::std::min<size_t>( (*itrArr)->size(), SAL_MAX_UINT32 );
209 : DBG_ASSERT(nCount, "ItemArr is empty");
210 10704 : rStream.WriteUInt32( nCount );
211 :
212 : // Write Items
213 10704 : SfxMultiMixRecordWriter aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS, 0 );
214 22418 : for ( size_t j = 0; j < nCount; ++j )
215 : {
216 : // Get Item
217 11714 : const SfxPoolItem *pItem = (*itrArr)->operator[](j);
218 11714 : if ( pItem && pItem->GetRefCount() ) //! See other MI-REF
219 : {
220 11714 : aItemsRec.NewContent((sal_uInt16)j, 'X' );
221 :
222 11714 : if ( pItem->GetRefCount() == SFX_ITEMS_SPECIAL )
223 0 : rStream.WriteUInt16( convertSfxItemKindToUInt16(pItem->GetKind()) );
224 : else
225 : {
226 11714 : rStream.WriteUInt16( pItem->GetRefCount() );
227 11714 : if( pItem->GetRefCount() > SFX_ITEMS_OLD_MAXREF )
228 0 : rStream.SetError( ERRCODE_IO_NOTSTORABLEINBINARYFORMAT );
229 : }
230 :
231 11714 : if ( !rStream.GetError() )
232 11714 : pItem->Store(rStream, nItemVersion);
233 : else
234 0 : break;
235 : #ifdef DBG_UTIL_MI
236 : if ( !pItem->ISA(SfxSetItem) )
237 : {
238 : sal_uLong nMark = rStream.Tell();
239 : rStream.Seek( nItemStartPos + sizeof(sal_uInt16) );
240 : boost::scoped_ptr<SfxPoolItem> pClone(pItem->Create(rStream, nItemVersion ));
241 : sal_uInt16 nWh = pItem->Which();
242 : SFX_ASSERT( rStream.Tell() == nMark, nWh,"asymmetric store/create" );
243 : SFX_ASSERT( *pClone == *pItem, nWh, "unequal after store/create" );
244 : }
245 : #endif
246 : }
247 10704 : }
248 : }
249 : }
250 : }
251 :
252 6366 : pImp->bInSetItem = false;
253 : }
254 :
255 : // Save the set Defaults (PoolDefaults)
256 6366 : if ( !rStream.GetError() )
257 : {
258 6366 : SfxMultiMixRecordWriter aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS, 0 );
259 6366 : sal_uInt16 nCount = GetSize_Impl();
260 356496 : for ( sal_uInt16 n = 0; n < nCount; ++n )
261 : {
262 350130 : const SfxPoolItem* pDefaultItem = pImp->ppPoolDefaults[n];
263 350130 : if ( pDefaultItem )
264 : {
265 : // Get version
266 0 : sal_uInt16 nItemVersion = pDefaultItem->GetVersion( pImp->mnFileFormatVersion );
267 0 : if ( USHRT_MAX == nItemVersion )
268 : // => Was not present in the version yet
269 0 : continue;
270 :
271 : // Own signature, global signature, version
272 0 : sal_uInt16 nSlotId = GetSlotId( pDefaultItem->Which(), false );
273 0 : aDefsRec.NewContent( nSlotId, 0 );
274 0 : rStream.WriteUInt16( pDefaultItem->Which() );
275 0 : rStream.WriteUInt16( nItemVersion );
276 :
277 : // Item
278 0 : pDefaultItem->Store( rStream, nItemVersion );
279 : }
280 6366 : }
281 : }
282 :
283 : // Write out additional Pools
284 6366 : pStoringPool_ = 0;
285 6366 : aPoolRec.Close();
286 6366 : if ( !rStream.GetError() && pImp->mpSecondary )
287 0 : pImp->mpSecondary->Store( rStream );
288 :
289 6366 : pImp->bStreaming = false;
290 6366 : return rStream;
291 : }
292 :
293 0 : bool SfxItemPool::HasPersistentRefCounts() const
294 : {
295 0 : return pImp->mbPersistentRefCounts;
296 : }
297 :
298 : /**
299 : * If the SfxItemPool was loaded with 'bRefCounts' == sal_False, we need
300 : * to finish the loading of the document contents with a call of this method.
301 : * In any other case calling this function has no meaning.
302 : *
303 : * When loading without RefCounts, they are actually set to 1 so that
304 : * SfxPoolItems that are needed during and after loading are not deleted.
305 : * This method resets the RefCount and also removes all items that are not
306 : * needed anymore.
307 : *
308 : * @see SfxItemPool::Load()
309 : */
310 0 : void SfxItemPool::LoadCompleted()
311 : {
312 : // Did we load without RefCounts?
313 0 : if ( pImp->nInitRefCount > 1 )
314 : {
315 : // Iterate over all Which values
316 0 : std::vector<SfxPoolItemArray_Impl*>::iterator itrItemArr = pImp->maPoolItems.begin();
317 0 : for( sal_uInt16 nArrCnt = GetSize_Impl(); nArrCnt; --nArrCnt, ++itrItemArr )
318 : {
319 : // Is there an item with the Which value present at all?
320 0 : if ( *itrItemArr )
321 : {
322 : // Iterate over all items with this WhichId
323 0 : SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*itrItemArr)->begin();
324 0 : for( size_t n = (*itrItemArr)->size(); n; --n, ++ppHtArr )
325 : {
326 0 : if (*ppHtArr)
327 : {
328 0 : if ( !ReleaseRef( **ppHtArr, 1 ) )
329 0 : DELETEZ( *ppHtArr );
330 : }
331 : }
332 0 : (*itrItemArr)->ReHash();
333 : }
334 : }
335 :
336 : // from now on normal initial ref count
337 0 : pImp->nInitRefCount = 1;
338 : }
339 :
340 : // notify secondary pool
341 0 : if ( pImp->mpSecondary )
342 0 : pImp->mpSecondary->LoadCompleted();
343 0 : }
344 :
345 23939 : sal_uInt16 SfxItemPool::GetFirstWhich() const
346 : {
347 23939 : return pImp->mnStart;
348 : }
349 :
350 1160043 : sal_uInt16 SfxItemPool::GetLastWhich() const
351 : {
352 1160043 : return pImp->mnEnd;
353 : }
354 :
355 381252180 : bool SfxItemPool::IsInRange( sal_uInt16 nWhich ) const
356 : {
357 381252180 : return nWhich >= pImp->mnStart && nWhich <= pImp->mnEnd;
358 : }
359 :
360 : // This had to be moved to a method of its own to keep Solaris GCC happy:
361 0 : void SfxItemPool_Impl::readTheItems (
362 : SvStream & rStream, sal_uInt32 nItemCount, sal_uInt16 nVer,
363 : SfxPoolItem * pDefItem, SfxPoolItemArray_Impl ** ppArr)
364 : {
365 0 : SfxMultiRecordReader aItemsRec( &rStream, SFX_ITEMPOOL_REC_ITEMS );
366 :
367 0 : SfxPoolItemArray_Impl *pNewArr = new SfxPoolItemArray_Impl();
368 0 : SfxPoolItem *pItem = 0;
369 :
370 0 : sal_uLong n, nLastSurrogate = sal_uLong(-1);
371 0 : while (aItemsRec.GetContent())
372 : {
373 : // Get next surrogate
374 0 : sal_uInt16 nSurrogate = aItemsRec.GetContentTag();
375 : DBG_ASSERT( aItemsRec.GetContentVersion() == 'X',
376 : "not an item content" );
377 :
378 : // Fill up missing ones
379 : // coverity[tainted_data] - ignore this, though we should finally kill off this format
380 0 : for ( pItem = 0, n = nLastSurrogate+1; n < nSurrogate; ++n )
381 0 : pNewArr->push_back( 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( 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( 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 : (*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 : (*ppArr)->operator[](nFree) = pOldItem;
454 : else
455 0 : (*ppArr)->push_back( 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 : // Unknown Format
514 0 : if (pImp->nMajorVer < 2 || pImp->nMajorVer > SFX_ITEMPOOL_VER_MAJOR)
515 : {
516 0 : rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
517 0 : pImp->bStreaming = false;
518 0 : return rStream;
519 : }
520 :
521 : // Trick for version 1.2: skip data
522 0 : CHECK_FILEFORMAT( rStream, SFX_ITEMPOOL_TAG_TRICK4OLD );
523 0 : rStream.SeekRel( 4 ); // Hack: Skip data due to SfxStyleSheetPool bug
524 : }
525 :
526 : // New record-oriented format
527 0 : SfxMiniRecordReader aPoolRec( &rStream, SFX_ITEMPOOL_REC );
528 0 : if ( rStream.GetError() )
529 : {
530 0 : pImp->bStreaming = false;
531 0 : return rStream;
532 : }
533 :
534 : // Single header
535 0 : OUString aExternName;
536 : {
537 : // Find HeaderRecord
538 0 : SfxMiniRecordReader aPoolHeaderRec( &rStream, SFX_ITEMPOOL_REC_HEADER );
539 0 : if ( rStream.GetError() )
540 : {
541 0 : pImp->bStreaming = false;
542 0 : return rStream;
543 : }
544 :
545 : // Read Header
546 0 : rStream.ReadUInt16( pImp->nLoadingVersion );
547 0 : aExternName = readByteString(rStream);
548 0 : bool bOwnPool = aExternName == pImp->aName;
549 :
550 : //! As long as we cannot read foreign Pools
551 0 : if ( !bOwnPool )
552 : {
553 0 : rStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
554 0 : aPoolRec.Skip();
555 0 : pImp->bStreaming = false;
556 0 : return rStream;
557 0 : }
558 : }
559 :
560 : // Version maps
561 : {
562 0 : SfxMultiRecordReader aVerRec( &rStream, SFX_ITEMPOOL_REC_VERSIONMAP );
563 0 : if ( rStream.GetError() )
564 : {
565 0 : pImp->bStreaming = false;
566 0 : return rStream;
567 : }
568 :
569 : // Version maps einlesen
570 0 : sal_uInt16 nOwnVersion = pImp->nVersion;
571 0 : for ( sal_uInt16 nVerNo = 0; aVerRec.GetContent(); ++nVerNo )
572 : {
573 : // Read header for single versions
574 0 : sal_uInt16 nVersion(0), nHStart(0), nHEnd(0);
575 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nHStart ).ReadUInt16( nHEnd );
576 0 : sal_uInt16 nCount = nHEnd - nHStart + 1;
577 :
578 : // Is new version is known?
579 0 : if ( nVerNo >= pImp->aVersions.size() )
580 : {
581 : // Add new Version
582 0 : const size_t nMaxRecords = rStream.remainingSize() / sizeof(sal_uInt16);
583 0 : if (nCount > nMaxRecords)
584 : {
585 : SAL_WARN("svl", "Parsing error: " << nMaxRecords <<
586 : " max possible entries, but " << nCount << " claimed, truncating");
587 0 : nCount = nMaxRecords;
588 : }
589 0 : sal_uInt16 *pMap = new sal_uInt16[nCount];
590 0 : memset(pMap, 0, nCount * sizeof(sal_uInt16));
591 0 : for ( sal_uInt16 n = 0; n < nCount; ++n )
592 0 : rStream.ReadUInt16( pMap[n] );
593 0 : SetVersionMap( nVersion, nHStart, nHEnd, pMap );
594 : }
595 : }
596 0 : pImp->nVersion = nOwnVersion;
597 : }
598 :
599 : // Load Items
600 0 : bool bSecondaryLoaded = false;
601 0 : long nSecondaryEnd = 0;
602 : {
603 0 : SfxMultiRecordReader aWhichIdsRec( &rStream, SFX_ITEMPOOL_REC_WHICHIDS);
604 0 : while ( aWhichIdsRec.GetContent() )
605 : {
606 : // Get SlotId, WhichId and Item version
607 0 : sal_uInt32 nCount(0);
608 0 : sal_uInt16 nVersion(0), nWhich(0);
609 : //!sal_uInt16 nSlotId = aWhichIdsRec.GetContentTag();
610 0 : rStream.ReadUInt16( nWhich );
611 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
612 : // Move WhichId from file version to Pool version
613 0 : nWhich = GetNewWhich( nWhich );
614 :
615 : // Unknown Item from newer version
616 0 : if ( !IsInRange(nWhich) )
617 0 : continue;
618 :
619 0 : rStream.ReadUInt16( nVersion );
620 0 : rStream.ReadUInt32( nCount );
621 : //!SFX_ASSERTWARNING( !nSlotId || !HasMap() ||
622 : //! ( nSlotId == GetSlotId( nWhich, sal_False ) ) ||
623 : //! !GetSlotId( nWhich, sal_False ),
624 : //! nWhich, "Slot/Which mismatch" );
625 :
626 0 : sal_uInt16 nIndex = GetIndex_Impl(nWhich);
627 0 : SfxPoolItemArray_Impl **ppArr = &pImp->maPoolItems[0] + nIndex;
628 :
629 : // SfxSetItems could contain Items from secondary Pools
630 0 : SfxPoolItem *pDefItem = *(pImp->ppStaticDefaults + nIndex);
631 0 : pImp->bInSetItem = pDefItem->ISA(SfxSetItem);
632 0 : if ( !bSecondaryLoaded && pImp->mpSecondary && pImp->bInSetItem )
633 : {
634 : // Seek to end of own Pool
635 0 : sal_uLong nLastPos = rStream.Tell();
636 0 : aPoolRec.Skip();
637 :
638 : // Read secondary Pool
639 0 : pImp->mpSecondary->Load( rStream );
640 0 : bSecondaryLoaded = true;
641 0 : nSecondaryEnd = rStream.Tell();
642 :
643 : // Back to our own Items
644 0 : rStream.Seek(nLastPos);
645 : }
646 :
647 : // Read Items
648 0 : pImp->readTheItems(rStream, nCount, nVersion, pDefItem, ppArr);
649 :
650 0 : pImp->bInSetItem = false;
651 0 : }
652 : }
653 :
654 : // Read Pool defaults
655 : {
656 0 : SfxMultiRecordReader aDefsRec( &rStream, SFX_ITEMPOOL_REC_DEFAULTS );
657 :
658 0 : while ( aDefsRec.GetContent() )
659 : {
660 : // Get SlotId, WhichId and Item versions
661 0 : sal_uInt16 nVersion(0), nWhich(0);
662 : //!sal_uInt16 nSlotId = aDefsRec.GetContentTag();
663 0 : rStream.ReadUInt16( nWhich );
664 0 : if ( pImp->nLoadingVersion != pImp->nVersion )
665 : // Move WhichId from file version to Pool version
666 0 : nWhich = GetNewWhich( nWhich );
667 :
668 : // Unknown Item from newer version
669 0 : if ( !IsInRange(nWhich) )
670 0 : continue;
671 :
672 0 : rStream.ReadUInt16( nVersion );
673 : //!SFX_ASSERTWARNING( !HasMap() || ( nSlotId == GetSlotId( nWhich, sal_False ) ),
674 : //! nWhich, "Slot/Which mismatch" );
675 :
676 : // Load PoolDefaultItem
677 : SfxPoolItem *pItem =
678 0 : ( *( pImp->ppStaticDefaults + GetIndex_Impl(nWhich) ) )
679 0 : ->Create( rStream, nVersion );
680 0 : pItem->SetKind( SFX_ITEMS_POOLDEFAULT );
681 0 : *( pImp->ppPoolDefaults + GetIndex_Impl(nWhich) ) = pItem;
682 0 : }
683 : }
684 :
685 : // Load secondary Pool if needed
686 0 : aPoolRec.Skip();
687 0 : if ( pImp->mpSecondary )
688 : {
689 0 : if ( !bSecondaryLoaded )
690 0 : pImp->mpSecondary->Load( rStream );
691 : else
692 0 : rStream.Seek( nSecondaryEnd );
693 : }
694 :
695 : // If not own Pool, then no name
696 0 : if ( aExternName != pImp->aName )
697 0 : (pImp->aName).clear();
698 :
699 0 : pImp->bStreaming = false;
700 0 : return rStream;
701 : };
702 :
703 333475855 : sal_uInt16 SfxItemPool::GetIndex_Impl(sal_uInt16 nWhich) const
704 : {
705 333475855 : if (nWhich < pImp->mnStart || nWhich > pImp->mnEnd)
706 : {
707 : assert(false && "missing bounds check before use");
708 0 : return 0;
709 : }
710 333475855 : return nWhich - pImp->mnStart;
711 : }
712 :
713 133152 : sal_uInt16 SfxItemPool::GetSize_Impl() const
714 : {
715 133152 : return pImp->mnEnd - pImp->mnStart + 1;
716 : }
717 :
718 : /**
719 : * Loads surrogate from 'rStream' and returns the corresponding SfxPoolItem
720 : * from the rRefPool.
721 : * If the surrogate contained within the stream == SFX_ITEMS_DIRECT
722 : * (!SfxItemPoolFlags::POOLABLE), we return 0 and the Item is to be loaded directly
723 : * from the stream.
724 : * We also return 0 for 0xfffffff0 (SFX_ITEMS_NULL) and rWhich is set to 0,
725 : * making the Items unavailable.
726 : *
727 : * Apart from that we also take into account whether the Pool is loaded without
728 : * RefCounts, if we reload from a new Pool (&rRefPool != this) or if we're
729 : * building from a differently constructed Pool.
730 : *
731 : * If we load from a differently constructed Pool and the 'nSlotId' cannot be
732 : * mapped to a WhichId of this Pool, we also return 0.
733 : *
734 : * Preconditions: - Pool must be loaded
735 : * - LoadCompleted must not have been called yet
736 : * - 'rStream' is at the position at which a surrogate
737 : * for an Item with the SlotId 'nSlotId', the WhichId
738 : * 'rWhichId' was saved with StoreSurrogate
739 : *
740 : * Postconditions: - 'rStream' is at the same position as after StoreSurrogate
741 : * had finished saving
742 : * - If we were able to load an Item, it's now in this
743 : * SfxItemPool
744 : * - 'rWhichId' now contains the mapped WhichId
745 : *
746 : * Runtime: Depth of the traget secondary Pool * 10 + 10
747 : *
748 : * @see SfxItemPool::StoreSurrogate(SvStream&,const SfxPoolItem &)const
749 : */
750 0 : const SfxPoolItem* SfxItemPool::LoadSurrogate
751 : (
752 : SvStream& rStream, // Stream before a surrogate
753 : sal_uInt16& rWhich, // WhichId of the SfxPoolItem that is to be loaded
754 : sal_uInt16 nSlotId, // SlotId of the SfxPoolItem that is to be loaded
755 : const SfxItemPool* pRefPool // SfxItemPool in which the surrogate is valid
756 : )
757 : {
758 : // Read the first surrogate
759 0 : sal_uInt32 nSurrogat(0);
760 0 : rStream.ReadUInt32( nSurrogat );
761 :
762 : // Is item stored directly?
763 0 : if ( SFX_ITEMS_DIRECT == nSurrogat )
764 0 : return 0;
765 :
766 : // Item does not exist?
767 0 : if ( SFX_ITEMS_NULL == nSurrogat )
768 : {
769 0 : rWhich = 0;
770 0 : return 0;
771 : }
772 :
773 : // If the Pool in the stream has the same structure, the surrogate
774 : // can be resolved in any case
775 0 : if ( !pRefPool )
776 0 : pRefPool = this;
777 :
778 0 : bool bResolvable = !pRefPool->GetName().isEmpty();
779 0 : if ( !bResolvable )
780 : {
781 : // If the pool in the stream has a different structure, the SlotId
782 : // from the stream must be mapable to a WhichId
783 0 : sal_uInt16 nMappedWhich = nSlotId ? GetWhich(nSlotId, true) : 0;
784 0 : if ( IsWhich(nMappedWhich) )
785 : {
786 : // Mapped SlotId can be taken over
787 0 : rWhich = nMappedWhich;
788 0 : bResolvable = true;
789 : }
790 : }
791 :
792 : // Can the surrogate be resolved?
793 0 : if ( bResolvable )
794 : {
795 0 : const SfxPoolItem *pItem = 0;
796 0 : for ( SfxItemPool *pTarget = this; pTarget; pTarget = pTarget->pImp->mpSecondary )
797 : {
798 : // Found the right (Range-)Pool?
799 0 : if ( pTarget->IsInRange(rWhich) )
800 : {
801 : // Default attribute?
802 0 : if ( SFX_ITEMS_DEFAULT == nSurrogat )
803 0 : return *(pTarget->pImp->ppStaticDefaults +
804 0 : pTarget->GetIndex_Impl(rWhich));
805 :
806 : SfxPoolItemArray_Impl* pItemArr =
807 0 : pTarget->pImp->maPoolItems[pTarget->GetIndex_Impl(rWhich)];
808 0 : pItem = pItemArr && nSurrogat < pItemArr->size()
809 0 : ? (*pItemArr)[nSurrogat]
810 0 : : 0;
811 0 : if ( !pItem )
812 : {
813 : OSL_FAIL( "can't resolve surrogate" );
814 0 : rWhich = 0; // Just to be sure; for the right StreamPos
815 0 : return 0;
816 : }
817 :
818 : // Reload from RefPool?
819 0 : if ( pRefPool != pImp->mpMaster )
820 0 : return &pTarget->Put( *pItem );
821 :
822 : // References have NOT been loaded together with the pool?
823 0 : if ( !pTarget->HasPersistentRefCounts() )
824 0 : AddRef( *pItem, 1 );
825 : else
826 0 : return pItem;
827 :
828 0 : return pItem;
829 : }
830 : }
831 :
832 : SFX_ASSERT( false, rWhich, "can't resolve Which-Id in LoadSurrogate" );
833 : }
834 :
835 0 : return 0;
836 : }
837 :
838 :
839 : /**
840 : * Saves a surrogate for '*pItem' in 'rStream'
841 : *
842 : * @returns sal_True: a real surrogates has been saved
843 : * SFX_ITEMS_NULL for 'pItem==0', SFX_ITEMS_STATICDEFAULT
844 : * and SFX_ITEMS_POOLDEFAULT are 'real' surrogates
845 : *
846 : * @returns sal_False: a dummy surrogate (SFX_ITEMS_DIRECT) has been saved;
847 : * the actual Item needs to be saved right after it on
848 : * its own
849 : */
850 16149 : bool SfxItemPool::StoreSurrogate ( SvStream& rStream, const SfxPoolItem* pItem) const
851 : {
852 16149 : if ( pItem )
853 : {
854 16149 : bool bRealSurrogate = IsItemFlag(*pItem, SfxItemPoolFlags::POOLABLE);
855 : rStream.WriteUInt32( bRealSurrogate
856 : ? GetSurrogate( pItem )
857 16149 : : SFX_ITEMS_DIRECT );
858 16149 : return bRealSurrogate;
859 : }
860 :
861 0 : rStream.WriteUInt32( SFX_ITEMS_NULL );
862 0 : return true;
863 : }
864 :
865 :
866 :
867 16149 : sal_uInt32 SfxItemPool::GetSurrogate(const SfxPoolItem *pItem) const
868 : {
869 : DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
870 : DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
871 : DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );
872 :
873 16149 : if ( !IsInRange(pItem->Which()) )
874 : {
875 0 : if ( pImp->mpSecondary )
876 0 : return pImp->mpSecondary->GetSurrogate( pItem );
877 : SFX_ASSERT( false, pItem->Which(), "unknown Which-Id - dont ask me for surrogates" );
878 : }
879 :
880 : // Pointer on static or pool-default attribute?
881 16149 : if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
882 0 : return SFX_ITEMS_DEFAULT;
883 :
884 16149 : SfxPoolItemArray_Impl* pItemArr = pImp->maPoolItems[GetIndex_Impl(pItem->Which())];
885 : DBG_ASSERT(pItemArr, "ItemArr is not available");
886 :
887 17327 : for ( size_t i = 0; i < pItemArr->size(); ++i )
888 : {
889 17327 : const SfxPoolItem *p = (*pItemArr)[i];
890 17327 : if ( p == pItem )
891 16149 : return i;
892 : }
893 : SFX_ASSERT( false, pItem->Which(), "Item not in the pool");
894 0 : return SFX_ITEMS_NULL;
895 : }
896 :
897 :
898 9964 : bool SfxItemPool::IsInStoringRange( sal_uInt16 nWhich ) const
899 : {
900 19928 : return nWhich >= pImp->nStoringStart &&
901 19928 : nWhich <= pImp->nStoringEnd;
902 : }
903 :
904 : /**
905 : * This method allows for restricting the WhichRange, which is saved
906 : * by ItemSets of this Pool (and the Pool itself).
907 : * The method must be called before SfxItemPool::Store() and the values
908 : * must also be still set when the actual document (the ItemSets) is
909 : * being saved.
910 : *
911 : * Resetting it is not necessary, if this range is set correctly before
912 : * _every_ save, because its only accounted for when saving.
913 : *
914 : * We need to do this for the 3.1 format, because there's a bug in the
915 : * Pool loading method.
916 : */
917 6366 : void SfxItemPool::SetStoringRange( sal_uInt16 nFrom, sal_uInt16 nTo )
918 : {
919 6366 : pImp->nStoringStart = nFrom;
920 6366 : pImp->nStoringEnd = nTo;
921 6366 : }
922 :
923 :
924 : /**
925 : * This method allows for the creation of new and incompatible WhichId
926 : * Ranges or distributions. Pools that were saved with old versions
927 : * are mapped using the provided conversion table until the current
928 : * version has been reached. Newer pools can be loaded, but will lose
929 : * newer attributes, because the map is saved in conjunction with the pool.
930 : *
931 : * Precondition: Pool must not be loaded yet
932 : * Postcondition: WhichIds from older versions can be mapped to version 'nVer'
933 : * Runtime: 1.5 * new + 10
934 : *
935 : * For newer WhichRanges (nStart,nEnd) it must hold that older WhichRanges
936 : * (nOldStart,nOldEnd) are completely contained in the newer WhichRange.
937 : * It is valid to extend the WhichRange to both sides; also by inserting
938 : * WhichIds. Moving WhichIds is not permitted.
939 : * This method should only be called in or right after the ctor.
940 : *
941 : * The array must be static, because its not copied and resued in the
942 : * copy-ctor of the SfxItemPool
943 : *
944 : * Example usage:
945 : * Originally (version 0) the pool had the following WhichIds:
946 : *
947 : * 1:A, 2:B, 3:C, 4:D
948 : *
949 : * A newer version (version 1) is now supposed to contain two new Ids
950 : * X and Y between B and C, looking like this:
951 : *
952 : * 1:A, 2:B, 3:X, 4:Y, 5:C, 6:D
953 : *
954 : * We see that the Ids 3 and 4 have changed. For the new version, we
955 : * would need to set the following in the new Pool:
956 : *
957 : * static sal_uInt16 nVersion1Map = { 1, 2, 5, 6 };
958 : * pPool->SetVersionMap( 1, 1, 4, &nVersion1Map );
959 : *
960 : * @see SfxItemPool::IsLoadingVersionCurrent() const
961 : * @see SfxItemPool::GetNewWhich(sal_uInt16)
962 : * @see SfxItemPool::GetVersion() const
963 : */
964 374459 : void SfxItemPool::SetVersionMap
965 : (
966 : sal_uInt16 nVer, // New version number
967 : sal_uInt16 nOldStart, // Old first WhichId
968 : sal_uInt16 nOldEnd, // Old last WhichId
969 : const sal_uInt16* pOldWhichIdTab /* Array containing the structure of the WhichIds
970 : of the previous version, in which the new
971 : corresponding new WhichId is located */
972 : )
973 : {
974 : // Create new map entry to insert
975 : const SfxPoolVersion_ImplPtr pVerMap = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl(
976 374459 : nVer, nOldStart, nOldEnd, pOldWhichIdTab ) );
977 374459 : pImp->aVersions.push_back( pVerMap );
978 :
979 : DBG_ASSERT( nVer > pImp->nVersion, "Versions not sorted" );
980 374459 : pImp->nVersion = nVer;
981 :
982 : // Adapt version range
983 13973783 : for ( sal_uInt16 n = 0; n < nOldEnd-nOldStart+1; ++n )
984 : {
985 13599324 : sal_uInt16 nWhich = pOldWhichIdTab[n];
986 13599324 : if ( nWhich < pImp->nVerStart )
987 : {
988 0 : if ( !nWhich )
989 0 : nWhich = 0;
990 0 : pImp->nVerStart = nWhich;
991 : }
992 13599324 : else if ( nWhich > pImp->nVerEnd )
993 1378 : pImp->nVerEnd = nWhich;
994 374459 : }
995 374459 : }
996 :
997 :
998 : /**
999 : * This method converts WhichIds from a file format to the version of the
1000 : * current pool.
1001 : * If the file format is older, the conversion tables (set by the pool developer
1002 : * using SetVersion()) are used. If the file format is newer the conversion tables
1003 : * loaded from the file format are used. In this case, not every WhichId can be
1004 : * mapped in which case we return 0.
1005 : *
1006 : * The calculation is only defined for WhichIds supported by the corresponding
1007 : * file version, which is guarded by an assertion.
1008 : *
1009 : * Precondition: Pool must be loaded
1010 : * Postcondition: Unchanged
1011 : * Runtime: linear(Count of the secondary pools) +
1012 : * linear(Difference of the old and newer version)
1013 : *
1014 : * @see SfxItemPool::IsLoadingVersionCurrent() const
1015 : * @see SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)
1016 : * @see SfxItemPool::GetVersion() const
1017 : */
1018 0 : sal_uInt16 SfxItemPool::GetNewWhich
1019 : (
1020 : sal_uInt16 nFileWhich // The WhichId loaded from the stream
1021 : ) const
1022 : {
1023 : // Determine (secondary) Pool
1024 0 : if ( !IsInVersionsRange(nFileWhich) )
1025 : {
1026 0 : if ( pImp->mpSecondary )
1027 0 : return pImp->mpSecondary->GetNewWhich( nFileWhich );
1028 : SFX_ASSERT( false, nFileWhich, "unknown which in GetNewWhich()" );
1029 : }
1030 :
1031 : // Newer/the same/older version?
1032 0 : short nDiff = (short)pImp->nLoadingVersion - (short)pImp->nVersion;
1033 :
1034 : // WhichId of a newer version?
1035 0 : if ( nDiff > 0 )
1036 : {
1037 : // Map step by step from the top version down to the file version
1038 0 : for ( size_t nMap = pImp->aVersions.size(); nMap > 0; --nMap )
1039 : {
1040 0 : SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap-1];
1041 0 : if ( pVerInfo->_nVer > pImp->nVersion )
1042 : { sal_uInt16 nOfs;
1043 0 : sal_uInt16 nCount = pVerInfo->_nEnd - pVerInfo->_nStart + 1;
1044 0 : for ( nOfs = 0;
1045 0 : nOfs <= nCount &&
1046 0 : pVerInfo->_pMap[nOfs] != nFileWhich;
1047 : ++nOfs )
1048 0 : continue;
1049 :
1050 0 : if ( pVerInfo->_pMap[nOfs] == nFileWhich )
1051 0 : nFileWhich = pVerInfo->_nStart + nOfs;
1052 : else
1053 0 : return 0;
1054 : }
1055 : else
1056 0 : break;
1057 0 : }
1058 : }
1059 :
1060 : // WhichId of a newer version?
1061 0 : else if ( nDiff < 0 )
1062 : {
1063 : // Map step by step from the top version down to the file version
1064 0 : for ( size_t nMap = 0; nMap < pImp->aVersions.size(); ++nMap )
1065 : {
1066 0 : SfxPoolVersion_ImplPtr pVerInfo = pImp->aVersions[nMap];
1067 0 : if ( pVerInfo->_nVer > pImp->nLoadingVersion )
1068 : {
1069 0 : if (nFileWhich >= pVerInfo->_nStart &&
1070 0 : nFileWhich <= pVerInfo->_nEnd)
1071 : {
1072 0 : nFileWhich = pVerInfo->_pMap[nFileWhich - pVerInfo->_nStart];
1073 : }
1074 : else
1075 : {
1076 : SAL_WARN("svl.items", "which-id unknown in version");
1077 : }
1078 : }
1079 0 : }
1080 : }
1081 :
1082 : // Return original (nDiff==0) or mapped (nDiff!=0) Id
1083 0 : return nFileWhich;
1084 : }
1085 :
1086 :
1087 :
1088 :
1089 0 : bool SfxItemPool::IsInVersionsRange( sal_uInt16 nWhich ) const
1090 : {
1091 0 : return nWhich >= pImp->nVerStart && nWhich <= pImp->nVerEnd;
1092 : }
1093 :
1094 :
1095 : /**
1096 : * This method determines whether the loaded Pool version corresponds to the
1097 : * currently loaded Pool structure.
1098 : *
1099 : * Precondition: Pool is loaded
1100 : * Postcondition: Unchanged
1101 : * Runtime: linear(Count of secondary pools)
1102 : *
1103 : * @see SfxItemPool::SetVersionMap(sal_uInt16,sal_uInt16,sal_uInt16,sal_uInt16*)
1104 : * @see SfxItemPool::GetNewWhich(sal_uInt16) const
1105 : * @see SfxItemPool::GetVersion() const
1106 : */
1107 0 : bool SfxItemPool::IsCurrentVersionLoading() const
1108 : {
1109 0 : return ( pImp->nVersion == pImp->nLoadingVersion ) &&
1110 0 : ( !pImp->mpSecondary || pImp->mpSecondary->IsCurrentVersionLoading() );
1111 : }
1112 :
1113 :
1114 : /**
1115 : * Saves the SfxPoolItem 'rItem' to the SvStream 'rStream':
1116 : * either as a surrogate ('bDirect == sal_False') or directly with
1117 : * 'rItem.Store()'.
1118 : * Non-poolable Items are always saved directly. Items without WhichId and
1119 : * SID-Items as well as Items that were not yet present in the file format
1120 : * version (return sal_False) are not saved.
1121 : *
1122 : * The Item is saved to the Stream in the following manner:
1123 : * sal_uInt16 rItem.Which()
1124 : * sal_uInt16 GetSlotId( rItem.Which() ) or 0 if not available
1125 : * sal_uInt16 GetSurrogate( &rItem ) or SFX_ITEM_DIRECT fo '!SFX_ITEM_POOLBLE'
1126 : *
1127 : * Optionally (if 'bDirect == sal_True' or '!rItem.IsPoolable()':
1128 : * sal_uInt16 rItem.GetVersion()
1129 : * sal_uLong Size
1130 : * Size rItem.Store()
1131 : *
1132 : * @see SfxItemPool::LoadItem(SvStream&,bool) const
1133 : */
1134 9964 : bool SfxItemPool::StoreItem( SvStream &rStream, const SfxPoolItem &rItem,
1135 : bool bDirect ) const
1136 : {
1137 : DBG_ASSERT( !IsInvalidItem(&rItem), "cannot store invalid items" );
1138 :
1139 9964 : if ( IsSlot( rItem.Which() ) )
1140 0 : return false;
1141 :
1142 9964 : const SfxItemPool *pPool = this;
1143 19928 : while ( !pPool->IsInStoringRange(rItem.Which()) )
1144 0 : if ( 0 == ( pPool = pPool->pImp->mpSecondary ) )
1145 0 : return false;
1146 :
1147 : DBG_ASSERT( !pImp->bInSetItem || !rItem.ISA(SfxSetItem),
1148 : "SetItem contains ItemSet with SetItem" );
1149 :
1150 9964 : sal_uInt16 nSlotId = pPool->GetSlotId( rItem.Which(), true );
1151 9964 : sal_uInt16 nItemVersion = rItem.GetVersion(pImp->mnFileFormatVersion);
1152 9964 : if ( USHRT_MAX == nItemVersion )
1153 0 : return false;
1154 :
1155 9964 : rStream.WriteUInt16( rItem.Which() ).WriteUInt16( nSlotId );
1156 9964 : if ( bDirect || !pPool->StoreSurrogate( rStream, &rItem ) )
1157 : {
1158 0 : rStream.WriteUInt16( nItemVersion );
1159 0 : rStream.WriteUInt32( 0L ); // Room for length in bytes
1160 0 : sal_uLong nIStart = rStream.Tell();
1161 0 : rItem.Store(rStream, nItemVersion);
1162 0 : sal_uLong nIEnd = rStream.Tell();
1163 0 : rStream.Seek( nIStart-4 );
1164 0 : rStream.WriteInt32( nIEnd-nIStart );
1165 0 : rStream.Seek( nIEnd );
1166 : }
1167 :
1168 9964 : return true;
1169 : }
1170 :
1171 :
1172 : /**
1173 : * If pRefPool==-1 => do not put!
1174 : */
1175 0 : const SfxPoolItem* SfxItemPool::LoadItem( SvStream &rStream, bool bDirect,
1176 : const SfxItemPool *pRefPool )
1177 : {
1178 0 : sal_uInt16 nWhich(0), nSlot(0); // nSurrogate;
1179 0 : rStream.ReadUInt16( nWhich ).ReadUInt16( nSlot );
1180 :
1181 0 : bool bDontPut = reinterpret_cast<SfxItemPool*>(-1) == pRefPool;
1182 0 : if ( bDontPut || !pRefPool )
1183 0 : pRefPool = this;
1184 :
1185 : // Find right secondary Pool
1186 0 : while ( !pRefPool->IsInVersionsRange(nWhich) )
1187 : {
1188 0 : if ( pRefPool->pImp->mpSecondary )
1189 0 : pRefPool = pRefPool->pImp->mpSecondary;
1190 : else
1191 : {
1192 : // WID not present in this version => skip
1193 0 : sal_uInt32 nSurro(0);
1194 0 : sal_uInt16 nVersion(0), nLen(0);
1195 0 : rStream.ReadUInt32( nSurro );
1196 0 : if ( SFX_ITEMS_DIRECT == nSurro )
1197 : {
1198 0 : rStream.ReadUInt16( nVersion ).ReadUInt16( nLen );
1199 0 : rStream.SeekRel( nLen );
1200 : }
1201 0 : return 0;
1202 : }
1203 : }
1204 :
1205 : // Are we loading a different version?
1206 0 : bool bCurVersion = pRefPool->IsCurrentVersionLoading();
1207 0 : if ( !bCurVersion )
1208 0 : nWhich = pRefPool->GetNewWhich( nWhich ); // Map WhichId to new version
1209 :
1210 : DBG_ASSERT( !nWhich || !pImp->bInSetItem ||
1211 : !pRefPool->pImp->ppStaticDefaults[pRefPool->GetIndex_Impl(nWhich)]->ISA(SfxSetItem),
1212 : "loading SetItem in ItemSet of SetItem" );
1213 :
1214 : // Are we loading via surrogate?
1215 0 : const SfxPoolItem *pItem = 0;
1216 0 : if ( !bDirect )
1217 : {
1218 : // WhichId known in this version?
1219 0 : if ( nWhich )
1220 : // Load surrogate and react if none present
1221 0 : pItem = LoadSurrogate( rStream, nWhich, nSlot, pRefPool );
1222 : else
1223 : // Else skip it
1224 0 : rStream.SeekRel( sizeof(sal_uInt16) );
1225 : }
1226 :
1227 : // Is loaded directly (not via surrogate)?
1228 0 : if ( bDirect || ( nWhich && !pItem ) )
1229 : {
1230 : // bDirekt or not IsPoolable() => Load Item directly
1231 0 : sal_uInt16 nVersion(0);
1232 0 : sal_uInt32 nLen(0);
1233 0 : rStream.ReadUInt16( nVersion ).ReadUInt32( nLen );
1234 0 : sal_uLong nIStart = rStream.Tell();
1235 :
1236 : // WhichId known in this version?
1237 0 : if ( nWhich )
1238 : {
1239 : // Load Item directly
1240 : SfxPoolItem *pNewItem =
1241 0 : pRefPool->GetDefaultItem(nWhich).Create(rStream, nVersion);
1242 0 : if ( bDontPut )
1243 0 : pItem = pNewItem;
1244 : else
1245 0 : if ( pNewItem )
1246 : {
1247 0 : pItem = &Put(*pNewItem);
1248 0 : delete pNewItem;
1249 : }
1250 : else
1251 0 : pItem = 0;
1252 0 : sal_uLong nIEnd = rStream.Tell();
1253 : DBG_ASSERT( nIEnd <= (nIStart+nLen), "read past end of item" );
1254 0 : if ( (nIStart+nLen) != nIEnd )
1255 0 : rStream.Seek( nIStart+nLen );
1256 : }
1257 : else
1258 : // SKip Item
1259 0 : rStream.Seek( nIStart+nLen );
1260 : }
1261 :
1262 0 : return pItem;
1263 : }
1264 :
1265 :
1266 0 : OUString readByteString(SvStream& rStream)
1267 : {
1268 0 : return rStream.ReadUniOrByteString(rStream.GetStreamCharSet());
1269 : }
1270 :
1271 6366 : void writeByteString(SvStream & rStream, const OUString& rString)
1272 : {
1273 6366 : rStream.WriteUniOrByteString(rString, rStream.GetStreamCharSet());
1274 6366 : }
1275 :
1276 0 : OUString readUnicodeString(SvStream & rStream, bool bUnicode)
1277 : {
1278 : return rStream.ReadUniOrByteString(bUnicode ? RTL_TEXTENCODING_UCS2 :
1279 0 : rStream.GetStreamCharSet());
1280 : }
1281 :
1282 0 : void writeUnicodeString(SvStream & rStream, const OUString& rString)
1283 : {
1284 0 : rStream.WriteUniOrByteString(rString, RTL_TEXTENCODING_UCS2);
1285 0 : }
1286 :
1287 :
1288 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|