Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / excel / xistream.cxx
blobf7427b9295edd1ba0fcdf6abf2932d62092df004
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 <sal/log.hxx>
25 #include <tools/solar.h>
26 #include <ftools.hxx>
27 #include <xistream.hxx>
28 #include <xlstring.hxx>
29 #include <xiroot.hxx>
31 #include <vector>
32 #include <memory>
34 using namespace ::com::sun::star;
36 // Decryption
37 XclImpDecrypter::XclImpDecrypter() :
38 mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
39 mnOldPos( STREAM_SEEK_TO_END ),
40 mnRecSize( 0 )
44 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
45 ::comphelper::IDocPasswordVerifier(),
46 mnError( rSrc.mnError ),
47 mnOldPos( STREAM_SEEK_TO_END ),
48 mnRecSize( 0 )
52 XclImpDecrypter::~XclImpDecrypter()
56 XclImpDecrypterRef XclImpDecrypter::Clone() const
58 XclImpDecrypterRef xNewDecr;
59 if( IsValid() )
60 xNewDecr.reset( OnClone() );
61 return xNewDecr;
64 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
66 o_rEncryptionData = OnVerifyPassword( rPassword );
67 mnError = o_rEncryptionData.hasElements() ? ERRCODE_NONE : ERRCODE_ABORT;
68 return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult::OK : ::comphelper::DocPasswordVerifierResult::WrongPassword;
71 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
73 bool bValid = OnVerifyEncryptionData( rEncryptionData );
74 mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
75 return bValid ? ::comphelper::DocPasswordVerifierResult::OK : ::comphelper::DocPasswordVerifierResult::WrongPassword;
78 void XclImpDecrypter::Update( const SvStream& rStrm, sal_uInt16 nRecSize )
80 if( IsValid() )
82 sal_uInt64 const nNewPos = rStrm.Tell();
83 if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
85 OnUpdate( mnOldPos, nNewPos, nRecSize );
86 mnOldPos = nNewPos;
87 mnRecSize = nRecSize;
92 sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
94 sal_uInt16 nRet = 0;
95 if( pData && nBytes )
97 if( IsValid() )
99 Update( rStrm, mnRecSize );
100 nRet = OnRead( rStrm, static_cast< sal_uInt8* >( pData ), nBytes );
101 mnOldPos = rStrm.Tell();
103 else
104 nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pData, nBytes));
106 return nRet;
109 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
110 mnKey( nKey ),
111 mnHash( nHash )
115 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
116 XclImpDecrypter( rSrc ),
117 maEncryptionData( rSrc.maEncryptionData ),
118 mnKey( rSrc.mnKey ),
119 mnHash( rSrc.mnHash )
121 if( IsValid() )
122 maCodec.InitCodec( maEncryptionData );
125 XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
127 return new XclImpBiff5Decrypter( *this );
130 uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const OUString& rPassword )
132 maEncryptionData.realloc( 0 );
134 /* Convert password to a byte string. TODO: this needs some fine tuning
135 according to the spec... */
136 OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
137 sal_Int32 nLen = aBytePassword.getLength();
138 if( (0 < nLen) && (nLen < 16) )
140 // init codec
141 maCodec.InitKey( reinterpret_cast<sal_uInt8 const *>(aBytePassword.getStr()) );
143 if ( maCodec.VerifyKey( mnKey, mnHash ) )
145 maEncryptionData = maCodec.GetEncryptionData();
147 // since the export uses Std97 encryption always we have to request it here
148 ::std::vector< sal_uInt16 > aPassVect( 16 );
149 sal_Int32 nInd = 0;
150 std::for_each(aPassVect.begin(), aPassVect.begin() + nLen,
151 [&rPassword, &nInd](sal_uInt16& rPass) {
152 rPass = static_cast< sal_uInt16 >( rPassword[nInd] );
153 ++nInd;
156 uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
157 OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the sequence!" );
159 ::msfilter::MSCodec_Std97 aCodec97;
160 aCodec97.InitKey(aPassVect.data(), reinterpret_cast<sal_uInt8 const *>(aDocId.getConstArray()));
162 // merge the EncryptionData, there should be no conflicts
163 ::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
164 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
165 aEncryptionHash >> maEncryptionData;
169 return maEncryptionData;
172 bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
174 maEncryptionData.realloc( 0 );
176 if( rEncryptionData.hasElements() )
178 // init codec
179 maCodec.InitCodec( rEncryptionData );
181 if ( maCodec.VerifyKey( mnKey, mnHash ) )
182 maEncryptionData = rEncryptionData;
185 return maEncryptionData.hasElements();
188 void XclImpBiff5Decrypter::OnUpdate( std::size_t /*nOldStrmPos*/, std::size_t nNewStrmPos, sal_uInt16 nRecSize )
190 maCodec.InitCipher();
191 maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
194 sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
196 sal_uInt16 nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pnData, nBytes));
197 maCodec.Decode( pnData, nRet );
198 return nRet;
201 XclImpBiff8Decrypter::XclImpBiff8Decrypter(const std::vector<sal_uInt8>& rSalt,
202 const std::vector<sal_uInt8>& rVerifier,
203 const std::vector<sal_uInt8>& rVerifierHash)
204 : maSalt(rSalt)
205 , maVerifier(rVerifier)
206 , maVerifierHash(rVerifierHash)
207 , mpCodec(nullptr)
211 XclImpBiff8Decrypter::XclImpBiff8Decrypter(const XclImpBiff8Decrypter& rSrc)
212 : XclImpDecrypter(rSrc)
213 , maEncryptionData(rSrc.maEncryptionData)
214 , maSalt(rSrc.maSalt)
215 , maVerifier(rSrc.maVerifier)
216 , maVerifierHash(rSrc.maVerifierHash)
217 , mpCodec(nullptr)
221 XclImpBiff8StdDecrypter::XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter& rSrc)
222 : XclImpBiff8Decrypter(rSrc)
224 mpCodec = &maCodec;
225 if (IsValid())
226 maCodec.InitCodec(maEncryptionData);
229 XclImpBiff8StdDecrypter* XclImpBiff8StdDecrypter::OnClone() const
231 return new XclImpBiff8StdDecrypter(*this);
234 XclImpBiff8CryptoAPIDecrypter::XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter& rSrc)
235 : XclImpBiff8Decrypter(rSrc)
237 mpCodec = &maCodec;
238 if (IsValid())
239 maCodec.InitCodec(maEncryptionData);
242 XclImpBiff8CryptoAPIDecrypter* XclImpBiff8CryptoAPIDecrypter::OnClone() const
244 return new XclImpBiff8CryptoAPIDecrypter(*this);
247 uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
249 maEncryptionData.realloc( 0 );
251 sal_Int32 nLen = rPassword.getLength();
252 if( (0 < nLen) && (nLen < 16) )
254 // copy string to sal_uInt16 array
255 ::std::vector< sal_uInt16 > aPassVect( 16 );
256 const sal_Unicode* pcChar = rPassword.getStr();
257 std::for_each(aPassVect.begin(), aPassVect.begin() + nLen,
258 [&pcChar](sal_uInt16& rPass) {
259 rPass = static_cast< sal_uInt16 >( *pcChar );
260 ++pcChar;
263 // init codec
264 mpCodec->InitKey(aPassVect.data(), maSalt.data());
265 if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
266 maEncryptionData = mpCodec->GetEncryptionData();
269 return maEncryptionData;
272 bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
274 maEncryptionData.realloc( 0 );
276 if( rEncryptionData.hasElements() )
278 // init codec
279 mpCodec->InitCodec( rEncryptionData );
281 if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
282 maEncryptionData = rEncryptionData;
285 return maEncryptionData.hasElements();
288 void XclImpBiff8Decrypter::OnUpdate( std::size_t nOldStrmPos, std::size_t nNewStrmPos, sal_uInt16 /*nRecSize*/ )
290 if( nNewStrmPos != nOldStrmPos )
292 sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
293 sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
295 sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
296 sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
298 /* Rekey cipher, if block changed or if previous offset in same block. */
299 if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
301 mpCodec->InitCipher( nNewBlock );
302 nOldOffset = 0; // reset nOldOffset for next if() statement
305 /* Seek to correct offset. */
306 if( nNewOffset > nOldOffset )
307 mpCodec->Skip( nNewOffset - nOldOffset );
311 sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
313 sal_uInt16 nRet = 0;
315 sal_uInt8* pnCurrData = pnData;
316 sal_uInt16 nBytesLeft = nBytes;
317 while( nBytesLeft )
319 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
320 sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
322 // read the block from stream
323 nRet = nRet + static_cast<sal_uInt16>(rStrm.ReadBytes(pnCurrData, nDecBytes));
324 // decode the block inplace
325 mpCodec->Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
326 if( GetOffset( rStrm.Tell() ) == 0 )
327 mpCodec->InitCipher( GetBlock( rStrm.Tell() ) );
329 pnCurrData += nDecBytes;
330 nBytesLeft = nBytesLeft - nDecBytes;
333 return nRet;
336 sal_uInt32 XclImpBiff8Decrypter::GetBlock( std::size_t nStrmPos )
338 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
341 sal_uInt16 XclImpBiff8Decrypter::GetOffset( std::size_t nStrmPos )
343 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
346 // Stream
347 XclImpStreamPos::XclImpStreamPos() :
348 mnPos( STREAM_SEEK_TO_BEGIN ),
349 mnNextPos( STREAM_SEEK_TO_BEGIN ),
350 mnCurrSize( 0 ),
351 mnRawRecId( EXC_ID_UNKNOWN ),
352 mnRawRecSize( 0 ),
353 mnRawRecLeft( 0 ),
354 mbValid( false )
358 void XclImpStreamPos::Set(
359 const SvStream& rStrm, std::size_t nNextPos, std::size_t nCurrSize,
360 sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft,
361 bool bValid )
363 mnPos = rStrm.Tell();
364 mnNextPos = nNextPos;
365 mnCurrSize = nCurrSize;
366 mnRawRecId = nRawRecId;
367 mnRawRecSize = nRawRecSize;
368 mnRawRecLeft = nRawRecLeft;
369 mbValid = bValid;
372 void XclImpStreamPos::Get(
373 SvStream& rStrm, std::size_t& rnNextPos, std::size_t& rnCurrSize,
374 sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft,
375 bool& rbValid ) const
377 rStrm.Seek( mnPos );
378 rnNextPos = mnNextPos;
379 rnCurrSize = mnCurrSize;
380 rnRawRecId = mnRawRecId;
381 rnRawRecSize = mnRawRecSize;
382 rnRawRecLeft = mnRawRecLeft;
383 rbValid = mbValid;
386 XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
388 XclBiff eBiff = EXC_BIFF_UNKNOWN;
390 rStrm.Seek( STREAM_SEEK_TO_BEGIN );
391 sal_uInt16 nBofId, nBofSize;
392 rStrm.ReadUInt16( nBofId ).ReadUInt16( nBofSize );
394 if( (4 <= nBofSize) && (nBofSize <= 16) ) switch( nBofId )
396 case EXC_ID2_BOF:
397 eBiff = EXC_BIFF2;
398 break;
399 case EXC_ID3_BOF:
400 eBiff = EXC_BIFF3;
401 break;
402 case EXC_ID4_BOF:
403 eBiff = EXC_BIFF4;
404 break;
405 case EXC_ID5_BOF:
407 sal_uInt16 nVersion;
408 rStrm.ReadUInt16( nVersion );
409 // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
410 switch( nVersion & 0xFF00 )
412 case 0: eBiff = EXC_BIFF5; break; // #i44031# #i62752#
413 case EXC_BOF_BIFF2: eBiff = EXC_BIFF2; break;
414 case EXC_BOF_BIFF3: eBiff = EXC_BIFF3; break;
415 case EXC_BOF_BIFF4: eBiff = EXC_BIFF4; break;
416 case EXC_BOF_BIFF5: eBiff = EXC_BIFF5; break;
417 case EXC_BOF_BIFF8: eBiff = EXC_BIFF8; break;
418 default: SAL_WARN("sc", "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x" << std::hex << nVersion );
421 break;
423 return eBiff;
426 XclImpStream::XclImpStream( SvStream& rInStrm, const XclImpRoot& rRoot ) :
427 mrStrm( rInStrm ),
428 mrRoot( rRoot ),
429 mnGlobRecId( EXC_ID_UNKNOWN ),
430 mbGlobValidRec( false ),
431 mbHasGlobPos( false ),
432 mnNextRecPos( STREAM_SEEK_TO_BEGIN ),
433 mnCurrRecSize( 0 ),
434 mnComplRecSize( 0 ),
435 mbHasComplRec( false ),
436 mnRecId( EXC_ID_UNKNOWN ),
437 mnAltContId( EXC_ID_UNKNOWN ),
438 mnRawRecId( EXC_ID_UNKNOWN ),
439 mnRawRecSize( 0 ),
440 mnRawRecLeft( 0 ),
441 mcNulSubst( '?' ),
442 mbCont( true ),
443 mbUseDecr( false ),
444 mbValidRec( false ),
445 mbValid( false )
447 mnStreamSize = mrStrm.TellEnd();
448 mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
451 XclImpStream::~XclImpStream()
455 bool XclImpStream::StartNextRecord()
457 maPosStack.clear();
459 /* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
460 "Crystal Report" writes zero records between other records) */
461 std::size_t nZeroRecCount = 5;
462 bool bIsZeroRec = false;
466 mbValidRec = ReadNextRawRecHeader();
467 bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
468 if( bIsZeroRec ) --nZeroRecCount;
469 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
471 while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
473 mbValidRec = mbValidRec && !bIsZeroRec;
474 mbValid = mbValidRec;
475 SetupRecord();
477 return mbValidRec;
480 bool XclImpStream::StartNextRecord( std::size_t nNextRecPos )
482 mnNextRecPos = nNextRecPos;
483 return StartNextRecord();
486 void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
488 if( mbValidRec )
490 maPosStack.clear();
491 RestorePosition( maFirstRec );
492 mnCurrRecSize = mnComplRecSize = mnRawRecSize;
493 mbHasComplRec = !bContLookup;
494 mbCont = bContLookup;
495 mnAltContId = nAltContId;
496 EnableDecryption();
500 void XclImpStream::RewindRecord()
502 mnNextRecPos = maFirstRec.GetPos();
503 mbValid = mbValidRec = false;
506 void XclImpStream::SetDecrypter( XclImpDecrypterRef const & xDecrypter )
508 mxDecrypter = xDecrypter;
509 EnableDecryption();
510 SetupDecrypter();
513 void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
515 XclImpDecrypterRef xNewDecr;
516 if( rStrm.mxDecrypter )
517 xNewDecr = rStrm.mxDecrypter->Clone();
518 SetDecrypter( xNewDecr );
521 void XclImpStream::EnableDecryption( bool bEnable )
523 mbUseDecr = bEnable && mxDecrypter && mxDecrypter->IsValid();
526 void XclImpStream::PushPosition()
528 maPosStack.emplace_back( );
529 StorePosition( maPosStack.back() );
532 void XclImpStream::PopPosition()
534 OSL_ENSURE( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
535 if( !maPosStack.empty() )
537 RestorePosition( maPosStack.back() );
538 maPosStack.pop_back();
542 void XclImpStream::StoreGlobalPosition()
544 StorePosition( maGlobPos );
545 mnGlobRecId = mnRecId;
546 mbGlobValidRec = mbValidRec;
547 mbHasGlobPos = true;
550 void XclImpStream::SeekGlobalPosition()
552 OSL_ENSURE( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
553 if( mbHasGlobPos )
555 RestorePosition( maGlobPos );
556 mnRecId = mnGlobRecId;
557 mnComplRecSize = mnCurrRecSize;
558 mbHasComplRec = !mbCont;
559 mbValidRec = mbGlobValidRec;
563 std::size_t XclImpStream::GetRecPos() const
565 return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
568 std::size_t XclImpStream::GetRecSize()
570 if( !mbHasComplRec )
572 PushPosition();
573 while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
574 mnComplRecSize = mnCurrRecSize;
575 mbHasComplRec = true;
576 PopPosition();
578 return mnComplRecSize;
581 std::size_t XclImpStream::GetRecLeft()
583 return mbValid ? (GetRecSize() - GetRecPos()) : 0;
586 sal_uInt16 XclImpStream::GetNextRecId()
588 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
589 if( mbValidRec )
591 PushPosition();
592 while( JumpToNextContinue() ) ; // skip following CONTINUE records
593 if( mnNextRecPos < mnStreamSize )
595 mrStrm.Seek( mnNextRecPos );
596 mrStrm.ReadUInt16( nRecId );
598 PopPosition();
600 return nRecId;
603 sal_uInt16 XclImpStream::PeekRecId( std::size_t nPos )
605 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
606 if (mbValidRec && nPos < mnStreamSize)
608 sal_uInt64 const nCurPos = mrStrm.Tell();
609 mrStrm.Seek(nPos);
610 mrStrm.ReadUInt16( nRecId );
611 mrStrm.Seek(nCurPos);
613 return nRecId;
616 sal_uInt8 XclImpStream::ReaduInt8()
618 sal_uInt8 nValue = 0;
619 if( EnsureRawReadSize( 1 ) )
621 if( mbUseDecr )
622 mxDecrypter->Read( mrStrm, &nValue, 1 );
623 else
624 mrStrm.ReadUChar( nValue );
625 --mnRawRecLeft;
627 return nValue;
630 sal_Int16 XclImpStream::ReadInt16()
632 sal_Int16 nValue = 0;
633 if( EnsureRawReadSize( 2 ) )
635 if( mbUseDecr )
637 SVBT16 pnBuffer;
638 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
639 nValue = static_cast< sal_Int16 >( SVBT16ToUInt16( pnBuffer ) );
641 else
642 mrStrm.ReadInt16( nValue );
643 mnRawRecLeft -= 2;
645 return nValue;
648 sal_uInt16 XclImpStream::ReaduInt16()
650 sal_uInt16 nValue = 0;
651 if( EnsureRawReadSize( 2 ) )
653 if( mbUseDecr )
655 SVBT16 pnBuffer;
656 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
657 nValue = SVBT16ToUInt16( pnBuffer );
659 else
660 mrStrm.ReadUInt16( nValue );
661 mnRawRecLeft -= 2;
663 return nValue;
666 sal_Int32 XclImpStream::ReadInt32()
668 sal_Int32 nValue = 0;
669 if( EnsureRawReadSize( 4 ) )
671 if( mbUseDecr )
673 SVBT32 pnBuffer;
674 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
675 nValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
677 else
678 mrStrm.ReadInt32( nValue );
679 mnRawRecLeft -= 4;
681 return nValue;
684 sal_uInt32 XclImpStream::ReaduInt32()
686 sal_uInt32 nValue = 0;
687 if( EnsureRawReadSize( 4 ) )
689 if( mbUseDecr )
691 SVBT32 pnBuffer;
692 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
693 nValue = SVBT32ToUInt32( pnBuffer );
695 else
696 mrStrm.ReadUInt32( nValue );
697 mnRawRecLeft -= 4;
699 return nValue;
702 double XclImpStream::ReadDouble()
704 double nValue = 0;
705 if( EnsureRawReadSize( 8 ) )
707 if( mbUseDecr )
709 SVBT64 pnBuffer;
710 mxDecrypter->Read( mrStrm, pnBuffer, 8 );
711 nValue = SVBT64ToDouble( pnBuffer );
713 else
714 mrStrm.ReadDouble( nValue );
715 mnRawRecLeft -= 8;
717 return nValue;
720 std::size_t XclImpStream::Read( void* pData, std::size_t nBytes )
722 std::size_t nRet = 0;
723 if( mbValid && pData && (nBytes > 0) )
725 sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( pData );
726 std::size_t nBytesLeft = nBytes;
728 while( mbValid && (nBytesLeft > 0) )
730 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
731 sal_uInt16 nReadRet = ReadRawData( pnBuffer, nReadSize );
732 nRet += nReadRet;
733 mbValid = (nReadSize == nReadRet);
734 OSL_ENSURE( mbValid, "XclImpStream::Read - stream read error" );
735 pnBuffer += nReadRet;
736 nBytesLeft -= nReadRet;
737 if( mbValid && (nBytesLeft > 0) )
738 JumpToNextContinue();
739 OSL_ENSURE( mbValid, "XclImpStream::Read - record overread" );
742 return nRet;
745 std::size_t XclImpStream::CopyToStream( SvStream& rOutStrm, std::size_t nBytes )
747 std::size_t nRet = 0;
748 if( mbValid && (nBytes > 0) )
750 const std::size_t nMaxBuffer = 4096;
751 std::unique_ptr<sal_uInt8[]> pnBuffer(new sal_uInt8[ ::std::min( nBytes, nMaxBuffer ) ]);
752 std::size_t nBytesLeft = nBytes;
754 while( mbValid && (nBytesLeft > 0) )
756 std::size_t nReadSize = ::std::min( nBytesLeft, nMaxBuffer );
757 nRet += Read( pnBuffer.get(), nReadSize );
758 // writing more bytes than read results in invalid memory access
759 SAL_WARN_IF(nRet != nReadSize, "sc", "read less bytes than requested");
760 rOutStrm.WriteBytes(pnBuffer.get(), nReadSize);
761 nBytesLeft -= nReadSize;
764 return nRet;
767 void XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
769 if( mbValidRec )
771 PushPosition();
772 RestorePosition( maFirstRec );
773 CopyToStream( rOutStrm, GetRecSize() );
774 PopPosition();
778 void XclImpStream::Seek( std::size_t nPos )
780 if( mbValidRec )
782 std::size_t nCurrPos = GetRecPos();
783 if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
785 RestorePosition( maFirstRec );
786 Ignore( nPos );
788 else if( nPos > nCurrPos ) // forward
790 Ignore( nPos - nCurrPos );
795 void XclImpStream::Ignore( std::size_t nBytes )
797 // implementation similar to Read(), but without really reading anything
798 std::size_t nBytesLeft = nBytes;
799 while( mbValid && (nBytesLeft > 0) )
801 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
802 mbValid = checkSeek(mrStrm, mrStrm.Tell() + nReadSize);
803 mnRawRecLeft = mnRawRecLeft - nReadSize;
804 nBytesLeft -= nReadSize;
805 if (mbValid && nBytesLeft > 0)
806 JumpToNextContinue();
807 OSL_ENSURE( mbValid, "XclImpStream::Ignore - record overread" );
811 std::size_t XclImpStream::ReadUniStringExtHeader(
812 bool& rb16Bit, bool& rbRich, bool& rbFareast,
813 sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
815 OSL_ENSURE( !::get_flag( nFlags, EXC_STRF_UNKNOWN ), "XclImpStream::ReadUniStringExt - unknown flags" );
816 rb16Bit = ::get_flag( nFlags, EXC_STRF_16BIT );
817 rbRich = ::get_flag( nFlags, EXC_STRF_RICH );
818 rbFareast = ::get_flag( nFlags, EXC_STRF_FAREAST );
819 rnFormatRuns = rbRich ? ReaduInt16() : 0;
820 rnExtInf = rbFareast ? ReaduInt32() : 0;
821 return rnExtInf + 4 * rnFormatRuns;
824 std::size_t XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
826 bool bRich, bFareast;
827 sal_uInt16 nCrun;
828 sal_uInt32 nExtInf;
829 return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
832 OUString XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
834 OUStringBuffer aRet(nChars);
835 sal_uInt16 nCharsLeft = nChars;
836 sal_uInt16 nReadSize;
838 while( IsValid() && (nCharsLeft > 0) )
840 if( b16Bit )
842 nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
843 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
844 "XclImpStream::ReadRawUniString - missing a byte" );
846 else
847 nReadSize = GetMaxRawReadSize( nCharsLeft );
849 std::unique_ptr<sal_Unicode[]> pcBuffer(new sal_Unicode[nReadSize + 1]);
851 sal_Unicode* pcUniChar = pcBuffer.get();
852 sal_Unicode* pcEndChar = pcBuffer.get() + nReadSize;
854 if( b16Bit )
856 sal_uInt16 nReadChar;
857 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
859 nReadChar = ReaduInt16();
860 (*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
863 else
865 sal_uInt8 nReadChar;
866 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
868 nReadChar = ReaduInt8();
869 (*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
873 *pcEndChar = '\0';
874 // this has the side-effect of only copying as far as the first null, which appears to be intentional. e.g.
875 // see tdf#124318
876 aRet.append( pcBuffer.get() );
878 nCharsLeft = nCharsLeft - nReadSize;
879 if( nCharsLeft > 0 )
880 JumpToNextStringContinue( b16Bit );
883 return aRet.makeStringAndClear();
886 OUString XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
888 bool b16Bit;
889 std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
890 OUString aRet( ReadRawUniString( nChars, b16Bit ) );
891 Ignore( nExtSize );
892 return aRet;
895 OUString XclImpStream::ReadUniString( sal_uInt16 nChars )
897 return ReadUniString( nChars, ReaduInt8() );
900 OUString XclImpStream::ReadUniString()
902 return ReadUniString( ReaduInt16() );
905 void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
907 sal_uInt16 nCharsLeft = nChars;
908 sal_uInt16 nReadSize;
910 while( IsValid() && (nCharsLeft > 0) )
912 if( b16Bit )
914 nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
915 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
916 "XclImpStream::IgnoreRawUniString - missing a byte" );
917 Ignore( nReadSize * 2 );
919 else
921 nReadSize = GetMaxRawReadSize( nCharsLeft );
922 Ignore( nReadSize );
925 nCharsLeft = nCharsLeft - nReadSize;
926 if( nCharsLeft > 0 )
927 JumpToNextStringContinue( b16Bit );
931 void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
933 bool b16Bit;
934 std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
935 IgnoreRawUniString( nChars, b16Bit );
936 Ignore( nExtSize );
939 void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
941 IgnoreUniString( nChars, ReaduInt8() );
944 OUString XclImpStream::ReadRawByteString( sal_uInt16 nChars )
946 nChars = GetMaxRawReadSize(nChars);
947 std::unique_ptr<sal_Char[]> pcBuffer(new sal_Char[ nChars + 1 ]);
948 sal_uInt16 nCharsRead = ReadRawData( pcBuffer.get(), nChars );
949 pcBuffer[ nCharsRead ] = '\0';
950 OUString aRet( pcBuffer.get(), strlen(pcBuffer.get()), mrRoot.GetTextEncoding() );
951 return aRet;
954 OUString XclImpStream::ReadByteString( bool b16BitLen )
956 return ReadRawByteString( b16BitLen ? ReaduInt16() : ReaduInt8() );
959 // private --------------------------------------------------------------------
961 void XclImpStream::StorePosition( XclImpStreamPos& rPos )
963 rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
966 void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
968 rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
969 SetupDecrypter();
972 bool XclImpStream::ReadNextRawRecHeader()
974 bool bRet = checkSeek(mrStrm, mnNextRecPos) && (mnNextRecPos + 4 <= mnStreamSize);
975 if (bRet)
977 mrStrm.ReadUInt16( mnRawRecId ).ReadUInt16( mnRawRecSize );
978 bRet = mrStrm.good();
980 return bRet;
983 void XclImpStream::SetupDecrypter()
985 if( mxDecrypter )
986 mxDecrypter->Update( mrStrm, mnRawRecSize );
989 void XclImpStream::SetupRawRecord()
991 // pre: mnRawRecSize contains current raw record size
992 // pre: mrStrm points to start of raw record data
993 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
994 mnRawRecLeft = mnRawRecSize;
995 mnCurrRecSize += mnRawRecSize;
996 SetupDecrypter(); // decrypter works on raw record level
999 void XclImpStream::SetupRecord()
1001 mnRecId = mnRawRecId;
1002 mnAltContId = EXC_ID_UNKNOWN;
1003 mnCurrRecSize = 0;
1004 mnComplRecSize = mnRawRecSize;
1005 mbHasComplRec = !mbCont;
1006 SetupRawRecord();
1007 SetNulSubstChar();
1008 EnableDecryption();
1009 StorePosition( maFirstRec );
1012 bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
1014 return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
1017 bool XclImpStream::JumpToNextContinue()
1019 mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
1020 if( mbValid ) // do not setup a following non-CONTINUE record
1021 SetupRawRecord();
1022 return mbValid;
1025 bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
1027 OSL_ENSURE( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
1029 if( mbCont && (GetRecLeft() > 0) )
1031 JumpToNextContinue();
1033 else if( mnRecId == EXC_ID_CONT )
1035 // CONTINUE handling is off, but we have started reading in a CONTINUE record
1036 // -> start next CONTINUE for TXO import
1037 mbValidRec = ReadNextRawRecHeader() && ((mnRawRecId != 0) || (mnRawRecSize > 0));
1038 mbValid = mbValidRec && (mnRawRecId == EXC_ID_CONT);
1039 // we really start a new record here - no chance to return to string origin
1040 if( mbValid )
1041 SetupRecord();
1043 else
1044 mbValid = false;
1046 if( mbValid )
1047 rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
1048 return mbValid;
1051 bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
1053 if( mbValid && nBytes )
1055 while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
1056 mbValid = mbValid && (nBytes <= mnRawRecLeft);
1057 OSL_ENSURE( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
1059 return mbValid;
1062 sal_uInt16 XclImpStream::GetMaxRawReadSize( std::size_t nBytes ) const
1064 return static_cast< sal_uInt16 >( ::std::min< std::size_t >( nBytes, mnRawRecLeft ) );
1067 sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
1069 OSL_ENSURE( (nBytes <= mnRawRecLeft), "XclImpStream::ReadRawData - record overread" );
1070 sal_uInt16 nRet = 0;
1071 if( mbUseDecr )
1072 nRet = mxDecrypter->Read( mrStrm, pData, nBytes );
1073 else
1074 nRet = static_cast<sal_uInt16>(mrStrm.ReadBytes(pData, nBytes));
1075 mnRawRecLeft = mnRawRecLeft - nRet;
1076 return nRet;
1079 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */