Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 : #include <tools/pstm.hxx>
22 : #include <rtl/strbuf.hxx>
23 :
24 : #define STOR_NO_OPTIMIZE
25 :
26 2438 : void SvClassManager::Register( sal_Int32 nClassId, SvCreateInstancePersist pFunc )
27 : {
28 : #ifdef DBG_UTIL
29 : SvCreateInstancePersist p;
30 : p = Get( nClassId );
31 : DBG_ASSERT( !p || p == pFunc, "register class with same id" );
32 : #endif
33 2438 : aAssocTable.insert(Map::value_type(nClassId, pFunc));
34 2438 : }
35 :
36 0 : SvCreateInstancePersist SvClassManager::Get( sal_Int32 nClassId )
37 : {
38 0 : Map::const_iterator i(aAssocTable.find(nClassId));
39 0 : return i == aAssocTable.end() ? 0 : i->second;
40 : }
41 :
42 : // SvRttiBase
43 12016 : TYPEINIT0( SvRttiBase );
44 :
45 : /** Constructor
46 :
47 : @param rMgr Stores factories for objects that can persisted
48 : @param pStream This stream is used as the medium for PersistStream
49 : @param nStartIdxP Start value for object identifier (set > 0 )
50 :
51 : @warning Objects rMgr and pStream must not be manipulated while used in
52 : SvPersistStream. An Exception to this is pvStream
53 : (cf. <SvPersistStream::SetStream>).
54 : @see SvPersistStream::SetStream
55 : */
56 0 : SvPersistStream::SvPersistStream( SvClassManager & rMgr, SvStream * pStream, sal_uInt32 nStartIdxP )
57 : : rClassMgr( rMgr )
58 : , pStm( pStream )
59 : , aPUIdx( nStartIdxP )
60 : , nStartIdx( nStartIdxP )
61 : , pRefStm( NULL )
62 0 : , nFlags( 0 )
63 : {
64 : DBG_ASSERT( nStartIdx != 0, "zero index not allowed" );
65 0 : bIsWritable = true;
66 0 : if( pStm )
67 : {
68 0 : SetVersion( pStm->GetVersion() );
69 0 : SetError( pStm->GetError() );
70 0 : SyncSvStream( pStm->Tell() );
71 : }
72 0 : }
73 :
74 0 : SvPersistStream::~SvPersistStream()
75 : {
76 0 : SetStream( NULL );
77 0 : }
78 :
79 : /**
80 :
81 : @param pStream This stream is used as the medium for PersistStream
82 :
83 : @warning pStream is used as the medium for PersistStream.
84 : It must not be manipulated while used in SvPersistStream.
85 : An Exception to this is pvStream (cf. <SvPersistStream::SetStream>).
86 : */
87 0 : void SvPersistStream::SetStream( SvStream * pStream )
88 : {
89 0 : if( pStm != pStream )
90 : {
91 0 : if( pStm )
92 : {
93 0 : SyncSysStream();
94 0 : pStm->SetError( GetError() );
95 : }
96 0 : pStm = pStream;
97 : }
98 0 : if( pStm )
99 : {
100 0 : SetVersion( pStm->GetVersion() );
101 0 : SetError( pStm->GetError() );
102 0 : SyncSvStream( pStm->Tell() );
103 : }
104 0 : }
105 :
106 0 : void SvPersistStream::ResetError()
107 : {
108 0 : SvStream::ResetError();
109 : DBG_ASSERT( pStm, "stream not set" );
110 0 : pStm->ResetError();
111 0 : }
112 :
113 0 : sal_uIntPtr SvPersistStream::GetData( void* pData, sal_uIntPtr nSize )
114 : {
115 : DBG_ASSERT( pStm, "stream not set" );
116 0 : sal_uIntPtr nRet = pStm->Read( pData, nSize );
117 0 : SetError( pStm->GetError() );
118 0 : return nRet;
119 : }
120 :
121 0 : sal_uIntPtr SvPersistStream::PutData( const void* pData, sal_uIntPtr nSize )
122 : {
123 : DBG_ASSERT( pStm, "stream not set" );
124 0 : sal_uIntPtr nRet = pStm->Write( pData, nSize );
125 0 : SetError( pStm->GetError() );
126 0 : return nRet;
127 : }
128 :
129 0 : sal_uInt64 SvPersistStream::SeekPos(sal_uInt64 const nPos)
130 : {
131 : DBG_ASSERT( pStm, "stream not set" );
132 0 : sal_uInt64 nRet = pStm->Seek( nPos );
133 0 : SetError( pStm->GetError() );
134 0 : return nRet;
135 : }
136 :
137 0 : void SvPersistStream::FlushData()
138 : {
139 0 : }
140 :
141 0 : sal_uIntPtr SvPersistStream::GetIndex( SvPersistBase * pObj ) const
142 : {
143 0 : PersistBaseMap::const_iterator it = aPTable.find( pObj );
144 0 : if( it == aPTable.end() )
145 : {
146 0 : if ( pRefStm )
147 0 : return pRefStm->GetIndex( pObj );
148 : else
149 0 : return 0;
150 : }
151 0 : return it->second;
152 : }
153 :
154 0 : SvPersistBase * SvPersistStream::GetObject( sal_uIntPtr nIdx ) const
155 : {
156 0 : if( nIdx >= nStartIdx )
157 0 : return aPUIdx.Get( nIdx );
158 0 : else if( pRefStm )
159 0 : return pRefStm->GetObject( nIdx );
160 0 : return NULL;
161 : }
162 :
163 : #define LEN_1 0x80
164 : #define LEN_2 0x40
165 : #define LEN_4 0x20
166 : #define LEN_5 0x10
167 :
168 : /** Reads a compressed word from the stream.
169 :
170 : For details on what format is used for compression, see
171 : <SvPersistStream::WriteCompressed>.
172 :
173 : @param rStm Source to read compressed data from
174 :
175 : @return Uncompressed word
176 : @see SvPersistStream::WriteCompressed
177 : */
178 0 : sal_uInt32 SvPersistStream::ReadCompressed( SvStream & rStm )
179 : {
180 0 : sal_uInt32 nRet(0);
181 : sal_uInt8 nMask;
182 0 : rStm.ReadUChar( nMask );
183 0 : if( nMask & LEN_1 )
184 0 : nRet = ~LEN_1 & nMask;
185 0 : else if( nMask & LEN_2 )
186 : {
187 0 : nRet = ~LEN_2 & nMask;
188 0 : nRet <<= 8;
189 0 : rStm.ReadUChar( nMask );
190 0 : nRet |= nMask;
191 : }
192 0 : else if( nMask & LEN_4 )
193 : {
194 0 : nRet = ~LEN_4 & nMask;
195 0 : nRet <<= 8;
196 0 : rStm.ReadUChar( nMask );
197 0 : nRet |= nMask;
198 0 : nRet <<= 16;
199 : sal_uInt16 n;
200 0 : rStm.ReadUInt16( n );
201 0 : nRet |= n;
202 : }
203 0 : else if( nMask & LEN_5 )
204 : {
205 0 : if( nMask & 0x0F )
206 : {
207 0 : rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
208 : OSL_FAIL( "format error" );
209 : }
210 0 : rStm.ReadUInt32( nRet );
211 : }
212 : else
213 : {
214 0 : rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
215 : OSL_FAIL( "format error" );
216 : }
217 0 : return nRet;
218 : }
219 :
220 : /** Writes compressed stream
221 :
222 : @param rStm Source for writing compressed data
223 : @param nVal This value will be compressed and written
224 :
225 : nVal is compressed and written to stream using the following algorithm
226 : nVal < 0x80 => 0x80 + nVal of size 1 Byte.
227 : nVal < 0x4000 => 0x4000 + nVal of size 2 Byte.
228 : nVal < 0x20000000 => 0x20000000 + nVal of size 4 Byte.
229 : nVal > 0x1FFFFFFF => 0x1000000000+ nVal of size 5 Byte.
230 :
231 : @see SvPersistStream::ReadCompressed
232 : */
233 0 : void SvPersistStream::WriteCompressed( SvStream & rStm, sal_uInt32 nVal )
234 : {
235 : #ifdef STOR_NO_OPTIMIZE
236 0 : if( nVal < 0x80 )
237 0 : rStm.WriteUChar( (LEN_1 | nVal) );
238 0 : else if( nVal < 0x4000 )
239 : {
240 0 : rStm.WriteUChar( (LEN_2 | (nVal >> 8)) );
241 0 : rStm.WriteUChar( nVal );
242 : }
243 0 : else if( nVal < 0x20000000 )
244 : {
245 : // highest sal_uInt8
246 0 : rStm.WriteUChar( (LEN_4 | (nVal >> 24)) );
247 : // 2nd highest sal_uInt8
248 0 : rStm.WriteUChar( (nVal >> 16) );
249 0 : rStm.WriteUInt16( (nVal) );
250 : }
251 : else
252 : #endif
253 : {
254 0 : rStm.WriteUChar( LEN_5 );
255 0 : rStm.WriteUInt32( nVal );
256 : }
257 0 : }
258 :
259 : /** This method writes length value of 4 Bytes to the stream and returns the
260 : stream position.
261 :
262 : Example:
263 : @code
264 : sal_uInt32 nObjPos = rStm.WriteDummyLen();
265 : ...
266 : // write data
267 : ...
268 : rStm.WriteLen( nObjPos );
269 : @endcode
270 :
271 : @return Position of stream behind length value
272 :
273 : @see SvPersistStream::ReadLen
274 : @see SvPersistStream::WriteLen
275 : */
276 0 : sal_uInt32 SvPersistStream::WriteDummyLen()
277 : {
278 : #ifdef DBG_UTIL
279 : sal_uInt32 nPos = Tell();
280 : #endif
281 0 : sal_uInt32 n0 = 0;
282 0 : WriteUInt32( n0 ); // Because of Sun sp
283 : // Don't assert on stream error
284 : DBG_ASSERT( GetError() != SVSTREAM_OK
285 : || (sizeof( sal_uInt32 ) == Tell() -nPos),
286 : "No 4 byte as length parameter" );
287 0 : return Tell();
288 : }
289 :
290 : /** Write difference between current position and nObjPos
291 : as sal_uInt32 to position nObjPos-4 in the stream.
292 :
293 : Afterwards, reset stream to old position.
294 :
295 : Example: Difference does not contain length value
296 : @code
297 : sal_uInt32 nObjPos = rStm.WriteDummyLen();
298 : ...
299 : // write data
300 : ...
301 : rStm.WriteLen( nObjPos );
302 : // write more data
303 : @endcode
304 :
305 : @param nObjPos Position+4, on which length is written to
306 :
307 : @see SvPersistStream::ReadLen
308 : @see SvPersistStream::WriteDummyLen
309 : */
310 0 : void SvPersistStream::WriteLen( sal_uInt32 nObjPos )
311 : {
312 0 : sal_uInt32 nPos = Tell();
313 0 : sal_uInt32 nLen = nPos - nObjPos;
314 : // Length in stream must be 4 Bytes
315 0 : Seek( nObjPos - sizeof( sal_uInt32 ) );
316 : // write length
317 0 : WriteUInt32( nLen );
318 0 : Seek( nPos );
319 0 : }
320 :
321 : /** Read a length value written to stream
322 :
323 : @param pTestPos Position of the stream after reading length. May be NULL.
324 :
325 : @see SvPersistStream::WriteDummyLen
326 : @see SvPersistStream::WriteLen
327 : */
328 0 : sal_uInt32 SvPersistStream::ReadLen( sal_uInt32 * pTestPos )
329 : {
330 : sal_uInt32 nLen;
331 0 : ReadUInt32( nLen );
332 0 : if( pTestPos )
333 0 : *pTestPos = Tell();
334 0 : return nLen;
335 : }
336 :
337 : // File format backward-compatible
338 : #ifdef STOR_NO_OPTIMIZE
339 : #define P_VER (sal_uInt8)0x00
340 : #else
341 : #define P_VER (sal_uInt8)0x01
342 : #endif
343 : #define P_VER_MASK (sal_uInt8)0x0F
344 : #define P_ID_0 (sal_uInt8)0x80
345 : #define P_OBJ (sal_uInt8)0x40
346 : #define P_DBGUTIL (sal_uInt8)0x20
347 : #define P_ID (sal_uInt8)0x10
348 : #ifdef STOR_NO_OPTIMIZE
349 : #define P_STD P_DBGUTIL
350 : #else
351 : #define P_STD 0
352 : #endif
353 :
354 0 : static void WriteId
355 : (
356 : SvStream & rStm,
357 : sal_uInt8 nHdr,
358 : sal_uInt32 nId,
359 : sal_uInt16 nClassId
360 : )
361 : {
362 : #ifdef STOR_NO_OPTIMIZE
363 0 : nHdr |= P_ID;
364 : #endif
365 0 : nHdr |= P_VER;
366 0 : if( nHdr & P_ID )
367 : {
368 0 : if( (nHdr & P_OBJ) || nId != 0 )
369 : { // Id set only for pointers or DBGUTIL
370 0 : rStm.WriteUChar( (nHdr) );
371 0 : SvPersistStream::WriteCompressed( rStm, nId );
372 : }
373 : else
374 : { // NULL Pointer
375 0 : rStm.WriteUChar( (nHdr | P_ID_0) );
376 0 : return;
377 : }
378 : }
379 : else
380 0 : rStm.WriteUChar( nHdr );
381 :
382 0 : if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
383 : // Objects always have a class id
384 : // Pointers only for DBG_UTIL and != NULL
385 0 : SvPersistStream::WriteCompressed( rStm, nClassId );
386 : }
387 :
388 0 : static void ReadId
389 : (
390 : SvStream & rStm,
391 : sal_uInt8 & nHdr,
392 : sal_uInt32 & nId,
393 : sal_uInt16 & nClassId
394 : )
395 : {
396 0 : nClassId = 0;
397 0 : rStm.ReadUChar( nHdr );
398 0 : if( nHdr & P_ID_0 )
399 0 : nId = 0;
400 : else
401 : {
402 0 : if( (nHdr & P_VER_MASK) == 0 )
403 : {
404 0 : if( (nHdr & P_DBGUTIL) || !(nHdr & P_OBJ) )
405 0 : nId = SvPersistStream::ReadCompressed( rStm );
406 : else
407 0 : nId = 0;
408 : }
409 0 : else if( nHdr & P_ID )
410 0 : nId = SvPersistStream::ReadCompressed( rStm );
411 :
412 0 : if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
413 0 : nClassId = (sal_uInt16)SvPersistStream::ReadCompressed( rStm );
414 : }
415 0 : }
416 :
417 0 : void SvPersistStream::WriteObj
418 : (
419 : sal_uInt8 nHdr,
420 : SvPersistBase * pObj
421 : )
422 : {
423 : #ifdef STOR_NO_OPTIMIZE
424 0 : sal_uInt32 nObjPos = 0;
425 0 : if( nHdr & P_DBGUTIL )
426 : // remember position for length value
427 0 : nObjPos = WriteDummyLen();
428 : #endif
429 0 : pObj->Save( *this );
430 : #ifdef STOR_NO_OPTIMIZE
431 0 : if( nHdr & P_DBGUTIL )
432 0 : WriteLen( nObjPos );
433 : #endif
434 0 : }
435 :
436 0 : SvPersistStream& SvPersistStream::WritePointer
437 : (
438 : SvPersistBase * pObj
439 : )
440 : {
441 0 : sal_uInt8 nP = P_STD;
442 :
443 0 : if( pObj )
444 : {
445 0 : sal_uIntPtr nId = GetIndex( pObj );
446 0 : if( nId )
447 0 : nP |= P_ID;
448 : else
449 : {
450 0 : nId = aPUIdx.Insert( pObj );
451 0 : aPTable[ pObj ] = nId;
452 0 : nP |= P_OBJ;
453 : }
454 0 : WriteId( *this, nP, nId, pObj->GetClassId() );
455 0 : if( nP & P_OBJ )
456 0 : WriteObj( nP, pObj );
457 : }
458 : else
459 : { // NULL Pointer
460 0 : WriteId( *this, nP | P_ID, 0, 0 );
461 : }
462 0 : return *this;
463 : }
464 :
465 0 : sal_uInt32 SvPersistStream::ReadObj
466 : (
467 : SvPersistBase * & rpObj,
468 : bool bRegister
469 : )
470 : {
471 : sal_uInt8 nHdr;
472 0 : sal_uInt32 nId = 0;
473 : sal_uInt16 nClassId;
474 :
475 0 : rpObj = NULL; // specification: 0 in case of error
476 0 : ReadId( *this, nHdr, nId, nClassId );
477 :
478 : // get version number through masking
479 0 : if( P_VER < (nHdr & P_VER_MASK) )
480 : {
481 0 : SetError( SVSTREAM_FILEFORMAT_ERROR );
482 : OSL_FAIL( "false version" );
483 : }
484 :
485 0 : if( !(nHdr & P_ID_0) && GetError() == SVSTREAM_OK )
486 : {
487 0 : if( P_OBJ & nHdr )
488 : { // read object, nId only set for P_DBGUTIL
489 : DBG_ASSERT( !(nHdr & P_DBGUTIL) || NULL == aPUIdx.Get( nId ),
490 : "object already exist" );
491 0 : SvCreateInstancePersist pFunc = rClassMgr.Get( nClassId );
492 :
493 0 : sal_uInt32 nObjLen(0), nObjPos(0);
494 0 : if( nHdr & P_DBGUTIL )
495 0 : nObjLen = ReadLen( &nObjPos );
496 0 : if( !pFunc )
497 : {
498 : #ifdef DBG_UTIL
499 : OStringBuffer aStr("no class with id: " );
500 : aStr.append(static_cast<sal_Int32>(nClassId));
501 : aStr.append(" registered");
502 : DBG_WARNING(aStr.getStr());
503 : #else
504 : (void)nObjLen;
505 : #endif
506 0 : SetError( ERRCODE_IO_NOFACTORY );
507 0 : return 0;
508 : }
509 0 : pFunc( &rpObj );
510 : // Save reference
511 0 : rpObj->AddFirstRef();
512 :
513 0 : if( bRegister )
514 : {
515 : // insert into table
516 0 : sal_uIntPtr nNewId = aPUIdx.Insert( rpObj );
517 : // in order to restore state after saving
518 0 : aPTable[ rpObj ] = nNewId;
519 : DBG_ASSERT( !(nHdr & P_DBGUTIL) || nId == nNewId,
520 : "read write id conflict: not the same" );
521 : }
522 0 : rpObj->Load( *this );
523 : #ifdef DBG_UTIL
524 : if( nObjLen + nObjPos != Tell() )
525 : {
526 : OStringBuffer aStr("false object len: read = ");
527 : aStr.append(static_cast<sal_Int64>((long)(Tell() - nObjPos)));
528 : aStr.append(", should = ");
529 : aStr.append(static_cast<sal_Int32>(nObjLen));
530 : OSL_FAIL(aStr.getStr());
531 : }
532 : #endif
533 0 : rpObj->RestoreNoDelete();
534 0 : rpObj->ReleaseRef();
535 : }
536 : else
537 : {
538 0 : rpObj = GetObject( nId );
539 : DBG_ASSERT( rpObj != NULL, "object does not exist" );
540 : DBG_ASSERT( rpObj->GetClassId() == nClassId, "class mismatch" );
541 : }
542 : }
543 0 : return nId;
544 : }
545 :
546 0 : SvPersistStream& SvPersistStream::ReadPointer
547 : (
548 : SvPersistBase * & rpObj
549 : )
550 : {
551 0 : ReadObj( rpObj, true );
552 0 : return *this;
553 : }
554 :
555 0 : SvPersistStream& WriteSvPersistBase
556 : (
557 : SvPersistStream & rStm,
558 : SvPersistBase * pObj
559 : )
560 : {
561 0 : return rStm.WritePointer( pObj );
562 : }
563 :
564 0 : SvPersistStream& operator >>
565 : (
566 : SvPersistStream & rStm,
567 : SvPersistBase * & rpObj
568 : )
569 : {
570 0 : return rStm.ReadPointer( rpObj );
571 : }
572 :
573 0 : SvStream& WriteSvPersistStream
574 : (
575 : SvStream & rStm,
576 : SvPersistStream & rThis
577 : )
578 : {
579 0 : SvStream * pOldStm = rThis.GetStream();
580 0 : rThis.SetStream( &rStm );
581 :
582 0 : sal_uInt8 bTmp = 0;
583 0 : rThis.WriteUChar( bTmp ); // Version
584 0 : sal_uInt32 nCount = (sal_uInt32)rThis.aPUIdx.Count();
585 0 : rThis.WriteUInt32( nCount );
586 0 : sal_uIntPtr aIndex = rThis.aPUIdx.FirstIndex();
587 0 : for( sal_uInt32 i = 0; i < nCount; i++ )
588 : {
589 0 : SvPersistBase * pEle = rThis.aPUIdx.Get(aIndex);
590 0 : sal_uInt8 nP = P_OBJ | P_ID | P_STD;
591 0 : WriteId( rThis, nP, aIndex, pEle->GetClassId() );
592 0 : rThis.WriteObj( nP, pEle );
593 0 : aIndex = rThis.aPUIdx.NextIndex( aIndex );
594 : }
595 0 : rThis.SetStream( pOldStm );
596 0 : return rStm;
597 : }
598 :
599 0 : SvStream& operator >>
600 : (
601 : SvStream & rStm,
602 : SvPersistStream & rThis
603 : )
604 : {
605 0 : SvStream * pOldStm = rThis.GetStream();
606 0 : rThis.SetStream( &rStm );
607 :
608 : sal_uInt8 nVers;
609 0 : rThis.ReadUChar( nVers ); // Version
610 0 : if( 0 == nVers )
611 : {
612 0 : sal_uInt32 nCount = 0;
613 0 : rThis.ReadUInt32( nCount );
614 0 : for( sal_uInt32 i = 0; i < nCount; i++ )
615 : {
616 : SvPersistBase * pEle;
617 : // read, but don't insert into table
618 0 : sal_uIntPtr nId = rThis.ReadObj( pEle, false );
619 0 : if( rThis.GetError() )
620 0 : break;
621 :
622 : // Id of object is never modified
623 0 : rThis.aPUIdx.Insert( nId, pEle );
624 0 : rThis.aPTable[ pEle ] = nId;
625 : }
626 : }
627 : else
628 0 : rThis.SetError( SVSTREAM_FILEFORMAT_ERROR );
629 :
630 0 : rThis.SetStream( pOldStm );
631 0 : return rStm;
632 : }
633 :
634 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|