xref: /trunk/main/tools/source/ref/pstm.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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