xref: /aoo4110/main/tools/source/ref/pstm.cxx (revision b1cdbd2c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 
27 #include <tools/debug.hxx>
28 #include <tools/pstm.hxx>
29 
30 #define STOR_NO_OPTIMIZE
31 
32 /***********************************************************************/
33 /************************************************************************
34 |*	  SvClassManager::Register()
35 *************************************************************************/
Register(sal_uInt16 nClassId,SvCreateInstancePersist pFunc)36 void SvClassManager::Register( sal_uInt16 nClassId, SvCreateInstancePersist pFunc )
37 {
38 #ifdef DBG_UTIL
39 	SvCreateInstancePersist p;
40 	p = Get( nClassId );
41 	DBG_ASSERT( !p || p == pFunc, "register class with same id" );
42 #endif
43     aAssocTable.insert(Map::value_type(nClassId, pFunc));
44 }
45 
46 /************************************************************************
47 |*	  SvClassManager::Get()
48 *************************************************************************/
Get(sal_uInt16 nClassId)49 SvCreateInstancePersist SvClassManager::Get( sal_uInt16 nClassId )
50 {
51     Map::const_iterator i(aAssocTable.find(nClassId));
52     return i == aAssocTable.end() ? 0 : i->second;
53 }
54 
55 /****************** SvRttiBase *******************************************/
56 TYPEINIT0( SvRttiBase );
57 
58 /****************** SvPersistBaseMemberList ******************************/
59 
SvPersistBaseMemberList()60 SvPersistBaseMemberList::SvPersistBaseMemberList(){}
SvPersistBaseMemberList(sal_uInt16 nInitSz,sal_uInt16 nResize)61 SvPersistBaseMemberList::SvPersistBaseMemberList(
62     sal_uInt16 nInitSz, sal_uInt16 nResize )
63     : SuperSvPersistBaseMemberList( nInitSz, nResize ){}
64 
65 #define PERSIST_LIST_VER		(sal_uInt8)0
66 #define PERSIST_LIST_DBGUTIL	(sal_uInt8)0x80
67 
68 /************************************************************************
69 |*	  SvPersistBaseMemberList::WriteOnlyStreamedObjects()
70 *************************************************************************/
WriteObjects(SvPersistStream & rStm,sal_Bool bOnlyStreamed) const71 void SvPersistBaseMemberList::WriteObjects( SvPersistStream & rStm,
72 											sal_Bool bOnlyStreamed ) const
73 {
74 #ifdef STOR_NO_OPTIMIZE
75 	rStm << (sal_uInt8)(PERSIST_LIST_VER | PERSIST_LIST_DBGUTIL);
76 	sal_uInt32 nObjPos = rStm.WriteDummyLen();
77 #else
78 	sal_uInt8 bTmp = PERSIST_LIST_VER;
79 	rStm << bTmp;
80 #endif
81 	sal_uInt32 nCountMember = Count();
82 	sal_uIntPtr  nCountPos = rStm.Tell();
83 	sal_uInt32 nWriteCount = 0;
84 	rStm << nCountMember;
85 	//bloss die Liste nicht veraendern,
86 	//wegen Seiteneffekten beim Save
87 	for( sal_uIntPtr n = 0; n < nCountMember; n++ )
88 	{
89 		SvPersistBase * pObj = GetObject( n );
90 		if( !bOnlyStreamed || rStm.IsStreamed( pObj ) )
91 		{ // Objekt soll geschrieben werden
92 			rStm << GetObject( n );
93 			nWriteCount++;
94 		}
95 	}
96 	if( nWriteCount != nCountMember )
97 	{
98 		// nicht alle Objekte geschrieben, Count anpassen
99 		sal_uIntPtr nPos = rStm.Tell();
100 		rStm.Seek( nCountPos );
101 		rStm << nWriteCount;
102 		rStm.Seek( nPos );
103 	}
104 #ifdef STOR_NO_OPTIMIZE
105 	rStm.WriteLen( nObjPos );
106 #endif
107 }
108 
109 /************************************************************************
110 |*	  operator << ()
111 *************************************************************************/
operator <<(SvPersistStream & rStm,const SvPersistBaseMemberList & rLst)112 SvPersistStream& operator << ( SvPersistStream & rStm,
113 							   const SvPersistBaseMemberList & rLst )
114 {
115 	rLst.WriteObjects( rStm );
116 	return rStm;
117 }
118 
119 /************************************************************************
120 |*	  operator >> ()
121 *************************************************************************/
operator >>(SvPersistStream & rStm,SvPersistBaseMemberList & rLst)122 SvPersistStream& operator >> ( SvPersistStream & rStm,
123 							   SvPersistBaseMemberList & rLst )
124 {
125 	sal_uInt8 nVer;
126 	rStm >> nVer;
127 
128 	if( (nVer & ~PERSIST_LIST_DBGUTIL) != PERSIST_LIST_VER )
129 	{
130 		rStm.SetError( SVSTREAM_GENERALERROR );
131 		DBG_ERROR( "persist list, false version" );
132 	}
133 
134 	sal_uInt32 nObjLen(0), nObjPos(0);
135 	if( nVer & PERSIST_LIST_DBGUTIL )
136 		nObjLen = rStm.ReadLen( &nObjPos );
137 
138 	sal_uInt32 nCount;
139 	rStm >> nCount;
140 	for( sal_uIntPtr n = 0; n < nCount && rStm.GetError() == SVSTREAM_OK; n++ )
141 	{
142 		SvPersistBase * pObj;
143 		rStm >> pObj;
144 		if( pObj )
145 			rLst.Append( pObj );
146 	}
147 #ifdef DBG_UTIL
148 			if( nObjLen + nObjPos != rStm.Tell() )
149 			{
150 				ByteString aStr( "false list len: read = " );
151 				aStr += ByteString::CreateFromInt32( (long)(rStm.Tell() - nObjPos) );
152 				aStr += ", should = ";
153 				aStr += ByteString::CreateFromInt64(nObjLen);
154 				DBG_ERROR( aStr.GetBuffer() );
155 			}
156 #endif
157 	return rStm;
158 }
159 
160 //=========================================================================
SvPersistStream(SvClassManager & rMgr,SvStream * pStream,sal_uInt32 nStartIdxP)161 SvPersistStream::SvPersistStream
162 (
163 	SvClassManager & rMgr,	/* Alle Factorys, deren Objekt geladen und
164 							   gespeichert werdn k"onnen */
165 	SvStream * pStream,		/* Dieser Stream wird als Medium genommen, auf
166 							   dem der PersistStream arbeitet */
167 	sal_uInt32 nStartIdxP		/* Ab diesem Index werden die Id's f"ur
168 							   die Objekte vergeben, er muss gr"osser
169 							   als Null sein. */
170 )
171 	: rClassMgr( rMgr )
172 	, pStm( pStream )
173 	, aPUIdx( nStartIdxP )
174 	, nStartIdx( nStartIdxP )
175 	, pRefStm( NULL )
176 	, nFlags( 0 )
177 /*	[Beschreibung]
178 
179 	Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
180 	pStream d"urfen nicht ver"andert werden, solange sie in einem
181 	SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
182 	pStream (siehe <SvPersistStream::SetStream>).
183 */
184 {
185 	DBG_ASSERT( nStartIdx != 0, "zero index not allowed" );
186 	bIsWritable = sal_True;
187 	if( pStm )
188 	{
189 		SetVersion( pStm->GetVersion() );
190 		SetError( pStm->GetError() );
191 		SyncSvStream( pStm->Tell() );
192 	}
193 }
194 
195 //=========================================================================
SvPersistStream(SvClassManager & rMgr,SvStream * pStream,const SvPersistStream & rPersStm)196 SvPersistStream::SvPersistStream
197 (
198 	SvClassManager & rMgr,	/* Alle Factorys, deren Objekt geladen und
199 							   gespeichert werdn k"onnen */
200 	SvStream * pStream,		/* Dieser Stream wird als Medium genommen, auf
201 							   dem der PersistStream arbeitet */
202 	const SvPersistStream & rPersStm
203 							/* Wenn PersistStream's verschachtelt werden,
204 							   dann ist dies der Parent-Stream. */
205 )
206 	: rClassMgr( rMgr )
207 	, pStm( pStream )
208 	// Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
209 	, aPUIdx( rPersStm.GetCurMaxIndex() +1 )
210 	, nStartIdx( rPersStm.GetCurMaxIndex() +1 )
211 	, pRefStm( &rPersStm )
212 	, nFlags( 0 )
213 /*	[Beschreibung]
214 
215 	Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
216 	pStream d"urfen nicht ver"andert werden, solange sie in einem
217 	SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
218 	pStream (siehe <SvPersistStream::SetStream>).
219 	Durch diesen Konstruktor wird eine Hierarchiebildung unterst"utzt.
220 	Alle Objekte aus einer Hierarchie m"ussen erst geladen werden,
221 	wenn das erste aus dieser Hierarchie benutzt werden soll.
222 */
223 {
224 	bIsWritable = sal_True;
225 	if( pStm )
226 	{
227 		SetVersion( pStm->GetVersion() );
228 		SetError( pStm->GetError() );
229 		SyncSvStream( pStm->Tell() );
230 	}
231 }
232 
233 //=========================================================================
~SvPersistStream()234 SvPersistStream::~SvPersistStream()
235 /*	[Beschreibung]
236 
237 	Der Detruktor ruft die Methode <SvPersistStream::SetStream>
238 	mit NULL.
239 */
240 {
241 	SetStream( NULL );
242 }
243 
244 //=========================================================================
SetStream(SvStream * pStream)245 void SvPersistStream::SetStream
246 (
247 	SvStream * pStream	/* auf diesem Stream arbeitet der PersistStream */
248 
249 )
250 /*	[Beschreibung]
251 
252 	Es wird ein Medium (pStream) eingesetzt, auf dem PersistStream arbeitet.
253 	Dieses darf nicht von aussen modifiziert werden, solange es
254  	eingesetzt ist. Es sei denn, w"ahrend auf dem Medium gearbeitet
255 	wird, wird keine Methode von SvPersistStream gerufen, bevor
256 	nicht <SvPersistStream::SetStream> mit demselben Medium gerufen
257 	wurde.
258 */
259 {
260 	if( pStm != pStream )
261 	{
262 		if( pStm )
263 		{
264 			SyncSysStream();
265 			pStm->SetError( GetError() );
266 		}
267 		pStm = pStream;
268 	}
269 	if( pStm )
270 	{
271 		SetVersion( pStm->GetVersion() );
272 		SetError( pStm->GetError() );
273 		SyncSvStream( pStm->Tell() );
274 	}
275 }
276 
277 //=========================================================================
IsA() const278 sal_uInt16 SvPersistStream::IsA() const
279 /*	[Beschreibung]
280 
281 	Gibt den Identifier dieses Streamklasse zur"uck.
282 
283 	[R"uckgabewert]
284 
285 	sal_uInt16		ID_PERSISTSTREAM wird zur"uckgegeben.
286 
287 
288 	[Querverweise]
289 
290 	<SvStream::IsA>
291 */
292 {
293 	return ID_PERSISTSTREAM;
294 }
295 
296 
297 /*************************************************************************
298 |*	  SvPersistStream::ResetError()
299 *************************************************************************/
ResetError()300 void SvPersistStream::ResetError()
301 {
302 	SvStream::ResetError();
303 	DBG_ASSERT( pStm, "stream not set" );
304 	pStm->ResetError();
305 }
306 
307 /*************************************************************************
308 |*	  SvPersistStream::GetData()
309 *************************************************************************/
GetData(void * pData,sal_uIntPtr nSize)310 sal_uIntPtr SvPersistStream::GetData( void* pData, sal_uIntPtr nSize )
311 {
312 	DBG_ASSERT( pStm, "stream not set" );
313 	sal_uIntPtr nRet = pStm->Read( pData, nSize );
314 	SetError( pStm->GetError() );
315 	return nRet;
316 }
317 
318 /*************************************************************************
319 |*	  SvPersistStream::PutData()
320 *************************************************************************/
PutData(const void * pData,sal_uIntPtr nSize)321 sal_uIntPtr SvPersistStream::PutData( const void* pData, sal_uIntPtr nSize )
322 {
323 	DBG_ASSERT( pStm, "stream not set" );
324 	sal_uIntPtr nRet = pStm->Write( pData, nSize );
325 	SetError( pStm->GetError() );
326 	return nRet;
327 }
328 
329 /*************************************************************************
330 |*	  SvPersistStream::Seek()
331 *************************************************************************/
SeekPos(sal_uIntPtr nPos)332 sal_uIntPtr SvPersistStream::SeekPos( sal_uIntPtr nPos )
333 {
334 	DBG_ASSERT( pStm, "stream not set" );
335 	sal_uIntPtr nRet = pStm->Seek( nPos );
336 	SetError( pStm->GetError() );
337 	return nRet;
338 }
339 
340 /*************************************************************************
341 |*	  SvPersistStream::FlushData()
342 *************************************************************************/
FlushData()343 void SvPersistStream::FlushData()
344 {
345 }
346 
347 /*************************************************************************
348 |*	  SvPersistStream::GetCurMaxIndex()
349 *************************************************************************/
GetCurMaxIndex(const SvPersistUIdx & rIdx) const350 sal_uIntPtr SvPersistStream::GetCurMaxIndex( const SvPersistUIdx & rIdx ) const
351 {
352 	// const  bekomme ich nicht den hoechsten Index
353 	SvPersistUIdx * p = (SvPersistUIdx *)&rIdx;
354 	// alten merken
355 	sal_uIntPtr nCurIdx = p->GetCurIndex();
356 	p->Last();
357 	// Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
358 	sal_uIntPtr nMaxIdx = p->GetCurIndex();
359 	// wieder herstellen
360 	p->Seek( nCurIdx );
361 	return nMaxIdx;
362 }
363 
364 /*************************************************************************
365 |*	  SvPersistStream::GetIndex()
366 *************************************************************************/
GetIndex(SvPersistBase * pObj) const367 sal_uIntPtr SvPersistStream::GetIndex( SvPersistBase * pObj ) const
368 {
369 	sal_uIntPtr nId = (sal_uIntPtr)aPTable.Get( (sal_uIntPtr)pObj );
370 	if( !nId && pRefStm )
371 		return pRefStm->GetIndex( pObj );
372 	return nId;
373 }
374 
375 /*************************************************************************
376 |*	  SvPersistStream::GetObject)
377 *************************************************************************/
GetObject(sal_uIntPtr nIdx) const378 SvPersistBase * SvPersistStream::GetObject( sal_uIntPtr nIdx ) const
379 {
380 	if( nIdx >= nStartIdx )
381 		return aPUIdx.Get( nIdx );
382 	else if( pRefStm )
383 		return pRefStm->GetObject( nIdx );
384 	return NULL;
385 }
386 
387 //=========================================================================
388 #define LEN_1			0x80
389 #define LEN_2			0x40
390 #define LEN_4			0x20
391 #define LEN_5			0x10
ReadCompressed(SvStream & rStm)392 sal_uInt32 SvPersistStream::ReadCompressed
393 (
394 	SvStream & rStm	/* Aus diesem Stream werden die komprimierten Daten
395 					   gelesen */
396 )
397 /*	[Beschreibung]
398 
399 	Ein im Stream komprimiert abgelegtes Wort wird gelesen. In welchem
400 	Format komprimiert wird, siehe <SvPersistStream::WriteCompressed>.
401 
402 	[R"uckgabewert]
403 
404 	sal_uInt32		Das nicht komprimierte Wort wird zur"uckgegeben.
405 
406 	[Querverweise]
407 
408 */
409 {
410 	sal_uInt32 nRet(0);
411 	sal_uInt8	nMask;
412 	rStm >> nMask;
413 	if( nMask & LEN_1 )
414 		nRet = ~LEN_1 & nMask;
415 	else if( nMask & LEN_2 )
416 	{
417 		nRet = ~LEN_2 & nMask;
418 		nRet <<= 8;
419 		rStm >> nMask;
420 		nRet |= nMask;
421 	}
422 	else if( nMask & LEN_4 )
423 	{
424 		nRet = ~LEN_4 & nMask;
425 		nRet <<= 8;
426 		rStm >> nMask;
427 		nRet |= nMask;
428 		nRet <<= 16;
429 		sal_uInt16 n;
430 		rStm >> n;
431 		nRet |= n;
432 	}
433 	else if( nMask & LEN_5 )
434 	{
435 		if( nMask & 0x0F )
436 		{
437 			rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
438 			DBG_ERROR( "format error" );
439 		}
440 		rStm >> nRet;
441 	}
442 	else
443 	{
444 		rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
445 		DBG_ERROR( "format error" );
446 	}
447 	return nRet;
448 }
449 
450 //=========================================================================
WriteCompressed(SvStream & rStm,sal_uInt32 nVal)451 void SvPersistStream::WriteCompressed
452 (
453 	SvStream & rStm,/* Aus diesem Stream werden die komprimierten Daten
454 					   gelesen */
455 	sal_uInt32 nVal		/* Dieser Wert wird komprimiert geschrieben */
456 )
457 /*	[Beschreibung]
458 
459 	Das "ubergebene Wort wird komprimiert und in den Stream
460  	geschrieben. Folgendermassen wir komprimiert.
461 	nVal < 0x80			=>	0x80 		+ nVal ist 1 Byte gross.
462 	nVal < 0x4000		=>	0x4000 		+ nVal ist 2 Byte gross.
463 	nVal < 0x20000000   =>	0x20000000	+ nVal ist 4 Byte gross.
464 	nVal > 0x1FFFFFFF   =>	0x1000000000+ nVal ist 5 Byte gross.
465 
466 	[Querverweise]
467 
468 	<SvPersistStream::ReadCompressed>
469 */
470 {
471 #ifdef STOR_NO_OPTIMIZE
472 	if( nVal < 0x80 )
473 		rStm << (sal_uInt8)(LEN_1 | nVal);
474 	else if( nVal < 0x4000 )
475 	{
476 		rStm << (sal_uInt8)(LEN_2 | (nVal >> 8));
477 		rStm << (sal_uInt8)nVal;
478 	}
479 	else if( nVal < 0x20000000 )
480 	{
481 		// hoechstes sal_uInt8
482 		rStm << (sal_uInt8)(LEN_4 | (nVal >> 24));
483 		// 2. hoechstes sal_uInt8
484 		rStm << (sal_uInt8)(nVal >> 16);
485 		rStm << (sal_uInt16)(nVal);
486 	}
487 	else
488 #endif
489 	{
490 		rStm << (sal_uInt8)LEN_5;
491 		rStm << nVal;
492 	}
493 }
494 
495 //=========================================================================
WriteDummyLen()496 sal_uInt32 SvPersistStream::WriteDummyLen()
497 /*	[Beschreibung]
498 
499 	Die Methode schreibt 4 Byte in den Stream und gibt die Streamposition
500 	zur"uck.
501 
502 	[R"uckgabewert]
503 
504 	sal_uInt32		Die Position hinter der L"angenangabe wird zur"uckgegeben.
505 
506 	[Beispiel]
507 
508 	sal_uInt32 nObjPos = rStm.WriteDummyLen();
509 	...
510 	// Daten schreiben
511 	...
512 	rStm.WriteLen( nObjPos );
513 
514 	[Querverweise]
515 
516 	<SvPersistStream::ReadLen>, <SvPersistStream::WriteLen>
517 
518 */
519 {
520 #ifdef DBG_UTIL
521 	sal_uInt32 nPos = Tell();
522 #endif
523 	sal_uInt32 n0 = 0;
524 	*this << n0; // wegen Sun sp
525 	// keine Assertion bei Streamfehler
526 	DBG_ASSERT( GetError() != SVSTREAM_OK
527 				  || (sizeof( sal_uInt32 ) == Tell() -nPos),
528 				"keine 4-Byte fuer Langenangabe" );
529 	return Tell();
530 }
531 
532 //=========================================================================
WriteLen(sal_uInt32 nObjPos)533 void SvPersistStream::WriteLen
534 (
535 	sal_uInt32 nObjPos	/* die Position + 4, an der die L"ange geschrieben
536 					   wird. */
537 )
538 /*	[Beschreibung]
539 
540 	Die Methode schreibt die Differenz zwischen der aktuellen und
541  	nObjPos als sal_uInt32 an die Position nObjPos -4 im Stream. Danach
542 	wird der Stream wieder auf die alte Position gestellt.
543 
544 	[Beispiel]
545 
546 	Die Differenz enth"alt nicht die L"angenangabe.
547 
548 	sal_uInt32 nObjPos = rStm.WriteDummyLen();
549 	...
550 	// Daten schreiben
551 	...
552 	rStm.WriteLen( nObjPos );
553 	// weitere Daten schreiben
554 
555 	[Querverweise]
556 
557 	<SvPersistStream::ReadLen>, <SvPersistStream::WriteDummyLen>
558 */
559 {
560 	sal_uInt32 nPos = Tell();
561 	sal_uInt32 nLen = nPos - nObjPos;
562 	// die Laenge mu� im stream 4-Byte betragen
563 	Seek( nObjPos - sizeof( sal_uInt32 ) );
564 	// Laenge schreiben
565 	*this << nLen;
566 	Seek( nPos );
567 }
568 
569 //=========================================================================
ReadLen(sal_uInt32 * pTestPos)570 sal_uInt32 SvPersistStream::ReadLen
571 (
572 	sal_uInt32 * pTestPos	/* Die Position des Streams, nach dem Lesen der
573 						   L"ange, wird zur"uckgegeben. Es darf auch NULL
574 						   "ubergeben werden. */
575 )
576 /*	[Beschreibung]
577 
578 	Liest die L"ange die vorher mit <SvPersistStream::WriteDummyLen>
579 	und <SvPersistStream::WriteLen> geschrieben wurde.
580 */
581 {
582 	sal_uInt32 nLen;
583 	*this >> nLen;
584 	if( pTestPos )
585 		*pTestPos = Tell();
586 	return nLen;
587 }
588 
589 //=========================================================================
590 // Dateirormat abw"arts kompatibel
591 #ifdef STOR_NO_OPTIMIZE
592 #define P_VER		(sal_uInt8)0x00
593 #else
594 #define P_VER		(sal_uInt8)0x01
595 #endif
596 #define P_VER_MASK	(sal_uInt8)0x0F
597 #define P_ID_0		(sal_uInt8)0x80
598 #define P_OBJ		(sal_uInt8)0x40
599 #define P_DBGUTIL	(sal_uInt8)0x20
600 #define P_ID		(sal_uInt8)0x10
601 #ifdef STOR_NO_OPTIMIZE
602 #define P_STD	P_DBGUTIL
603 #else
604 #define P_STD	0
605 #endif
606 
WriteId(SvStream & rStm,sal_uInt8 nHdr,sal_uInt32 nId,sal_uInt16 nClassId)607 static void WriteId
608 (
609 	SvStream & rStm,
610 	sal_uInt8 nHdr,
611 	sal_uInt32 nId,
612 	sal_uInt16 nClassId
613 )
614 {
615 #ifdef STOR_NO_OPTIMIZE
616 	nHdr |= P_ID;
617 #endif
618 	nHdr |= P_VER;
619 	if( nHdr & P_ID )
620 	{
621 		if( (nHdr & P_OBJ) || nId != 0 )
622 		{ // Id nur bei Zeiger, oder DBGUTIL
623 			rStm << (sal_uInt8)(nHdr);
624 			SvPersistStream::WriteCompressed( rStm, nId );
625 		}
626 		else
627 		{ // NULL Pointer
628 			rStm << (sal_uInt8)(nHdr | P_ID_0);
629 			return;
630 		}
631 	}
632 	else
633 		rStm << nHdr;
634 
635 	if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
636 		// Objekte haben immer eine Klasse,
637 		// Pointer nur bei DBG_UTIL und != NULL
638 		SvPersistStream::WriteCompressed( rStm, nClassId );
639 }
640 
641 //=========================================================================
ReadId(SvStream & rStm,sal_uInt8 & nHdr,sal_uInt32 & nId,sal_uInt16 & nClassId)642 static void ReadId
643 (
644 	SvStream & rStm,
645 	sal_uInt8 & nHdr,
646 	sal_uInt32 & nId,
647 	sal_uInt16 & nClassId
648 )
649 {
650 	nClassId = 0;
651 	rStm >> nHdr;
652 	if( nHdr & P_ID_0 )
653 		nId = 0;
654 	else
655 	{
656 		if( (nHdr & P_VER_MASK) == 0 )
657 		{
658 			if( (nHdr & P_DBGUTIL) || !(nHdr & P_OBJ) )
659 				nId = SvPersistStream::ReadCompressed( rStm );
660 			else
661 				nId = 0;
662 		}
663 		else if( nHdr & P_ID )
664 			nId = SvPersistStream::ReadCompressed( rStm );
665 
666 		if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
667 			nClassId = (sal_uInt16)SvPersistStream::ReadCompressed( rStm );
668 	}
669 }
670 
671 //=========================================================================
WriteObj(sal_uInt8 nHdr,SvPersistBase * pObj)672 void SvPersistStream::WriteObj
673 (
674 	sal_uInt8 nHdr,
675 	SvPersistBase * pObj
676 )
677 {
678 #ifdef STOR_NO_OPTIMIZE
679 	sal_uInt32 nObjPos = 0;
680 	if( nHdr & P_DBGUTIL )
681 		// Position fuer Laenge merken
682 		nObjPos = WriteDummyLen();
683 #endif
684 	pObj->Save( *this );
685 #ifdef STOR_NO_OPTIMIZE
686 	if( nHdr & P_DBGUTIL )
687 		WriteLen( nObjPos );
688 #endif
689 }
690 
691 //=========================================================================
WritePointer(SvPersistBase * pObj)692 SvPersistStream& SvPersistStream::WritePointer
693 (
694 	SvPersistBase * pObj
695 )
696 {
697 	sal_uInt8 nP = P_STD;
698 
699 	if( pObj )
700 	{
701 		sal_uIntPtr nId = GetIndex( pObj );
702 		if( nId )
703 			nP |= P_ID;
704 		else
705 		{
706 			nId = aPUIdx.Insert( pObj );
707 			aPTable.Insert( (sal_uIntPtr)pObj, (void *)nId );
708 			nP |= P_OBJ;
709 		}
710 		WriteId( *this, nP, nId, pObj->GetClassId() );
711 		if( nP & P_OBJ )
712 			WriteObj( nP, pObj );
713 	}
714 	else
715 	{ // NULL Pointer
716 		WriteId( *this, nP | P_ID, 0, 0 );
717 	}
718 	return *this;
719 }
720 
721 //=========================================================================
ReadObj(SvPersistBase * & rpObj,sal_Bool bRegister)722 sal_uInt32 SvPersistStream::ReadObj
723 (
724 	SvPersistBase * &	rpObj,
725 	sal_Bool				bRegister
726 )
727 {
728 	sal_uInt8	nHdr;
729 	sal_uInt32	nId = 0;
730 	sal_uInt16	nClassId;
731 
732 	rpObj = NULL;	// Spezifikation: Im Fehlerfall 0.
733 	ReadId( *this, nHdr, nId, nClassId );
734 
735 	// reine Versionsnummer durch maskieren
736 	if( P_VER < (nHdr & P_VER_MASK) )
737 	{
738 		SetError( SVSTREAM_FILEFORMAT_ERROR );
739 		DBG_ERROR( "false version" );
740 	}
741 
742 	if( !(nHdr & P_ID_0) && GetError() == SVSTREAM_OK )
743 	{
744 		if( P_OBJ & nHdr )
745 		{ // read object, nId nur bei P_DBGUTIL gesetzt
746 			DBG_ASSERT( !(nHdr & P_DBGUTIL) || NULL == aPUIdx.Get( nId ),
747 						"object already exist" );
748 			SvCreateInstancePersist pFunc = rClassMgr.Get( nClassId );
749 
750 			sal_uInt32 nObjLen(0), nObjPos(0);
751 			if( nHdr & P_DBGUTIL )
752 				nObjLen = ReadLen( &nObjPos );
753 			if( !pFunc )
754 			{
755 #ifdef DBG_UTIL
756 				ByteString aStr( "no class with id: " );
757 				aStr += ByteString::CreateFromInt32( nClassId );
758 				aStr += " registered";
759 				DBG_WARNING( aStr.GetBuffer() );
760 #endif
761 				SetError( ERRCODE_IO_NOFACTORY );
762 				return 0;
763 			}
764 			pFunc( &rpObj );
765 			// Sichern
766 			rpObj->AddRef();
767 
768 			if( bRegister )
769 			{
770 				// unbedingt erst in Tabelle eintragen
771 				sal_uIntPtr nNewId = aPUIdx.Insert( rpObj );
772 				// um den gleichen Zustand, wie nach dem Speichern herzustellen
773 				aPTable.Insert( (sal_uIntPtr)rpObj, (void *)nNewId );
774 				DBG_ASSERT( !(nHdr & P_DBGUTIL) || nId == nNewId,
775 							"read write id conflict: not the same" );
776 			}
777 			// und dann Laden
778 			rpObj->Load( *this );
779 #ifdef DBG_UTIL
780 			if( nObjLen + nObjPos != Tell() )
781 			{
782 				ByteString aStr( "false object len: read = " );
783 				aStr += ByteString::CreateFromInt32( (long)(Tell() - nObjPos) );
784 				aStr += ", should = ";
785 				aStr += ByteString::CreateFromInt32( nObjLen );
786 				DBG_ERROR( aStr.GetBuffer() );
787 			}
788 #endif
789 			rpObj->RestoreNoDelete();
790 			rpObj->ReleaseRef();
791 		}
792 		else
793 		{
794 			rpObj = GetObject( nId );
795 			DBG_ASSERT( rpObj != NULL, "object does not exist" );
796 			DBG_ASSERT( rpObj->GetClassId() == nClassId, "class mismatch" );
797 		}
798 	}
799 	return nId;
800 }
801 
802 //=========================================================================
ReadPointer(SvPersistBase * & rpObj)803 SvPersistStream& SvPersistStream::ReadPointer
804 (
805 	SvPersistBase * & rpObj
806 )
807 {
808 	ReadObj( rpObj, sal_True );
809 	return *this;
810 }
811 
812 //=========================================================================
operator <<(SvPersistStream & rStm,SvPersistBase * pObj)813 SvPersistStream& operator <<
814 (
815 	SvPersistStream & rStm,
816 	SvPersistBase * pObj
817 )
818 {
819 	return rStm.WritePointer( pObj );
820 }
821 
822 //=========================================================================
operator >>(SvPersistStream & rStm,SvPersistBase * & rpObj)823 SvPersistStream& operator >>
824 (
825 	SvPersistStream & rStm,
826 	SvPersistBase * & rpObj
827 )
828 {
829 	return rStm.ReadPointer( rpObj );
830 }
831 
832 //=========================================================================
operator <<(SvStream & rStm,SvPersistStream & rThis)833 SvStream& operator <<
834 (
835 	SvStream & rStm,
836 	SvPersistStream & rThis
837 )
838 {
839 	SvStream * pOldStm = rThis.GetStream();
840 	rThis.SetStream( &rStm );
841 
842 	sal_uInt8 bTmp = 0;
843 	rThis << bTmp;    // Version
844 	sal_uInt32 nCount = (sal_uInt32)rThis.aPUIdx.Count();
845 	rThis << nCount;
846 	SvPersistBase * pEle = rThis.aPUIdx.First();
847 	for( sal_uInt32 i = 0; i < nCount; i++ )
848 	{
849 		sal_uInt8 nP = P_OBJ | P_ID | P_STD;
850 		WriteId( rThis, nP, rThis.aPUIdx.GetCurIndex(),
851 						pEle->GetClassId() );
852 		rThis.WriteObj( nP, pEle );
853 		pEle = rThis.aPUIdx.Next();
854 	}
855 	rThis.SetStream( pOldStm );
856 	return rStm;
857 }
858 
859 //=========================================================================
operator >>(SvStream & rStm,SvPersistStream & rThis)860 SvStream& operator >>
861 (
862 	SvStream & rStm,
863 	SvPersistStream & rThis
864 )
865 {
866 	SvStream * pOldStm = rThis.GetStream();
867 	rThis.SetStream( &rStm );
868 
869 	sal_uInt8 nVers;
870 	rThis >> nVers;    // Version
871 	if( 0 == nVers )
872 	{
873 		sal_uInt32 nCount = 0;
874 		rThis >> nCount;
875 		for( sal_uInt32 i = 0; i < nCount; i++ )
876 		{
877 			SvPersistBase * pEle;
878 			// Lesen, ohne in die Tabellen einzutragen
879 			sal_uInt32 nId = rThis.ReadObj( pEle, sal_False );
880 			if( rThis.GetError() )
881 				break;
882 
883 			// Die Id eines Objektes wird nie modifiziert
884 			rThis.aPUIdx.Insert( nId, pEle );
885 			rThis.aPTable.Insert( (sal_uIntPtr)pEle, (void *)nId );
886 		}
887 	}
888 	else
889 		rThis.SetError( SVSTREAM_FILEFORMAT_ERROR );
890 
891 	rThis.SetStream( pOldStm );
892 	return rStm;
893 }
894 
895 //=========================================================================
InsertObj(SvPersistBase * pObj)896 sal_uIntPtr SvPersistStream::InsertObj( SvPersistBase * pObj )
897 {
898 	sal_uIntPtr nId = aPUIdx.Insert( pObj );
899 	aPTable.Insert( (sal_uIntPtr)pObj, (void *)nId );
900 	return nId;
901 }
902 
903 //=========================================================================
RemoveObj(SvPersistBase * pObj)904 sal_uIntPtr SvPersistStream::RemoveObj( SvPersistBase * pObj )
905 {
906 	sal_uIntPtr nIdx = GetIndex( pObj );
907 	aPUIdx.Remove( nIdx );
908 	aPTable.Remove( (sal_uIntPtr)pObj );
909 	return nIdx;
910 }
911 
912