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