fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xistream.cxx
blobf5efccef8d7e8295f643e29566fd12f927b1ff35
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 <comphelper/docpasswordhelper.hxx>
21 #include <comphelper/sequenceashashmap.hxx>
22 #include <osl/thread.h>
23 #include <osl/diagnose.h>
24 #include "xistream.hxx"
25 #include "xlstring.hxx"
26 #include "xiroot.hxx"
28 #include <vector>
29 #include <boost/scoped_array.hpp>
31 using namespace ::com::sun::star;
33 // Decryption
34 XclImpDecrypter::XclImpDecrypter() :
35 mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
36 mnOldPos( STREAM_SEEK_TO_END ),
37 mnRecSize( 0 )
41 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
42 ::comphelper::IDocPasswordVerifier(),
43 mnError( rSrc.mnError ),
44 mnOldPos( STREAM_SEEK_TO_END ),
45 mnRecSize( 0 )
49 XclImpDecrypter::~XclImpDecrypter()
53 XclImpDecrypterRef XclImpDecrypter::Clone() const
55 XclImpDecrypterRef xNewDecr;
56 if( IsValid() )
57 xNewDecr.reset( OnClone() );
58 return xNewDecr;
61 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
63 o_rEncryptionData = OnVerifyPassword( rPassword );
64 mnError = o_rEncryptionData.getLength() ? ERRCODE_NONE : ERRCODE_ABORT;
65 return o_rEncryptionData.getLength() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
68 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
70 bool bValid = OnVerifyEncryptionData( rEncryptionData );
71 mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
72 return bValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
75 void XclImpDecrypter::Update( SvStream& rStrm, sal_uInt16 nRecSize )
77 if( IsValid() )
79 sal_uInt64 const nNewPos = rStrm.Tell();
80 if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
82 OnUpdate( mnOldPos, nNewPos, nRecSize );
83 mnOldPos = nNewPos;
84 mnRecSize = nRecSize;
89 sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
91 sal_uInt16 nRet = 0;
92 if( pData && nBytes )
94 if( IsValid() )
96 Update( rStrm, mnRecSize );
97 nRet = OnRead( rStrm, static_cast< sal_uInt8* >( pData ), nBytes );
98 mnOldPos = rStrm.Tell();
100 else
101 nRet = static_cast< sal_uInt16 >( rStrm.Read( pData, nBytes ) );
103 return nRet;
106 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
107 mnKey( nKey ),
108 mnHash( nHash )
112 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
113 XclImpDecrypter( rSrc ),
114 maEncryptionData( rSrc.maEncryptionData ),
115 mnKey( rSrc.mnKey ),
116 mnHash( rSrc.mnHash )
118 if( IsValid() )
119 maCodec.InitCodec( maEncryptionData );
122 XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
124 return new XclImpBiff5Decrypter( *this );
127 uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const OUString& rPassword )
129 maEncryptionData.realloc( 0 );
131 /* Convert password to a byte string. TODO: this needs some finetuning
132 according to the spec... */
133 OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
134 sal_Int32 nLen = aBytePassword.getLength();
135 if( (0 < nLen) && (nLen < 16) )
137 // init codec
138 maCodec.InitKey( reinterpret_cast<sal_uInt8 const *>(aBytePassword.getStr()) );
140 if ( maCodec.VerifyKey( mnKey, mnHash ) )
142 maEncryptionData = maCodec.GetEncryptionData();
144 // since the export uses Std97 encryption always we have to request it here
145 ::std::vector< sal_uInt16 > aPassVect( 16 );
146 ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
147 for( sal_Int32 nInd = 0; nInd < nLen; ++nInd, ++aIt )
148 *aIt = static_cast< sal_uInt16 >( rPassword[nInd] );
150 uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
151 OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the senquence!" );
153 ::msfilter::MSCodec_Std97 aCodec97;
154 aCodec97.InitKey( &aPassVect.front(), reinterpret_cast<sal_uInt8 const *>(aDocId.getConstArray()) );
156 // merge the EncryptionData, there should be no conflicts
157 ::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
158 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
159 aEncryptionHash >> maEncryptionData;
163 return maEncryptionData;
166 bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
168 maEncryptionData.realloc( 0 );
170 if( rEncryptionData.getLength() )
172 // init codec
173 maCodec.InitCodec( rEncryptionData );
175 if ( maCodec.VerifyKey( mnKey, mnHash ) )
176 maEncryptionData = rEncryptionData;
179 return maEncryptionData.getLength();
182 void XclImpBiff5Decrypter::OnUpdate( sal_Size /*nOldStrmPos*/, sal_Size nNewStrmPos, sal_uInt16 nRecSize )
184 maCodec.InitCipher();
185 maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
188 sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
190 sal_uInt16 nRet = static_cast< sal_uInt16 >( rStrm.Read( pnData, nBytes ) );
191 maCodec.Decode( pnData, nRet );
192 return nRet;
195 XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
196 sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
197 maSalt( pnSalt, pnSalt + 16 ),
198 maVerifier( pnVerifier, pnVerifier + 16 ),
199 maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
203 XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ) :
204 XclImpDecrypter( rSrc ),
205 maEncryptionData( rSrc.maEncryptionData ),
206 maSalt( rSrc.maSalt ),
207 maVerifier( rSrc.maVerifier ),
208 maVerifierHash( rSrc.maVerifierHash )
210 if( IsValid() )
211 maCodec.InitCodec( maEncryptionData );
214 XclImpBiff8Decrypter* XclImpBiff8Decrypter::OnClone() const
216 return new XclImpBiff8Decrypter( *this );
219 uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
221 maEncryptionData.realloc( 0 );
223 sal_Int32 nLen = rPassword.getLength();
224 if( (0 < nLen) && (nLen < 16) )
226 // copy string to sal_uInt16 array
227 ::std::vector< sal_uInt16 > aPassVect( 16 );
228 const sal_Unicode* pcChar = rPassword.getStr();
229 const sal_Unicode* pcCharEnd = pcChar + nLen;
230 ::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
231 for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
232 *aIt = static_cast< sal_uInt16 >( *pcChar );
234 // init codec
235 maCodec.InitKey( &aPassVect.front(), &maSalt.front() );
236 if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
237 maEncryptionData = maCodec.GetEncryptionData();
240 return maEncryptionData;
243 bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
245 maEncryptionData.realloc( 0 );
247 if( rEncryptionData.getLength() )
249 // init codec
250 maCodec.InitCodec( rEncryptionData );
252 if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
253 maEncryptionData = rEncryptionData;
256 return maEncryptionData.getLength();
259 void XclImpBiff8Decrypter::OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 /*nRecSize*/ )
261 if( nNewStrmPos != nOldStrmPos )
263 sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
264 sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
266 sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
267 sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
269 /* Rekey cipher, if block changed or if previous offset in same block. */
270 if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
272 maCodec.InitCipher( nNewBlock );
273 nOldOffset = 0; // reset nOldOffset for next if() statement
276 /* Seek to correct offset. */
277 if( nNewOffset > nOldOffset )
278 maCodec.Skip( nNewOffset - nOldOffset );
282 sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
284 sal_uInt16 nRet = 0;
286 sal_uInt8* pnCurrData = pnData;
287 sal_uInt16 nBytesLeft = nBytes;
288 while( nBytesLeft )
290 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
291 sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
293 // read the block from stream
294 nRet = nRet + static_cast< sal_uInt16 >( rStrm.Read( pnCurrData, nDecBytes ) );
295 // decode the block inplace
296 maCodec.Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
297 if( GetOffset( rStrm.Tell() ) == 0 )
298 maCodec.InitCipher( GetBlock( rStrm.Tell() ) );
300 pnCurrData += nDecBytes;
301 nBytesLeft = nBytesLeft - nDecBytes;
304 return nRet;
307 sal_uInt32 XclImpBiff8Decrypter::GetBlock( sal_Size nStrmPos )
309 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
312 sal_uInt16 XclImpBiff8Decrypter::GetOffset( sal_Size nStrmPos )
314 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
317 // Stream
318 XclImpStreamPos::XclImpStreamPos() :
319 mnPos( STREAM_SEEK_TO_BEGIN ),
320 mnNextPos( STREAM_SEEK_TO_BEGIN ),
321 mnCurrSize( 0 ),
322 mnRawRecId( EXC_ID_UNKNOWN ),
323 mnRawRecSize( 0 ),
324 mnRawRecLeft( 0 ),
325 mbValid( false )
329 void XclImpStreamPos::Set(
330 const SvStream& rStrm, sal_Size nNextPos, sal_Size nCurrSize,
331 sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft,
332 bool bValid )
334 mnPos = rStrm.Tell();
335 mnNextPos = nNextPos;
336 mnCurrSize = nCurrSize;
337 mnRawRecId = nRawRecId;
338 mnRawRecSize = nRawRecSize;
339 mnRawRecLeft = nRawRecLeft;
340 mbValid = bValid;
343 void XclImpStreamPos::Get(
344 SvStream& rStrm, sal_Size& rnNextPos, sal_Size& rnCurrSize,
345 sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft,
346 bool& rbValid ) const
348 rStrm.Seek( mnPos );
349 rnNextPos = mnNextPos;
350 rnCurrSize = mnCurrSize;
351 rnRawRecId = mnRawRecId;
352 rnRawRecSize = mnRawRecSize;
353 rnRawRecLeft = mnRawRecLeft;
354 rbValid = mbValid;
357 XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
359 XclBiff eBiff = EXC_BIFF_UNKNOWN;
361 rStrm.Seek( STREAM_SEEK_TO_BEGIN );
362 sal_uInt16 nBofId, nBofSize;
363 rStrm.ReadUInt16( nBofId ).ReadUInt16( nBofSize );
365 if( (4 <= nBofSize) && (nBofSize <= 16) ) switch( nBofId )
367 case EXC_ID2_BOF:
368 eBiff = EXC_BIFF2;
369 break;
370 case EXC_ID3_BOF:
371 eBiff = EXC_BIFF3;
372 break;
373 case EXC_ID4_BOF:
374 eBiff = EXC_BIFF4;
375 break;
376 case EXC_ID5_BOF:
378 sal_uInt16 nVersion;
379 rStrm.ReadUInt16( nVersion );
380 // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
381 switch( nVersion & 0xFF00 )
383 case 0: eBiff = EXC_BIFF5; break; // #i44031# #i62752#
384 case EXC_BOF_BIFF2: eBiff = EXC_BIFF2; break;
385 case EXC_BOF_BIFF3: eBiff = EXC_BIFF3; break;
386 case EXC_BOF_BIFF4: eBiff = EXC_BIFF4; break;
387 case EXC_BOF_BIFF5: eBiff = EXC_BIFF5; break;
388 case EXC_BOF_BIFF8: eBiff = EXC_BIFF8; break;
389 default: OSL_TRACE( "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x%04hX", nVersion );
392 break;
394 return eBiff;
397 XclImpStream::XclImpStream( SvStream& rInStrm, const XclImpRoot& rRoot, bool bContLookup ) :
398 mrStrm( rInStrm ),
399 mrRoot( rRoot ),
400 mnGlobRecId( EXC_ID_UNKNOWN ),
401 mbGlobValidRec( false ),
402 mbHasGlobPos( false ),
403 mnNextRecPos( STREAM_SEEK_TO_BEGIN ),
404 mnCurrRecSize( 0 ),
405 mnComplRecSize( 0 ),
406 mbHasComplRec( false ),
407 mnRecId( EXC_ID_UNKNOWN ),
408 mnAltContId( EXC_ID_UNKNOWN ),
409 mnRawRecId( EXC_ID_UNKNOWN ),
410 mnRawRecSize( 0 ),
411 mnRawRecLeft( 0 ),
412 mcNulSubst( '?' ),
413 mbCont( bContLookup ),
414 mbUseDecr( false ),
415 mbValidRec( false ),
416 mbValid( false )
418 mrStrm.Seek( STREAM_SEEK_TO_END );
419 mnStreamSize = mrStrm.Tell();
420 mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
423 XclImpStream::~XclImpStream()
427 bool XclImpStream::StartNextRecord()
429 maPosStack.clear();
431 /* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
432 "Crystal Report" writes zero records between other records) */
433 sal_Size nZeroRecCount = 5;
434 bool bIsZeroRec = false;
438 mbValidRec = ReadNextRawRecHeader();
439 bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
440 if( bIsZeroRec ) --nZeroRecCount;
441 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
443 while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
445 mbValidRec = mbValidRec && !bIsZeroRec;
446 mbValid = mbValidRec;
447 SetupRecord();
449 return mbValidRec;
452 bool XclImpStream::StartNextRecord( sal_Size nNextRecPos )
454 mnNextRecPos = nNextRecPos;
455 return StartNextRecord();
458 void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
460 if( mbValidRec )
462 maPosStack.clear();
463 RestorePosition( maFirstRec );
464 mnCurrRecSize = mnComplRecSize = mnRawRecSize;
465 mbHasComplRec = !bContLookup;
466 mbCont = bContLookup;
467 mnAltContId = nAltContId;
468 EnableDecryption();
472 void XclImpStream::RewindRecord()
474 mnNextRecPos = maFirstRec.GetPos();
475 mbValid = mbValidRec = false;
478 void XclImpStream::SetDecrypter( XclImpDecrypterRef xDecrypter )
480 mxDecrypter = xDecrypter;
481 EnableDecryption();
482 SetupDecrypter();
485 void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
487 XclImpDecrypterRef xNewDecr;
488 if( rStrm.mxDecrypter )
489 xNewDecr = rStrm.mxDecrypter->Clone();
490 SetDecrypter( xNewDecr );
493 bool XclImpStream::HasValidDecrypter() const
495 return mxDecrypter && mxDecrypter->IsValid();
498 void XclImpStream::EnableDecryption( bool bEnable )
500 mbUseDecr = bEnable && HasValidDecrypter();
503 void XclImpStream::PushPosition()
505 maPosStack.push_back( XclImpStreamPos() );
506 StorePosition( maPosStack.back() );
509 void XclImpStream::PopPosition()
511 OSL_ENSURE( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
512 if( !maPosStack.empty() )
514 RestorePosition( maPosStack.back() );
515 maPosStack.pop_back();
519 void XclImpStream::StoreGlobalPosition()
521 StorePosition( maGlobPos );
522 mnGlobRecId = mnRecId;
523 mbGlobValidRec = mbValidRec;
524 mbHasGlobPos = true;
527 void XclImpStream::SeekGlobalPosition()
529 OSL_ENSURE( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
530 if( mbHasGlobPos )
532 RestorePosition( maGlobPos );
533 mnRecId = mnGlobRecId;
534 mnComplRecSize = mnCurrRecSize;
535 mbHasComplRec = !mbCont;
536 mbValidRec = mbGlobValidRec;
540 sal_Size XclImpStream::GetRecPos() const
542 return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
545 sal_Size XclImpStream::GetRecSize()
547 if( !mbHasComplRec )
549 PushPosition();
550 while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
551 mnComplRecSize = mnCurrRecSize;
552 mbHasComplRec = true;
553 PopPosition();
555 return mnComplRecSize;
558 sal_Size XclImpStream::GetRecLeft()
560 return mbValid ? (GetRecSize() - GetRecPos()) : 0;
563 sal_uInt16 XclImpStream::GetNextRecId()
565 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
566 if( mbValidRec )
568 PushPosition();
569 while( JumpToNextContinue() ) ; // skip following CONTINUE records
570 if( mnNextRecPos < mnStreamSize )
572 mrStrm.Seek( mnNextRecPos );
573 mrStrm.ReadUInt16( nRecId );
575 PopPosition();
577 return nRecId;
580 sal_uInt16 XclImpStream::PeekRecId( sal_Size nPos )
582 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
583 if (mbValidRec && nPos < mnStreamSize)
585 sal_Size nCurPos = mrStrm.Tell();
586 mrStrm.Seek(nPos);
587 mrStrm.ReadUInt16( nRecId );
588 mrStrm.Seek(nCurPos);
590 return nRecId;
593 sal_uInt8 XclImpStream::ReaduInt8()
595 sal_uInt8 nValue = 0;
596 if( EnsureRawReadSize( 1 ) )
598 if( mbUseDecr )
599 mxDecrypter->Read( mrStrm, &nValue, 1 );
600 else
601 mrStrm.ReadUChar( nValue );
602 --mnRawRecLeft;
604 return nValue;
607 sal_Int16 XclImpStream::ReadInt16()
609 sal_Int16 nValue = 0;
610 if( EnsureRawReadSize( 2 ) )
612 if( mbUseDecr )
614 SVBT16 pnBuffer;
615 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
616 nValue = static_cast< sal_Int16 >( SVBT16ToShort( pnBuffer ) );
618 else
619 mrStrm.ReadInt16( nValue );
620 mnRawRecLeft -= 2;
622 return nValue;
625 sal_uInt16 XclImpStream::ReaduInt16()
627 sal_uInt16 nValue = 0;
628 if( EnsureRawReadSize( 2 ) )
630 if( mbUseDecr )
632 SVBT16 pnBuffer;
633 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
634 nValue = SVBT16ToShort( pnBuffer );
636 else
637 mrStrm.ReadUInt16( nValue );
638 mnRawRecLeft -= 2;
640 return nValue;
643 sal_Int32 XclImpStream::ReadInt32()
645 sal_Int32 nValue = 0;
646 if( EnsureRawReadSize( 4 ) )
648 if( mbUseDecr )
650 SVBT32 pnBuffer;
651 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
652 nValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
654 else
655 mrStrm.ReadInt32( nValue );
656 mnRawRecLeft -= 4;
658 return nValue;
661 sal_uInt32 XclImpStream::ReaduInt32()
663 sal_uInt32 nValue = 0;
664 if( EnsureRawReadSize( 4 ) )
666 if( mbUseDecr )
668 SVBT32 pnBuffer;
669 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
670 nValue = SVBT32ToUInt32( pnBuffer );
672 else
673 mrStrm.ReadUInt32( nValue );
674 mnRawRecLeft -= 4;
676 return nValue;
679 double XclImpStream::ReadDouble()
681 double nValue = 0;
682 if( EnsureRawReadSize( 8 ) )
684 if( mbUseDecr )
686 SVBT64 pnBuffer;
687 mxDecrypter->Read( mrStrm, pnBuffer, 8 );
688 nValue = SVBT64ToDouble( pnBuffer );
690 else
691 mrStrm.ReadDouble( nValue );
692 mnRawRecLeft -= 8;
694 return nValue;
697 sal_Size XclImpStream::Read( void* pData, sal_Size nBytes )
699 sal_Size nRet = 0;
700 if( mbValid && pData && (nBytes > 0) )
702 sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( pData );
703 sal_Size nBytesLeft = nBytes;
705 while( mbValid && (nBytesLeft > 0) )
707 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
708 sal_uInt16 nReadRet = ReadRawData( pnBuffer, nReadSize );
709 nRet += nReadRet;
710 mbValid = (nReadSize == nReadRet);
711 OSL_ENSURE( mbValid, "XclImpStream::Read - stream read error" );
712 pnBuffer += nReadRet;
713 nBytesLeft -= nReadRet;
714 if( mbValid && (nBytesLeft > 0) )
715 JumpToNextContinue();
716 OSL_ENSURE( mbValid, "XclImpStream::Read - record overread" );
719 return nRet;
722 sal_Size XclImpStream::CopyToStream( SvStream& rOutStrm, sal_Size nBytes )
724 sal_Size nRet = 0;
725 if( mbValid && (nBytes > 0) )
727 const sal_Size nMaxBuffer = 4096;
728 boost::scoped_array<sal_uInt8> pnBuffer(new sal_uInt8[ ::std::min( nBytes, nMaxBuffer ) ]);
729 sal_Size nBytesLeft = nBytes;
731 while( mbValid && (nBytesLeft > 0) )
733 sal_Size nReadSize = ::std::min( nBytesLeft, nMaxBuffer );
734 nRet += Read( pnBuffer.get(), nReadSize );
735 // writing more bytes than read results in invalid memory access
736 SAL_WARN_IF(nRet != nReadSize, "sc", "read less bytes than requested");
737 rOutStrm.Write( pnBuffer.get(), nReadSize );
738 nBytesLeft -= nReadSize;
741 return nRet;
744 sal_Size XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
746 sal_Size nRet = 0;
747 if( mbValidRec )
749 PushPosition();
750 RestorePosition( maFirstRec );
751 nRet = CopyToStream( rOutStrm, GetRecSize() );
752 PopPosition();
754 return nRet;
757 void XclImpStream::Seek( sal_Size nPos )
759 if( mbValidRec )
761 sal_Size nCurrPos = GetRecPos();
762 if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
764 RestorePosition( maFirstRec );
765 Ignore( nPos );
767 else if( nPos > nCurrPos ) // forward
769 Ignore( nPos - nCurrPos );
774 void XclImpStream::Ignore( sal_Size nBytes )
776 // implementation similar to Read(), but without really reading anything
777 sal_Size nBytesLeft = nBytes;
778 while( mbValid && (nBytesLeft > 0) )
780 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
781 mrStrm.SeekRel( nReadSize );
782 mnRawRecLeft = mnRawRecLeft - nReadSize;
783 nBytesLeft -= nReadSize;
784 if( nBytesLeft > 0 )
785 JumpToNextContinue();
786 OSL_ENSURE( mbValid, "XclImpStream::Ignore - record overread" );
790 sal_Size XclImpStream::ReadUniStringExtHeader(
791 bool& rb16Bit, bool& rbRich, bool& rbFareast,
792 sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
794 OSL_ENSURE( !::get_flag( nFlags, EXC_STRF_UNKNOWN ), "XclImpStream::ReadUniStringExt - unknown flags" );
795 rb16Bit = ::get_flag( nFlags, EXC_STRF_16BIT );
796 rbRich = ::get_flag( nFlags, EXC_STRF_RICH );
797 rbFareast = ::get_flag( nFlags, EXC_STRF_FAREAST );
798 rnFormatRuns = rbRich ? ReaduInt16() : 0;
799 rnExtInf = rbFareast ? ReaduInt32() : 0;
800 return rnExtInf + 4 * rnFormatRuns;
803 sal_Size XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
805 bool bRich, bFareast;
806 sal_uInt16 nCrun;
807 sal_uInt32 nExtInf;
808 return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
811 OUString XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
813 OUString aRet;
814 sal_uInt16 nCharsLeft = nChars;
815 sal_uInt16 nReadSize;
817 boost::scoped_array<sal_Unicode> pcBuffer(new sal_Unicode[ nCharsLeft + 1 ]);
819 while( IsValid() && (nCharsLeft > 0) )
821 if( b16Bit )
823 nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
824 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
825 "XclImpStream::ReadRawUniString - missing a byte" );
827 else
828 nReadSize = GetMaxRawReadSize( nCharsLeft );
830 sal_Unicode* pcUniChar = pcBuffer.get();
831 sal_Unicode* pcEndChar = pcBuffer.get() + nReadSize;
833 if( b16Bit )
835 sal_uInt16 nReadChar;
836 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
838 nReadChar = ReaduInt16();
839 (*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
842 else
844 sal_uInt8 nReadChar;
845 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
847 nReadChar = ReaduInt8();
848 (*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
852 *pcEndChar = '\0';
853 aRet += OUString( pcBuffer.get() );
855 nCharsLeft = nCharsLeft - nReadSize;
856 if( nCharsLeft > 0 )
857 JumpToNextStringContinue( b16Bit );
860 return aRet;
863 OUString XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
865 bool b16Bit;
866 sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
867 OUString aRet( ReadRawUniString( nChars, b16Bit ) );
868 Ignore( nExtSize );
869 return aRet;
872 OUString XclImpStream::ReadUniString( sal_uInt16 nChars )
874 return ReadUniString( nChars, ReaduInt8() );
877 OUString XclImpStream::ReadUniString()
879 return ReadUniString( ReaduInt16() );
882 void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
884 sal_uInt16 nCharsLeft = nChars;
885 sal_uInt16 nReadSize;
887 while( IsValid() && (nCharsLeft > 0) )
889 if( b16Bit )
891 nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
892 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
893 "XclImpStream::IgnoreRawUniString - missing a byte" );
894 Ignore( nReadSize * 2 );
896 else
898 nReadSize = GetMaxRawReadSize( nCharsLeft );
899 Ignore( nReadSize );
902 nCharsLeft = nCharsLeft - nReadSize;
903 if( nCharsLeft > 0 )
904 JumpToNextStringContinue( b16Bit );
908 void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
910 bool b16Bit;
911 sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
912 IgnoreRawUniString( nChars, b16Bit );
913 Ignore( nExtSize );
916 void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
918 IgnoreUniString( nChars, ReaduInt8() );
921 OUString XclImpStream::ReadRawByteString( sal_uInt16 nChars )
923 nChars = GetMaxRawReadSize(nChars);
924 boost::scoped_array<sal_Char> pcBuffer(new sal_Char[ nChars + 1 ]);
925 sal_uInt16 nCharsRead = ReadRawData( pcBuffer.get(), nChars );
926 pcBuffer[ nCharsRead ] = '\0';
927 OUString aRet( pcBuffer.get(), strlen(pcBuffer.get()), mrRoot.GetTextEncoding() );
928 return aRet;
931 OUString XclImpStream::ReadByteString( bool b16BitLen )
933 return ReadRawByteString( ReadByteStrLen( b16BitLen ) );
936 // private --------------------------------------------------------------------
938 void XclImpStream::StorePosition( XclImpStreamPos& rPos )
940 rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
943 void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
945 rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
946 SetupDecrypter();
949 bool XclImpStream::ReadNextRawRecHeader()
951 sal_Size nSeekedPos = mrStrm.Seek( mnNextRecPos );
952 bool bRet = (nSeekedPos == mnNextRecPos) && (mnNextRecPos + 4 <= mnStreamSize);
953 if( bRet )
955 mrStrm.ReadUInt16( mnRawRecId ).ReadUInt16( mnRawRecSize );
956 bRet = mrStrm.good();
958 return bRet;
961 void XclImpStream::SetupDecrypter()
963 if( mxDecrypter )
964 mxDecrypter->Update( mrStrm, mnRawRecSize );
967 void XclImpStream::SetupRawRecord()
969 // pre: mnRawRecSize contains current raw record size
970 // pre: mrStrm points to start of raw record data
971 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
972 mnRawRecLeft = mnRawRecSize;
973 mnCurrRecSize += mnRawRecSize;
974 SetupDecrypter(); // decrypter works on raw record level
977 void XclImpStream::SetupRecord()
979 mnRecId = mnRawRecId;
980 mnAltContId = EXC_ID_UNKNOWN;
981 mnCurrRecSize = 0;
982 mnComplRecSize = mnRawRecSize;
983 mbHasComplRec = !mbCont;
984 SetupRawRecord();
985 SetNulSubstChar();
986 EnableDecryption();
987 StorePosition( maFirstRec );
990 bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
992 return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
995 bool XclImpStream::JumpToNextContinue()
997 mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
998 if( mbValid ) // do not setup a following non-CONTINUE record
999 SetupRawRecord();
1000 return mbValid;
1003 bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
1005 OSL_ENSURE( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
1007 if( mbCont && (GetRecLeft() > 0) )
1009 JumpToNextContinue();
1011 else if( mnRecId == EXC_ID_CONT )
1013 // CONTINUE handling is off, but we have started reading in a CONTINUE record
1014 // -> start next CONTINUE for TXO import
1015 mbValidRec = ReadNextRawRecHeader() && ((mnRawRecId != 0) || (mnRawRecSize > 0));
1016 mbValid = mbValidRec && (mnRawRecId == EXC_ID_CONT);
1017 // we really start a new record here - no chance to return to string origin
1018 if( mbValid )
1019 SetupRecord();
1021 else
1022 mbValid = false;
1024 if( mbValid )
1025 rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
1026 return mbValid;
1029 bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
1031 if( mbValid && nBytes )
1033 while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
1034 mbValid = mbValid && (nBytes <= mnRawRecLeft);
1035 OSL_ENSURE( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
1037 return mbValid;
1040 sal_uInt16 XclImpStream::GetMaxRawReadSize( sal_Size nBytes ) const
1042 return static_cast< sal_uInt16 >( ::std::min< sal_Size >( nBytes, mnRawRecLeft ) );
1045 sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
1047 OSL_ENSURE( (nBytes <= mnRawRecLeft), "XclImpStream::ReadRawData - record overread" );
1048 sal_uInt16 nRet = 0;
1049 if( mbUseDecr )
1050 nRet = mxDecrypter->Read( mrStrm, pData, nBytes );
1051 else
1052 nRet = static_cast< sal_uInt16 >( mrStrm.Read( pData, nBytes ) );
1053 mnRawRecLeft = mnRawRecLeft - nRet;
1054 return nRet;
1057 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */