fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / tools / source / ref / pstm.cxx
blob66e4a28909c78babb6fc14f692c333250e92fdd8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tools/debug.hxx>
21 #include <tools/pstm.hxx>
22 #include <rtl/strbuf.hxx>
24 #define STOR_NO_OPTIMIZE
26 void SvClassManager::Register( sal_Int32 nClassId, SvCreateInstancePersist pFunc )
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 aAssocTable.insert(Map::value_type(nClassId, pFunc));
36 SvCreateInstancePersist SvClassManager::Get( sal_Int32 nClassId )
38 Map::const_iterator i(aAssocTable.find(nClassId));
39 return i == aAssocTable.end() ? 0 : i->second;
42 // SvRttiBase
43 TYPEINIT0( SvRttiBase );
45 // SvPersistBaseMemberList
47 #define PERSIST_LIST_VER (sal_uInt8)0
48 #define PERSIST_LIST_DBGUTIL (sal_uInt8)0x80
50 void TOOLS_DLLPUBLIC WritePersistListObjects(const SvPersistListWriteable& rList, SvPersistStream & rStm, bool bOnlyStreamed )
52 #ifdef STOR_NO_OPTIMIZE
53 rStm << (sal_uInt8)(PERSIST_LIST_VER | PERSIST_LIST_DBGUTIL);
54 sal_uInt32 nObjPos = rStm.WriteDummyLen();
55 #else
56 sal_uInt8 bTmp = PERSIST_LIST_VER;
57 rStm << bTmp;
58 #endif
59 sal_uInt32 nCountMember = rList.size();
60 sal_uIntPtr nCountPos = rStm.Tell();
61 sal_uInt32 nWriteCount = 0;
62 rStm << nCountMember;
63 // Don't change the list, as it causes side-effects while saving
64 for( sal_uIntPtr n = 0; n < nCountMember; n++ )
66 SvPersistBase * pObj = rList.GetPersistBase( n );
67 if( !bOnlyStreamed || rStm.IsStreamed( pObj ) )
68 { // Object should be stored
69 rStm << pObj;
70 nWriteCount++;
73 if( nWriteCount != nCountMember )
75 // Didn't write all members, adjust count
76 sal_uIntPtr nPos = rStm.Tell();
77 rStm.Seek( nCountPos );
78 rStm << nWriteCount;
79 rStm.Seek( nPos );
81 #ifdef STOR_NO_OPTIMIZE
82 rStm.WriteLen( nObjPos );
83 #endif
86 void TOOLS_DLLPUBLIC ReadObjects( SvPersistListReadable& rLst, SvPersistStream & rStm )
88 sal_uInt8 nVer;
89 rStm >> nVer;
91 if( (nVer & ~PERSIST_LIST_DBGUTIL) != PERSIST_LIST_VER )
93 rStm.SetError( SVSTREAM_GENERALERROR );
94 OSL_FAIL( "persist list, false version" );
97 sal_uInt32 nObjLen(0), nObjPos(0);
98 if( nVer & PERSIST_LIST_DBGUTIL )
99 nObjLen = rStm.ReadLen( &nObjPos );
101 sal_uInt32 nCount;
102 rStm >> nCount;
103 for( sal_uIntPtr n = 0; n < nCount && rStm.GetError() == SVSTREAM_OK; n++ )
105 SvPersistBase * pObj;
106 rStm >> pObj;
107 if( pObj )
108 rLst.push_back( pObj );
110 #ifdef DBG_UTIL
111 if( nObjLen + nObjPos != rStm.Tell() )
113 OStringBuffer aStr("false list len: read = ");
114 aStr.append(static_cast<sal_Int64>(rStm.Tell() - nObjPos));
115 aStr.append(", should = ");
116 aStr.append(static_cast<sal_Int64>(nObjLen));
117 OSL_FAIL(aStr.getStr());
119 #else
120 (void)nObjLen;
121 #endif
124 /** Constructor
126 @param rMgr Stores factories for objects that can persisted
127 @param pStream This stream is used as the medium for PersistStream
128 @param nStartIdxP Start value for object identifier (set > 0 )
130 @warning Objects rMgr and pStream must not be manipulated while used in
131 SvPersistStream. An Exception to this is pvStream
132 (cf. <SvPersistStream::SetStream>).
133 @see SvPersistStream::SetStream
135 SvPersistStream::SvPersistStream( SvClassManager & rMgr, SvStream * pStream, sal_uInt32 nStartIdxP )
136 : rClassMgr( rMgr )
137 , pStm( pStream )
138 , aPUIdx( nStartIdxP )
139 , nStartIdx( nStartIdxP )
140 , pRefStm( NULL )
141 , nFlags( 0 )
143 DBG_ASSERT( nStartIdx != 0, "zero index not allowed" );
144 bIsWritable = sal_True;
145 if( pStm )
147 SetVersion( pStm->GetVersion() );
148 SetError( pStm->GetError() );
149 SyncSvStream( pStm->Tell() );
153 SvPersistStream::~SvPersistStream()
155 SetStream( NULL );
160 @param pStream This stream is used as the medium for PersistStream
162 @warning pStream is used as the medium for PersistStream.
163 It must not be manipulated while used in SvPersistStream.
164 An Exception to this is pvStream (cf. <SvPersistStream::SetStream>).
166 void SvPersistStream::SetStream( SvStream * pStream )
168 if( pStm != pStream )
170 if( pStm )
172 SyncSysStream();
173 pStm->SetError( GetError() );
175 pStm = pStream;
177 if( pStm )
179 SetVersion( pStm->GetVersion() );
180 SetError( pStm->GetError() );
181 SyncSvStream( pStm->Tell() );
185 /** Returns the identifier of this stream class.
187 @return ID_PERSISTSTREAM
189 @see SvStream::IsA
191 sal_uInt16 SvPersistStream::IsA() const
193 return ID_PERSISTSTREAM;
196 void SvPersistStream::ResetError()
198 SvStream::ResetError();
199 DBG_ASSERT( pStm, "stream not set" );
200 pStm->ResetError();
203 sal_uIntPtr SvPersistStream::GetData( void* pData, sal_uIntPtr nSize )
205 DBG_ASSERT( pStm, "stream not set" );
206 sal_uIntPtr nRet = pStm->Read( pData, nSize );
207 SetError( pStm->GetError() );
208 return nRet;
211 sal_uIntPtr SvPersistStream::PutData( const void* pData, sal_uIntPtr nSize )
213 DBG_ASSERT( pStm, "stream not set" );
214 sal_uIntPtr nRet = pStm->Write( pData, nSize );
215 SetError( pStm->GetError() );
216 return nRet;
219 sal_uIntPtr SvPersistStream::SeekPos( sal_uIntPtr nPos )
221 DBG_ASSERT( pStm, "stream not set" );
222 sal_uIntPtr nRet = pStm->Seek( nPos );
223 SetError( pStm->GetError() );
224 return nRet;
227 void SvPersistStream::FlushData()
231 sal_uIntPtr SvPersistStream::GetIndex( SvPersistBase * pObj ) const
233 PersistBaseMap::const_iterator it = aPTable.find( pObj );
234 if( it == aPTable.end() )
236 if ( pRefStm )
237 return pRefStm->GetIndex( pObj );
238 else
239 return 0;
241 return it->second;
244 SvPersistBase * SvPersistStream::GetObject( sal_uIntPtr nIdx ) const
246 if( nIdx >= nStartIdx )
247 return aPUIdx.Get( nIdx );
248 else if( pRefStm )
249 return pRefStm->GetObject( nIdx );
250 return NULL;
253 #define LEN_1 0x80
254 #define LEN_2 0x40
255 #define LEN_4 0x20
256 #define LEN_5 0x10
258 /** Reads a compressed word from the stream.
260 For details on what format is used for compression, see
261 <SvPersistStream::WriteCompressed>.
263 @param rStm Source to read compressed data from
265 @return Uncompressed word
266 @see SvPersistStream::WriteCompressed
268 sal_uInt32 SvPersistStream::ReadCompressed( SvStream & rStm )
270 sal_uInt32 nRet(0);
271 sal_uInt8 nMask;
272 rStm >> nMask;
273 if( nMask & LEN_1 )
274 nRet = ~LEN_1 & nMask;
275 else if( nMask & LEN_2 )
277 nRet = ~LEN_2 & nMask;
278 nRet <<= 8;
279 rStm >> nMask;
280 nRet |= nMask;
282 else if( nMask & LEN_4 )
284 nRet = ~LEN_4 & nMask;
285 nRet <<= 8;
286 rStm >> nMask;
287 nRet |= nMask;
288 nRet <<= 16;
289 sal_uInt16 n;
290 rStm >> n;
291 nRet |= n;
293 else if( nMask & LEN_5 )
295 if( nMask & 0x0F )
297 rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
298 OSL_FAIL( "format error" );
300 rStm >> nRet;
302 else
304 rStm.SetError( SVSTREAM_FILEFORMAT_ERROR );
305 OSL_FAIL( "format error" );
307 return nRet;
310 /** Writes compressed stream
312 @param rStm Source for writing compressed data
313 @param nVal This value will be compressed and written
315 nVal is compressed and written to stream using the following algorithm
316 nVal < 0x80 => 0x80 + nVal of size 1 Byte.
317 nVal < 0x4000 => 0x4000 + nVal of size 2 Byte.
318 nVal < 0x20000000 => 0x20000000 + nVal of size 4 Byte.
319 nVal > 0x1FFFFFFF => 0x1000000000+ nVal of size 5 Byte.
321 @see SvPersistStream::ReadCompressed
323 void SvPersistStream::WriteCompressed( SvStream & rStm, sal_uInt32 nVal )
325 #ifdef STOR_NO_OPTIMIZE
326 if( nVal < 0x80 )
327 rStm << (sal_uInt8)(LEN_1 | nVal);
328 else if( nVal < 0x4000 )
330 rStm << (sal_uInt8)(LEN_2 | (nVal >> 8));
331 rStm << (sal_uInt8)nVal;
333 else if( nVal < 0x20000000 )
335 // highest sal_uInt8
336 rStm << (sal_uInt8)(LEN_4 | (nVal >> 24));
337 // 2nd highest sal_uInt8
338 rStm << (sal_uInt8)(nVal >> 16);
339 rStm << (sal_uInt16)(nVal);
341 else
342 #endif
344 rStm << (sal_uInt8)LEN_5;
345 rStm << nVal;
349 /** This method writes length value of 4 Bytes to the stream and returns the
350 stream position.
352 Example:
353 @code
354 sal_uInt32 nObjPos = rStm.WriteDummyLen();
356 // write data
358 rStm.WriteLen( nObjPos );
359 @endcode
361 @return Position of stream behind length value
363 @see SvPersistStream::ReadLen
364 @see SvPersistStream::WriteLen
366 sal_uInt32 SvPersistStream::WriteDummyLen()
368 #ifdef DBG_UTIL
369 sal_uInt32 nPos = Tell();
370 #endif
371 sal_uInt32 n0 = 0;
372 *this << n0; // Because of Sun sp
373 // Don't assert on stream error
374 DBG_ASSERT( GetError() != SVSTREAM_OK
375 || (sizeof( sal_uInt32 ) == Tell() -nPos),
376 "No 4 byte as length parameter" );
377 return Tell();
380 /** Write difference between current position and nObjPos
381 as sal_uInt32 to position nObjPos-4 in the stream.
383 Afterwards, reset stream to old position.
385 Example: Difference does not contain length value
386 @code
387 sal_uInt32 nObjPos = rStm.WriteDummyLen();
389 // write data
391 rStm.WriteLen( nObjPos );
392 // write more data
393 @endcode
395 @param nObjPos Position+4, on which length is written to
397 @see SvPersistStream::ReadLen
398 @see SvPersistStream::WriteDummyLen
400 void SvPersistStream::WriteLen( sal_uInt32 nObjPos )
402 sal_uInt32 nPos = Tell();
403 sal_uInt32 nLen = nPos - nObjPos;
404 // Length in stream must be 4 Bytes
405 Seek( nObjPos - sizeof( sal_uInt32 ) );
406 // write length
407 *this << nLen;
408 Seek( nPos );
411 /** Read a length value written to stream
413 @param pTestPos Position of the stream after reading length. May be NULL.
415 @see SvPersistStream::WriteDummyLen
416 @see SvPersistStream::WriteLen
418 sal_uInt32 SvPersistStream::ReadLen( sal_uInt32 * pTestPos )
420 sal_uInt32 nLen;
421 *this >> nLen;
422 if( pTestPos )
423 *pTestPos = Tell();
424 return nLen;
427 // File format backward-compatible
428 #ifdef STOR_NO_OPTIMIZE
429 #define P_VER (sal_uInt8)0x00
430 #else
431 #define P_VER (sal_uInt8)0x01
432 #endif
433 #define P_VER_MASK (sal_uInt8)0x0F
434 #define P_ID_0 (sal_uInt8)0x80
435 #define P_OBJ (sal_uInt8)0x40
436 #define P_DBGUTIL (sal_uInt8)0x20
437 #define P_ID (sal_uInt8)0x10
438 #ifdef STOR_NO_OPTIMIZE
439 #define P_STD P_DBGUTIL
440 #else
441 #define P_STD 0
442 #endif
444 static void WriteId
446 SvStream & rStm,
447 sal_uInt8 nHdr,
448 sal_uInt32 nId,
449 sal_uInt16 nClassId
452 #ifdef STOR_NO_OPTIMIZE
453 nHdr |= P_ID;
454 #endif
455 nHdr |= P_VER;
456 if( nHdr & P_ID )
458 if( (nHdr & P_OBJ) || nId != 0 )
459 { // Id set only for pointers or DBGUTIL
460 rStm << (sal_uInt8)(nHdr);
461 SvPersistStream::WriteCompressed( rStm, nId );
463 else
464 { // NULL Pointer
465 rStm << (sal_uInt8)(nHdr | P_ID_0);
466 return;
469 else
470 rStm << nHdr;
472 if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
473 // Objects always have a class id
474 // Pointers only for DBG_UTIL and != NULL
475 SvPersistStream::WriteCompressed( rStm, nClassId );
478 static void ReadId
480 SvStream & rStm,
481 sal_uInt8 & nHdr,
482 sal_uInt32 & nId,
483 sal_uInt16 & nClassId
486 nClassId = 0;
487 rStm >> nHdr;
488 if( nHdr & P_ID_0 )
489 nId = 0;
490 else
492 if( (nHdr & P_VER_MASK) == 0 )
494 if( (nHdr & P_DBGUTIL) || !(nHdr & P_OBJ) )
495 nId = SvPersistStream::ReadCompressed( rStm );
496 else
497 nId = 0;
499 else if( nHdr & P_ID )
500 nId = SvPersistStream::ReadCompressed( rStm );
502 if( (nHdr & P_DBGUTIL) || (nHdr & P_OBJ) )
503 nClassId = (sal_uInt16)SvPersistStream::ReadCompressed( rStm );
507 void SvPersistStream::WriteObj
509 sal_uInt8 nHdr,
510 SvPersistBase * pObj
513 #ifdef STOR_NO_OPTIMIZE
514 sal_uInt32 nObjPos = 0;
515 if( nHdr & P_DBGUTIL )
516 // remember position for length value
517 nObjPos = WriteDummyLen();
518 #endif
519 pObj->Save( *this );
520 #ifdef STOR_NO_OPTIMIZE
521 if( nHdr & P_DBGUTIL )
522 WriteLen( nObjPos );
523 #endif
526 SvPersistStream& SvPersistStream::WritePointer
528 SvPersistBase * pObj
531 sal_uInt8 nP = P_STD;
533 if( pObj )
535 sal_uIntPtr nId = GetIndex( pObj );
536 if( nId )
537 nP |= P_ID;
538 else
540 nId = aPUIdx.Insert( pObj );
541 aPTable[ pObj ] = nId;
542 nP |= P_OBJ;
544 WriteId( *this, nP, nId, pObj->GetClassId() );
545 if( nP & P_OBJ )
546 WriteObj( nP, pObj );
548 else
549 { // NULL Pointer
550 WriteId( *this, nP | P_ID, 0, 0 );
552 return *this;
555 sal_uInt32 SvPersistStream::ReadObj
557 SvPersistBase * & rpObj,
558 sal_Bool bRegister
561 sal_uInt8 nHdr;
562 sal_uInt32 nId = 0;
563 sal_uInt16 nClassId;
565 rpObj = NULL; // specification: 0 in case of error
566 ReadId( *this, nHdr, nId, nClassId );
568 // get version nummer through masking
569 if( P_VER < (nHdr & P_VER_MASK) )
571 SetError( SVSTREAM_FILEFORMAT_ERROR );
572 OSL_FAIL( "false version" );
575 if( !(nHdr & P_ID_0) && GetError() == SVSTREAM_OK )
577 if( P_OBJ & nHdr )
578 { // read object, nId only set for P_DBGUTIL
579 DBG_ASSERT( !(nHdr & P_DBGUTIL) || NULL == aPUIdx.Get( nId ),
580 "object already exist" );
581 SvCreateInstancePersist pFunc = rClassMgr.Get( nClassId );
583 sal_uInt32 nObjLen(0), nObjPos(0);
584 if( nHdr & P_DBGUTIL )
585 nObjLen = ReadLen( &nObjPos );
586 if( !pFunc )
588 #ifdef DBG_UTIL
589 OStringBuffer aStr("no class with id: " );
590 aStr.append(static_cast<sal_Int32>(nClassId));
591 aStr.append(" registered");
592 DBG_WARNING(aStr.getStr());
593 #else
594 (void)nObjLen;
595 #endif
596 SetError( ERRCODE_IO_NOFACTORY );
597 return 0;
599 pFunc( &rpObj );
600 // Save reference
601 rpObj->AddRef();
603 if( bRegister )
605 // insert into table
606 sal_uIntPtr nNewId = aPUIdx.Insert( rpObj );
607 // in order to restore state after saving
608 aPTable[ rpObj ] = nNewId;
609 DBG_ASSERT( !(nHdr & P_DBGUTIL) || nId == nNewId,
610 "read write id conflict: not the same" );
612 rpObj->Load( *this );
613 #ifdef DBG_UTIL
614 if( nObjLen + nObjPos != Tell() )
616 OStringBuffer aStr("false object len: read = ");
617 aStr.append(static_cast<sal_Int64>((long)(Tell() - nObjPos)));
618 aStr.append(", should = ");
619 aStr.append(static_cast<sal_Int32>(nObjLen));
620 OSL_FAIL(aStr.getStr());
622 #endif
623 rpObj->RestoreNoDelete();
624 rpObj->ReleaseRef();
626 else
628 rpObj = GetObject( nId );
629 DBG_ASSERT( rpObj != NULL, "object does not exist" );
630 DBG_ASSERT( rpObj->GetClassId() == nClassId, "class mismatch" );
633 return nId;
636 SvPersistStream& SvPersistStream::ReadPointer
638 SvPersistBase * & rpObj
641 ReadObj( rpObj, sal_True );
642 return *this;
645 SvPersistStream& operator <<
647 SvPersistStream & rStm,
648 SvPersistBase * pObj
651 return rStm.WritePointer( pObj );
654 SvPersistStream& operator >>
656 SvPersistStream & rStm,
657 SvPersistBase * & rpObj
660 return rStm.ReadPointer( rpObj );
663 SvStream& operator <<
665 SvStream & rStm,
666 SvPersistStream & rThis
669 SvStream * pOldStm = rThis.GetStream();
670 rThis.SetStream( &rStm );
672 sal_uInt8 bTmp = 0;
673 rThis << bTmp; // Version
674 sal_uInt32 nCount = (sal_uInt32)rThis.aPUIdx.Count();
675 rThis << nCount;
676 sal_uIntPtr aIndex = rThis.aPUIdx.FirstIndex();
677 for( sal_uInt32 i = 0; i < nCount; i++ )
679 SvPersistBase * pEle = rThis.aPUIdx.Get(aIndex);
680 sal_uInt8 nP = P_OBJ | P_ID | P_STD;
681 WriteId( rThis, nP, aIndex, pEle->GetClassId() );
682 rThis.WriteObj( nP, pEle );
683 aIndex = rThis.aPUIdx.NextIndex( aIndex );
685 rThis.SetStream( pOldStm );
686 return rStm;
689 SvStream& operator >>
691 SvStream & rStm,
692 SvPersistStream & rThis
695 SvStream * pOldStm = rThis.GetStream();
696 rThis.SetStream( &rStm );
698 sal_uInt8 nVers;
699 rThis >> nVers; // Version
700 if( 0 == nVers )
702 sal_uInt32 nCount = 0;
703 rThis >> nCount;
704 for( sal_uInt32 i = 0; i < nCount; i++ )
706 SvPersistBase * pEle;
707 // read, but don't insert into table
708 sal_uIntPtr nId = rThis.ReadObj( pEle, sal_False );
709 if( rThis.GetError() )
710 break;
712 // Id of object is never modified
713 rThis.aPUIdx.Insert( nId, pEle );
714 rThis.aPTable[ pEle ] = nId;
717 else
718 rThis.SetError( SVSTREAM_FILEFORMAT_ERROR );
720 rThis.SetStream( pOldStm );
721 return rStm;
724 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */