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