1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: pstm.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_tools.hxx"
34 #include <tools/debug.hxx>
35 #include <tools/pstm.hxx>
37 #define STOR_NO_OPTIMIZE
39 /***********************************************************************/
40 /************************************************************************
41 |* SvClassManager::Register()
42 *************************************************************************/
43 void SvClassManager::Register( USHORT nClassId
, SvCreateInstancePersist pFunc
)
46 SvCreateInstancePersist p
;
48 DBG_ASSERT( !p
|| p
== pFunc
, "register class with same id" );
50 aAssocTable
.insert(Map::value_type(nClassId
, pFunc
));
53 /************************************************************************
54 |* SvClassManager::Get()
55 *************************************************************************/
56 SvCreateInstancePersist
SvClassManager::Get( USHORT nClassId
)
58 Map::const_iterator
i(aAssocTable
.find(nClassId
));
59 return i
== aAssocTable
.end() ? 0 : i
->second
;
62 /****************** SvRttiBase *******************************************/
63 TYPEINIT0( SvRttiBase
);
65 /****************** SvPersistBaseMemberList ******************************/
67 SvPersistBaseMemberList::SvPersistBaseMemberList(){}
68 SvPersistBaseMemberList::SvPersistBaseMemberList(
69 USHORT nInitSz
, USHORT nResize
)
70 : SuperSvPersistBaseMemberList( nInitSz
, nResize
){}
72 #define PERSIST_LIST_VER (BYTE)0
73 #define PERSIST_LIST_DBGUTIL (BYTE)0x80
75 /************************************************************************
76 |* SvPersistBaseMemberList::WriteOnlyStreamedObjects()
77 *************************************************************************/
78 void SvPersistBaseMemberList::WriteObjects( SvPersistStream
& rStm
,
79 BOOL bOnlyStreamed
) const
81 #ifdef STOR_NO_OPTIMIZE
82 rStm
<< (BYTE
)(PERSIST_LIST_VER
| PERSIST_LIST_DBGUTIL
);
83 UINT32 nObjPos
= rStm
.WriteDummyLen();
85 BYTE bTmp
= PERSIST_LIST_VER
;
88 UINT32 nCountMember
= Count();
89 ULONG nCountPos
= rStm
.Tell();
90 UINT32 nWriteCount
= 0;
92 //bloss die Liste nicht veraendern,
93 //wegen Seiteneffekten beim Save
94 for( ULONG n
= 0; n
< nCountMember
; n
++ )
96 SvPersistBase
* pObj
= GetObject( n
);
97 if( !bOnlyStreamed
|| rStm
.IsStreamed( pObj
) )
98 { // Objekt soll geschrieben werden
99 rStm
<< GetObject( n
);
103 if( nWriteCount
!= nCountMember
)
105 // nicht alle Objekte geschrieben, Count anpassen
106 ULONG nPos
= rStm
.Tell();
107 rStm
.Seek( nCountPos
);
111 #ifdef STOR_NO_OPTIMIZE
112 rStm
.WriteLen( nObjPos
);
116 /************************************************************************
118 *************************************************************************/
119 SvPersistStream
& operator << ( SvPersistStream
& rStm
,
120 const SvPersistBaseMemberList
& rLst
)
122 rLst
.WriteObjects( rStm
);
126 /************************************************************************
128 *************************************************************************/
129 SvPersistStream
& operator >> ( SvPersistStream
& rStm
,
130 SvPersistBaseMemberList
& rLst
)
135 if( (nVer
& ~PERSIST_LIST_DBGUTIL
) != PERSIST_LIST_VER
)
137 rStm
.SetError( SVSTREAM_GENERALERROR
);
138 DBG_ERROR( "persist list, false version" );
141 UINT32
nObjLen(0), nObjPos(0);
142 if( nVer
& PERSIST_LIST_DBGUTIL
)
143 nObjLen
= rStm
.ReadLen( &nObjPos
);
147 for( ULONG n
= 0; n
< nCount
&& rStm
.GetError() == SVSTREAM_OK
; n
++ )
149 SvPersistBase
* pObj
;
155 if( nObjLen
+ nObjPos
!= rStm
.Tell() )
157 ByteString
aStr( "false list len: read = " );
158 aStr
+= ByteString::CreateFromInt32( (long)(rStm
.Tell() - nObjPos
) );
159 aStr
+= ", should = ";
160 aStr
+= ByteString::CreateFromInt64(nObjLen
);
161 DBG_ERROR( aStr
.GetBuffer() );
167 //=========================================================================
168 SvPersistStream::SvPersistStream
170 SvClassManager
& rMgr
, /* Alle Factorys, deren Objekt geladen und
171 gespeichert werdn k"onnen */
172 SvStream
* pStream
, /* Dieser Stream wird als Medium genommen, auf
173 dem der PersistStream arbeitet */
174 UINT32 nStartIdxP
/* Ab diesem Index werden die Id's f"ur
175 die Objekte vergeben, er muss gr"osser
180 , aPUIdx( nStartIdxP
)
181 , nStartIdx( nStartIdxP
)
186 Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
187 pStream d"urfen nicht ver"andert werden, solange sie in einem
188 SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
189 pStream (siehe <SvPersistStream::SetStream>).
192 DBG_ASSERT( nStartIdx
!= 0, "zero index not allowed" );
196 SetVersion( pStm
->GetVersion() );
197 SetError( pStm
->GetError() );
198 SyncSvStream( pStm
->Tell() );
202 //=========================================================================
203 SvPersistStream::SvPersistStream
205 SvClassManager
& rMgr
, /* Alle Factorys, deren Objekt geladen und
206 gespeichert werdn k"onnen */
207 SvStream
* pStream
, /* Dieser Stream wird als Medium genommen, auf
208 dem der PersistStream arbeitet */
209 const SvPersistStream
& rPersStm
210 /* Wenn PersistStream's verschachtelt werden,
211 dann ist dies der Parent-Stream. */
215 // Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
216 , aPUIdx( rPersStm
.GetCurMaxIndex() +1 )
217 , nStartIdx( rPersStm
.GetCurMaxIndex() +1 )
218 , pRefStm( &rPersStm
)
222 Der Konstruktor der Klasse SvPersistStream. Die Objekte rMgr und
223 pStream d"urfen nicht ver"andert werden, solange sie in einem
224 SvPersistStream eingesetzt sind. Eine Aussnahme gibt es f"ur
225 pStream (siehe <SvPersistStream::SetStream>).
226 Durch diesen Konstruktor wird eine Hierarchiebildung unterst"utzt.
227 Alle Objekte aus einer Hierarchie m"ussen erst geladen werden,
228 wenn das erste aus dieser Hierarchie benutzt werden soll.
234 SetVersion( pStm
->GetVersion() );
235 SetError( pStm
->GetError() );
236 SyncSvStream( pStm
->Tell() );
240 //=========================================================================
241 SvPersistStream::~SvPersistStream()
244 Der Detruktor ruft die Methode <SvPersistStream::SetStream>
251 //=========================================================================
252 void SvPersistStream::SetStream
254 SvStream
* pStream
/* auf diesem Stream arbeitet der PersistStream */
259 Es wird ein Medium (pStream) eingesetzt, auf dem PersistStream arbeitet.
260 Dieses darf nicht von aussen modifiziert werden, solange es
261 eingesetzt ist. Es sei denn, w"ahrend auf dem Medium gearbeitet
262 wird, wird keine Methode von SvPersistStream gerufen, bevor
263 nicht <SvPersistStream::SetStream> mit demselben Medium gerufen
267 if( pStm
!= pStream
)
272 pStm
->SetError( GetError() );
278 SetVersion( pStm
->GetVersion() );
279 SetError( pStm
->GetError() );
280 SyncSvStream( pStm
->Tell() );
284 //=========================================================================
285 USHORT
SvPersistStream::IsA() const
288 Gibt den Identifier dieses Streamklasse zur"uck.
292 USHORT ID_PERSISTSTREAM wird zur"uckgegeben.
300 return ID_PERSISTSTREAM
;
304 /*************************************************************************
305 |* SvPersistStream::ResetError()
306 *************************************************************************/
307 void SvPersistStream::ResetError()
309 SvStream::ResetError();
310 DBG_ASSERT( pStm
, "stream not set" );
314 /*************************************************************************
315 |* SvPersistStream::GetData()
316 *************************************************************************/
317 ULONG
SvPersistStream::GetData( void* pData
, ULONG nSize
)
319 DBG_ASSERT( pStm
, "stream not set" );
320 ULONG nRet
= pStm
->Read( pData
, nSize
);
321 SetError( pStm
->GetError() );
325 /*************************************************************************
326 |* SvPersistStream::PutData()
327 *************************************************************************/
328 ULONG
SvPersistStream::PutData( const void* pData
, ULONG nSize
)
330 DBG_ASSERT( pStm
, "stream not set" );
331 ULONG nRet
= pStm
->Write( pData
, nSize
);
332 SetError( pStm
->GetError() );
336 /*************************************************************************
337 |* SvPersistStream::Seek()
338 *************************************************************************/
339 ULONG
SvPersistStream::SeekPos( ULONG nPos
)
341 DBG_ASSERT( pStm
, "stream not set" );
342 ULONG nRet
= pStm
->Seek( nPos
);
343 SetError( pStm
->GetError() );
347 /*************************************************************************
348 |* SvPersistStream::FlushData()
349 *************************************************************************/
350 void SvPersistStream::FlushData()
354 /*************************************************************************
355 |* SvPersistStream::GetCurMaxIndex()
356 *************************************************************************/
357 ULONG
SvPersistStream::GetCurMaxIndex( const SvPersistUIdx
& rIdx
) const
359 // const bekomme ich nicht den hoechsten Index
360 SvPersistUIdx
* p
= (SvPersistUIdx
*)&rIdx
;
362 ULONG nCurIdx
= p
->GetCurIndex();
364 // Bereiche nicht ueberschneiden, deshalb nur groessere Indexe
365 ULONG nMaxIdx
= p
->GetCurIndex();
371 /*************************************************************************
372 |* SvPersistStream::GetIndex()
373 *************************************************************************/
374 ULONG
SvPersistStream::GetIndex( SvPersistBase
* pObj
) const
376 ULONG nId
= (ULONG
)aPTable
.Get( (ULONG
)pObj
);
377 if( !nId
&& pRefStm
)
378 return pRefStm
->GetIndex( pObj
);
382 /*************************************************************************
383 |* SvPersistStream::GetObject)
384 *************************************************************************/
385 SvPersistBase
* SvPersistStream::GetObject( ULONG nIdx
) const
387 if( nIdx
>= nStartIdx
)
388 return aPUIdx
.Get( nIdx
);
390 return pRefStm
->GetObject( nIdx
);
394 //=========================================================================
399 UINT32
SvPersistStream::ReadCompressed
401 SvStream
& rStm
/* Aus diesem Stream werden die komprimierten Daten
406 Ein im Stream komprimiert abgelegtes Wort wird gelesen. In welchem
407 Format komprimiert wird, siehe <SvPersistStream::WriteCompressed>.
411 UINT32 Das nicht komprimierte Wort wird zur"uckgegeben.
421 nRet
= ~LEN_1
& nMask
;
422 else if( nMask
& LEN_2
)
424 nRet
= ~LEN_2
& nMask
;
429 else if( nMask
& LEN_4
)
431 nRet
= ~LEN_4
& nMask
;
440 else if( nMask
& LEN_5
)
444 rStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
445 DBG_ERROR( "format error" );
451 rStm
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
452 DBG_ERROR( "format error" );
457 //=========================================================================
458 void SvPersistStream::WriteCompressed
460 SvStream
& rStm
,/* Aus diesem Stream werden die komprimierten Daten
462 UINT32 nVal
/* Dieser Wert wird komprimiert geschrieben */
466 Das "ubergebene Wort wird komprimiert und in den Stream
467 geschrieben. Folgendermassen wir komprimiert.
468 nVal < 0x80 => 0x80 + nVal ist 1 Byte gross.
469 nVal < 0x4000 => 0x4000 + nVal ist 2 Byte gross.
470 nVal < 0x20000000 => 0x20000000 + nVal ist 4 Byte gross.
471 nVal > 0x1FFFFFFF => 0x1000000000+ nVal ist 5 Byte gross.
475 <SvPersistStream::ReadCompressed>
478 #ifdef STOR_NO_OPTIMIZE
480 rStm
<< (BYTE
)(LEN_1
| nVal
);
481 else if( nVal
< 0x4000 )
483 rStm
<< (BYTE
)(LEN_2
| (nVal
>> 8));
486 else if( nVal
< 0x20000000 )
489 rStm
<< (BYTE
)(LEN_4
| (nVal
>> 24));
491 rStm
<< (BYTE
)(nVal
>> 16);
492 rStm
<< (USHORT
)(nVal
);
502 //=========================================================================
503 UINT32
SvPersistStream::WriteDummyLen()
506 Die Methode schreibt 4 Byte in den Stream und gibt die Streamposition
511 UINT32 Die Position hinter der L"angenangabe wird zur"uckgegeben.
515 UINT32 nObjPos = rStm.WriteDummyLen();
519 rStm.WriteLen( nObjPos );
523 <SvPersistStream::ReadLen>, <SvPersistStream::WriteLen>
528 UINT32 nPos
= Tell();
531 *this << n0
; // wegen Sun sp
532 // keine Assertion bei Streamfehler
533 DBG_ASSERT( GetError() != SVSTREAM_OK
534 || (sizeof( UINT32
) == Tell() -nPos
),
535 "keine 4-Byte fuer Langenangabe" );
539 //=========================================================================
540 void SvPersistStream::WriteLen
542 UINT32 nObjPos
/* die Position + 4, an der die L"ange geschrieben
547 Die Methode schreibt die Differenz zwischen der aktuellen und
548 nObjPos als UINT32 an die Position nObjPos -4 im Stream. Danach
549 wird der Stream wieder auf die alte Position gestellt.
553 Die Differenz enth"alt nicht die L"angenangabe.
555 UINT32 nObjPos = rStm.WriteDummyLen();
559 rStm.WriteLen( nObjPos );
560 // weitere Daten schreiben
564 <SvPersistStream::ReadLen>, <SvPersistStream::WriteDummyLen>
567 UINT32 nPos
= Tell();
568 UINT32 nLen
= nPos
- nObjPos
;
569 // die Laenge mu� im stream 4-Byte betragen
570 Seek( nObjPos
- sizeof( UINT32
) );
576 //=========================================================================
577 UINT32
SvPersistStream::ReadLen
579 UINT32
* pTestPos
/* Die Position des Streams, nach dem Lesen der
580 L"ange, wird zur"uckgegeben. Es darf auch NULL
581 "ubergeben werden. */
585 Liest die L"ange die vorher mit <SvPersistStream::WriteDummyLen>
586 und <SvPersistStream::WriteLen> geschrieben wurde.
596 //=========================================================================
597 // Dateirormat abw"arts kompatibel
598 #ifdef STOR_NO_OPTIMIZE
599 #define P_VER (BYTE)0x00
601 #define P_VER (BYTE)0x01
603 #define P_VER_MASK (BYTE)0x0F
604 #define P_ID_0 (BYTE)0x80
605 #define P_OBJ (BYTE)0x40
606 #define P_DBGUTIL (BYTE)0x20
607 #define P_ID (BYTE)0x10
608 #ifdef STOR_NO_OPTIMIZE
609 #define P_STD P_DBGUTIL
622 #ifdef STOR_NO_OPTIMIZE
628 if( (nHdr
& P_OBJ
) || nId
!= 0 )
629 { // Id nur bei Zeiger, oder DBGUTIL
630 rStm
<< (BYTE
)(nHdr
);
631 SvPersistStream::WriteCompressed( rStm
, nId
);
635 rStm
<< (BYTE
)(nHdr
| P_ID_0
);
642 if( (nHdr
& P_DBGUTIL
) || (nHdr
& P_OBJ
) )
643 // Objekte haben immer eine Klasse,
644 // Pointer nur bei DBG_UTIL und != NULL
645 SvPersistStream::WriteCompressed( rStm
, nClassId
);
648 //=========================================================================
663 if( (nHdr
& P_VER_MASK
) == 0 )
665 if( (nHdr
& P_DBGUTIL
) || !(nHdr
& P_OBJ
) )
666 nId
= SvPersistStream::ReadCompressed( rStm
);
670 else if( nHdr
& P_ID
)
671 nId
= SvPersistStream::ReadCompressed( rStm
);
673 if( (nHdr
& P_DBGUTIL
) || (nHdr
& P_OBJ
) )
674 nClassId
= (USHORT
)SvPersistStream::ReadCompressed( rStm
);
678 //=========================================================================
679 void SvPersistStream::WriteObj
685 #ifdef STOR_NO_OPTIMIZE
687 if( nHdr
& P_DBGUTIL
)
688 // Position fuer Laenge merken
689 nObjPos
= WriteDummyLen();
692 #ifdef STOR_NO_OPTIMIZE
693 if( nHdr
& P_DBGUTIL
)
698 //=========================================================================
699 SvPersistStream
& SvPersistStream::WritePointer
708 ULONG nId
= GetIndex( pObj
);
713 nId
= aPUIdx
.Insert( pObj
);
714 aPTable
.Insert( (ULONG
)pObj
, (void *)nId
);
717 WriteId( *this, nP
, nId
, pObj
->GetClassId() );
719 WriteObj( nP
, pObj
);
723 WriteId( *this, nP
| P_ID
, 0, 0 );
728 //=========================================================================
729 UINT32
SvPersistStream::ReadObj
731 SvPersistBase
* & rpObj
,
739 rpObj
= NULL
; // Spezifikation: Im Fehlerfall 0.
740 ReadId( *this, nHdr
, nId
, nClassId
);
742 // reine Versionsnummer durch maskieren
743 if( P_VER
< (nHdr
& P_VER_MASK
) )
745 SetError( SVSTREAM_FILEFORMAT_ERROR
);
746 DBG_ERROR( "false version" );
749 if( !(nHdr
& P_ID_0
) && GetError() == SVSTREAM_OK
)
752 { // read object, nId nur bei P_DBGUTIL gesetzt
753 DBG_ASSERT( !(nHdr
& P_DBGUTIL
) || NULL
== aPUIdx
.Get( nId
),
754 "object already exist" );
755 SvCreateInstancePersist pFunc
= rClassMgr
.Get( nClassId
);
757 UINT32
nObjLen(0), nObjPos(0);
758 if( nHdr
& P_DBGUTIL
)
759 nObjLen
= ReadLen( &nObjPos
);
763 ByteString
aStr( "no class with id: " );
764 aStr
+= ByteString::CreateFromInt32( nClassId
);
765 aStr
+= " registered";
766 DBG_WARNING( aStr
.GetBuffer() );
768 SetError( ERRCODE_IO_NOFACTORY
);
777 // unbedingt erst in Tabelle eintragen
778 ULONG nNewId
= aPUIdx
.Insert( rpObj
);
779 // um den gleichen Zustand, wie nach dem Speichern herzustellen
780 aPTable
.Insert( (ULONG
)rpObj
, (void *)nNewId
);
781 DBG_ASSERT( !(nHdr
& P_DBGUTIL
) || nId
== nNewId
,
782 "read write id conflict: not the same" );
785 rpObj
->Load( *this );
787 if( nObjLen
+ nObjPos
!= Tell() )
789 ByteString
aStr( "false object len: read = " );
790 aStr
+= ByteString::CreateFromInt32( (long)(Tell() - nObjPos
) );
791 aStr
+= ", should = ";
792 aStr
+= ByteString::CreateFromInt32( nObjLen
);
793 DBG_ERROR( aStr
.GetBuffer() );
796 rpObj
->RestoreNoDelete();
801 rpObj
= GetObject( nId
);
802 DBG_ASSERT( rpObj
!= NULL
, "object does not exist" );
803 DBG_ASSERT( rpObj
->GetClassId() == nClassId
, "class mismatch" );
809 //=========================================================================
810 SvPersistStream
& SvPersistStream::ReadPointer
812 SvPersistBase
* & rpObj
815 ReadObj( rpObj
, TRUE
);
819 //=========================================================================
820 SvPersistStream
& operator <<
822 SvPersistStream
& rStm
,
826 return rStm
.WritePointer( pObj
);
829 //=========================================================================
830 SvPersistStream
& operator >>
832 SvPersistStream
& rStm
,
833 SvPersistBase
* & rpObj
836 return rStm
.ReadPointer( rpObj
);
839 //=========================================================================
840 SvStream
& operator <<
843 SvPersistStream
& rThis
846 SvStream
* pOldStm
= rThis
.GetStream();
847 rThis
.SetStream( &rStm
);
850 rThis
<< bTmp
; // Version
851 UINT32 nCount
= (UINT32
)rThis
.aPUIdx
.Count();
853 SvPersistBase
* pEle
= rThis
.aPUIdx
.First();
854 for( UINT32 i
= 0; i
< nCount
; i
++ )
856 BYTE nP
= P_OBJ
| P_ID
| P_STD
;
857 WriteId( rThis
, nP
, rThis
.aPUIdx
.GetCurIndex(),
858 pEle
->GetClassId() );
859 rThis
.WriteObj( nP
, pEle
);
860 pEle
= rThis
.aPUIdx
.Next();
862 rThis
.SetStream( pOldStm
);
866 //=========================================================================
867 SvStream
& operator >>
870 SvPersistStream
& rThis
873 SvStream
* pOldStm
= rThis
.GetStream();
874 rThis
.SetStream( &rStm
);
877 rThis
>> nVers
; // Version
882 for( UINT32 i
= 0; i
< nCount
; i
++ )
884 SvPersistBase
* pEle
;
885 // Lesen, ohne in die Tabellen einzutragen
886 UINT32 nId
= rThis
.ReadObj( pEle
, FALSE
);
887 if( rThis
.GetError() )
890 // Die Id eines Objektes wird nie modifiziert
891 rThis
.aPUIdx
.Insert( nId
, pEle
);
892 rThis
.aPTable
.Insert( (ULONG
)pEle
, (void *)nId
);
896 rThis
.SetError( SVSTREAM_FILEFORMAT_ERROR
);
898 rThis
.SetStream( pOldStm
);
902 //=========================================================================
903 ULONG
SvPersistStream::InsertObj( SvPersistBase
* pObj
)
905 ULONG nId
= aPUIdx
.Insert( pObj
);
906 aPTable
.Insert( (ULONG
)pObj
, (void *)nId
);
910 //=========================================================================
911 ULONG
SvPersistStream::RemoveObj( SvPersistBase
* pObj
)
913 ULONG nIdx
= GetIndex( pObj
);
914 aPUIdx
.Remove( nIdx
);
915 aPTable
.Remove( (ULONG
)pObj
);