tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / filter / excel / xistream.cxx
blobc4aa3c2b502fafb656756980949af749a928dbe0
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 <o3tl/safeint.hxx>
23 #include <osl/thread.h>
24 #include <osl/diagnose.h>
25 #include <sal/log.hxx>
26 #include <tools/solar.h>
27 #include <ftools.hxx>
28 #include <xistream.hxx>
29 #include <xlstring.hxx>
30 #include <xiroot.hxx>
32 #include <vector>
33 #include <memory>
35 using namespace ::com::sun::star;
37 // Decryption
38 XclImpDecrypter::XclImpDecrypter() :
39 mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
40 mnOldPos( STREAM_SEEK_TO_END ),
41 mnRecSize( 0 )
45 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
46 ::comphelper::IDocPasswordVerifier(),
47 mnError( rSrc.mnError ),
48 mnOldPos( STREAM_SEEK_TO_END ),
49 mnRecSize( 0 )
53 XclImpDecrypter::~XclImpDecrypter()
57 XclImpDecrypterRef XclImpDecrypter::Clone() const
59 XclImpDecrypterRef xNewDecr;
60 if( IsValid() )
61 xNewDecr.reset( OnClone() );
62 return xNewDecr;
65 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
67 o_rEncryptionData = OnVerifyPassword( rPassword );
68 mnError = o_rEncryptionData.hasElements() ? ERRCODE_NONE : ERRCODE_ABORT;
69 return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult::OK : ::comphelper::DocPasswordVerifierResult::WrongPassword;
72 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
74 bool bValid = OnVerifyEncryptionData( rEncryptionData );
75 mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
76 return bValid ? ::comphelper::DocPasswordVerifierResult::OK : ::comphelper::DocPasswordVerifierResult::WrongPassword;
79 void XclImpDecrypter::Update( const SvStream& rStrm, sal_uInt16 nRecSize )
81 if( IsValid() )
83 sal_uInt64 const nNewPos = rStrm.Tell();
84 if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
86 OnUpdate( mnOldPos, nNewPos, nRecSize );
87 mnOldPos = nNewPos;
88 mnRecSize = nRecSize;
93 sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
95 sal_uInt16 nRet = 0;
96 if( pData && nBytes )
98 if( IsValid() )
100 Update( rStrm, mnRecSize );
101 nRet = OnRead( rStrm, static_cast< sal_uInt8* >( pData ), nBytes );
102 mnOldPos = rStrm.Tell();
104 else
105 nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pData, nBytes));
107 return nRet;
110 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
111 mnKey( nKey ),
112 mnHash( nHash )
116 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
117 XclImpDecrypter( rSrc ),
118 maEncryptionData( rSrc.maEncryptionData ),
119 mnKey( rSrc.mnKey ),
120 mnHash( rSrc.mnHash )
122 if( IsValid() )
123 maCodec.InitCodec( maEncryptionData );
126 XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
128 return new XclImpBiff5Decrypter( *this );
131 uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const OUString& rPassword )
133 maEncryptionData.realloc( 0 );
135 /* Convert password to a byte string. TODO: this needs some fine tuning
136 according to the spec... */
137 OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
138 sal_Int32 nLen = aBytePassword.getLength();
139 if( (0 < nLen) && (nLen < 16) )
141 // init codec
142 maCodec.InitKey( reinterpret_cast<sal_uInt8 const *>(aBytePassword.getStr()) );
144 if ( maCodec.VerifyKey( mnKey, mnHash ) )
146 maEncryptionData = maCodec.GetEncryptionData();
148 // since the export uses Std97 encryption always we have to request it here
149 ::std::vector< sal_uInt16 > aPassVect( 16 );
150 sal_Int32 nInd = 0;
151 std::for_each(aPassVect.begin(), aPassVect.begin() + nLen,
152 [&rPassword, &nInd](sal_uInt16& rPass) {
153 rPass = static_cast< sal_uInt16 >( rPassword[nInd] );
154 ++nInd;
157 uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
158 OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the sequence!" );
160 ::msfilter::MSCodec_Std97 aCodec97;
161 aCodec97.InitKey(aPassVect.data(), reinterpret_cast<sal_uInt8 const *>(aDocId.getConstArray()));
163 // merge the EncryptionData, there should be no conflicts
164 ::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
165 aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
166 aEncryptionHash >> maEncryptionData;
170 return maEncryptionData;
173 bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
175 maEncryptionData.realloc( 0 );
177 if( rEncryptionData.hasElements() )
179 // init codec
180 maCodec.InitCodec( rEncryptionData );
182 if ( maCodec.VerifyKey( mnKey, mnHash ) )
183 maEncryptionData = rEncryptionData;
186 return maEncryptionData.hasElements();
189 void XclImpBiff5Decrypter::OnUpdate( std::size_t /*nOldStrmPos*/, std::size_t nNewStrmPos, sal_uInt16 nRecSize )
191 maCodec.InitCipher();
192 maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
195 sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
197 sal_uInt16 nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pnData, nBytes));
198 maCodec.Decode( pnData, nRet );
199 return nRet;
202 XclImpBiff8Decrypter::XclImpBiff8Decrypter( std::vector<sal_uInt8>&& rSalt,
203 std::vector<sal_uInt8>&& rVerifier,
204 std::vector<sal_uInt8>&& rVerifierHash)
205 : maSalt(std::move(rSalt))
206 , maVerifier(std::move(rVerifier))
207 , maVerifierHash(std::move(rVerifierHash))
208 , mpCodec(nullptr)
212 XclImpBiff8Decrypter::XclImpBiff8Decrypter(const XclImpBiff8Decrypter& rSrc)
213 : XclImpDecrypter(rSrc)
214 , maEncryptionData(rSrc.maEncryptionData)
215 , maSalt(rSrc.maSalt)
216 , maVerifier(rSrc.maVerifier)
217 , maVerifierHash(rSrc.maVerifierHash)
218 , mpCodec(nullptr)
222 XclImpBiff8StdDecrypter::XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter& rSrc)
223 : XclImpBiff8Decrypter(rSrc)
225 mpCodec = &maCodec;
226 if (IsValid())
227 maCodec.InitCodec(maEncryptionData);
230 XclImpBiff8StdDecrypter* XclImpBiff8StdDecrypter::OnClone() const
232 return new XclImpBiff8StdDecrypter(*this);
235 XclImpBiff8CryptoAPIDecrypter::XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter& rSrc)
236 : XclImpBiff8Decrypter(rSrc)
238 mpCodec = &maCodec;
239 if (IsValid())
240 maCodec.InitCodec(maEncryptionData);
243 XclImpBiff8CryptoAPIDecrypter* XclImpBiff8CryptoAPIDecrypter::OnClone() const
245 return new XclImpBiff8CryptoAPIDecrypter(*this);
248 uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
250 maEncryptionData.realloc( 0 );
252 sal_Int32 nLen = rPassword.getLength();
253 if( (0 < nLen) && (nLen < 16) )
255 // copy string to sal_uInt16 array
256 ::std::vector< sal_uInt16 > aPassVect( 16 );
257 const sal_Unicode* pcChar = rPassword.getStr();
258 std::for_each(aPassVect.begin(), aPassVect.begin() + nLen,
259 [&pcChar](sal_uInt16& rPass) {
260 rPass = static_cast< sal_uInt16 >( *pcChar );
261 ++pcChar;
264 // init codec
265 mpCodec->InitKey(aPassVect.data(), maSalt.data());
266 if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
267 maEncryptionData = mpCodec->GetEncryptionData();
270 return maEncryptionData;
273 bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
275 maEncryptionData.realloc( 0 );
277 if( rEncryptionData.hasElements() )
279 // init codec
280 mpCodec->InitCodec( rEncryptionData );
282 if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
283 maEncryptionData = rEncryptionData;
286 return maEncryptionData.hasElements();
289 void XclImpBiff8Decrypter::OnUpdate( std::size_t nOldStrmPos, std::size_t nNewStrmPos, sal_uInt16 /*nRecSize*/ )
291 if( nNewStrmPos == nOldStrmPos )
292 return;
294 sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
295 sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
297 sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
298 sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
300 /* Rekey cipher, if block changed or if previous offset in same block. */
301 if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
303 mpCodec->InitCipher( nNewBlock );
304 nOldOffset = 0; // reset nOldOffset for next if() statement
307 /* Seek to correct offset. */
308 if( nNewOffset > nOldOffset )
309 mpCodec->Skip( nNewOffset - nOldOffset );
312 sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
314 sal_uInt16 nRet = 0;
316 sal_uInt8* pnCurrData = pnData;
317 sal_uInt16 nBytesLeft = nBytes;
318 while( nBytesLeft )
320 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
321 sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
323 // read the block from stream
324 nRet = nRet + static_cast<sal_uInt16>(rStrm.ReadBytes(pnCurrData, nDecBytes));
325 // decode the block inplace
326 mpCodec->Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
327 if( GetOffset( rStrm.Tell() ) == 0 )
328 mpCodec->InitCipher( GetBlock( rStrm.Tell() ) );
330 pnCurrData += nDecBytes;
331 nBytesLeft = nBytesLeft - nDecBytes;
334 return nRet;
337 sal_uInt32 XclImpBiff8Decrypter::GetBlock( std::size_t nStrmPos )
339 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
342 sal_uInt16 XclImpBiff8Decrypter::GetOffset( std::size_t nStrmPos )
344 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
347 // Stream
348 XclImpStreamPos::XclImpStreamPos() :
349 mnPos( STREAM_SEEK_TO_BEGIN ),
350 mnNextPos( STREAM_SEEK_TO_BEGIN ),
351 mnCurrSize( 0 ),
352 mnRawRecId( EXC_ID_UNKNOWN ),
353 mnRawRecSize( 0 ),
354 mnRawRecLeft( 0 ),
355 mbValid( false )
359 void XclImpStreamPos::Set(
360 const SvStream& rStrm, std::size_t nNextPos, std::size_t nCurrSize,
361 sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft,
362 bool bValid )
364 mnPos = rStrm.Tell();
365 mnNextPos = nNextPos;
366 mnCurrSize = nCurrSize;
367 mnRawRecId = nRawRecId;
368 mnRawRecSize = nRawRecSize;
369 mnRawRecLeft = nRawRecLeft;
370 mbValid = bValid;
373 void XclImpStreamPos::Get(
374 SvStream& rStrm, std::size_t& rnNextPos, std::size_t& rnCurrSize,
375 sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft,
376 bool& rbValid ) const
378 rStrm.Seek( mnPos );
379 rnNextPos = mnNextPos;
380 rnCurrSize = mnCurrSize;
381 rnRawRecId = mnRawRecId;
382 rnRawRecSize = mnRawRecSize;
383 rnRawRecLeft = mnRawRecLeft;
384 rbValid = mbValid;
387 XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
389 XclBiff eBiff = EXC_BIFF_UNKNOWN;
391 rStrm.Seek( STREAM_SEEK_TO_BEGIN );
392 sal_uInt16 nBofId(0), nBofSize(0);
393 rStrm.ReadUInt16( nBofId ).ReadUInt16( nBofSize );
395 if (rStrm.good() && 4 <= nBofSize && nBofSize <= 16) switch( nBofId )
397 case EXC_ID2_BOF:
398 eBiff = EXC_BIFF2;
399 break;
400 case EXC_ID3_BOF:
401 eBiff = EXC_BIFF3;
402 break;
403 case EXC_ID4_BOF:
404 eBiff = EXC_BIFF4;
405 break;
406 case EXC_ID5_BOF:
408 sal_uInt16 nVersion(0);
409 rStrm.ReadUInt16( nVersion );
410 // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
411 switch( nVersion & 0xFF00 )
413 case 0: eBiff = EXC_BIFF5; break; // #i44031# #i62752#
414 case EXC_BOF_BIFF2: eBiff = EXC_BIFF2; break;
415 case EXC_BOF_BIFF3: eBiff = EXC_BIFF3; break;
416 case EXC_BOF_BIFF4: eBiff = EXC_BIFF4; break;
417 case EXC_BOF_BIFF5: eBiff = EXC_BIFF5; break;
418 case EXC_BOF_BIFF8: eBiff = EXC_BIFF8; break;
419 default: SAL_WARN("sc", "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x" << std::hex << nVersion );
422 break;
424 return eBiff;
427 XclImpStream::XclImpStream( SvStream& rInStrm, const XclImpRoot& rRoot ) :
428 mrStrm( rInStrm ),
429 mrRoot( rRoot ),
430 mnGlobRecId( EXC_ID_UNKNOWN ),
431 mbGlobValidRec( false ),
432 mbHasGlobPos( false ),
433 mnNextRecPos( STREAM_SEEK_TO_BEGIN ),
434 mnCurrRecSize( 0 ),
435 mnComplRecSize( 0 ),
436 mbHasComplRec( false ),
437 mnRecId( EXC_ID_UNKNOWN ),
438 mnAltContId( EXC_ID_UNKNOWN ),
439 mnRawRecId( EXC_ID_UNKNOWN ),
440 mnRawRecSize( 0 ),
441 mnRawRecLeft( 0 ),
442 mcNulSubst( '?' ),
443 mbCont( true ),
444 mbUseDecr( false ),
445 mbValidRec( false ),
446 mbValid( false )
448 mnStreamSize = mrStrm.TellEnd();
449 mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
452 XclImpStream::~XclImpStream()
456 bool XclImpStream::StartNextRecord()
458 maPosStack.clear();
460 /* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
461 "Crystal Report" writes zero records between other records) */
462 int nZeroRecCount = 5;
463 bool bIsZeroRec = false;
467 mbValidRec = ReadNextRawRecHeader();
468 bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
469 if( bIsZeroRec ) --nZeroRecCount;
470 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
472 while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
474 mbValidRec = mbValidRec && !bIsZeroRec;
475 mbValid = mbValidRec;
476 SetupRecord();
478 return mbValidRec;
481 bool XclImpStream::StartNextRecord( std::size_t nNextRecPos )
483 mnNextRecPos = nNextRecPos;
484 return StartNextRecord();
487 void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
489 if( mbValidRec )
491 maPosStack.clear();
492 RestorePosition( maFirstRec );
493 mnCurrRecSize = mnComplRecSize = mnRawRecSize;
494 mbHasComplRec = !bContLookup;
495 mbCont = bContLookup;
496 mnAltContId = nAltContId;
497 EnableDecryption();
501 void XclImpStream::RewindRecord()
503 mnNextRecPos = maFirstRec.GetPos();
504 mbValid = mbValidRec = false;
507 void XclImpStream::SetDecrypter( XclImpDecrypterRef const & xDecrypter )
509 mxDecrypter = xDecrypter;
510 EnableDecryption();
511 SetupDecrypter();
514 void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
516 XclImpDecrypterRef xNewDecr;
517 if( rStrm.mxDecrypter )
518 xNewDecr = rStrm.mxDecrypter->Clone();
519 SetDecrypter( xNewDecr );
522 void XclImpStream::EnableDecryption( bool bEnable )
524 mbUseDecr = bEnable && mxDecrypter && mxDecrypter->IsValid();
527 void XclImpStream::PushPosition()
529 maPosStack.emplace_back( );
530 StorePosition( maPosStack.back() );
533 void XclImpStream::PopPosition()
535 OSL_ENSURE( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
536 if( !maPosStack.empty() )
538 RestorePosition( maPosStack.back() );
539 maPosStack.pop_back();
543 void XclImpStream::StoreGlobalPosition()
545 StorePosition( maGlobPos );
546 mnGlobRecId = mnRecId;
547 mbGlobValidRec = mbValidRec;
548 mbHasGlobPos = true;
551 void XclImpStream::SeekGlobalPosition()
553 OSL_ENSURE( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
554 if( mbHasGlobPos )
556 RestorePosition( maGlobPos );
557 mnRecId = mnGlobRecId;
558 mnComplRecSize = mnCurrRecSize;
559 mbHasComplRec = !mbCont;
560 mbValidRec = mbGlobValidRec;
564 std::size_t XclImpStream::GetRecPos() const
566 return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
569 std::size_t XclImpStream::GetRecSize()
571 if( !mbHasComplRec )
573 PushPosition();
574 while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
575 mnComplRecSize = mnCurrRecSize;
576 mbHasComplRec = true;
577 PopPosition();
579 return mnComplRecSize;
582 std::size_t XclImpStream::GetRecLeft()
584 return mbValid ? (GetRecSize() - GetRecPos()) : 0;
587 sal_uInt16 XclImpStream::GetNextRecId()
589 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
590 if( mbValidRec )
592 PushPosition();
593 while( JumpToNextContinue() ) ; // skip following CONTINUE records
594 if( mnNextRecPos < mnStreamSize )
596 mrStrm.Seek( mnNextRecPos );
597 mrStrm.ReadUInt16( nRecId );
599 PopPosition();
601 return nRecId;
604 sal_uInt16 XclImpStream::PeekRecId( std::size_t nPos )
606 sal_uInt16 nRecId = EXC_ID_UNKNOWN;
607 if (mbValidRec && nPos < mnStreamSize)
609 sal_uInt64 const nCurPos = mrStrm.Tell();
610 mrStrm.Seek(nPos);
611 mrStrm.ReadUInt16( nRecId );
612 mrStrm.Seek(nCurPos);
614 return nRecId;
617 sal_uInt8 XclImpStream::ReaduInt8()
619 sal_uInt8 nValue = 0;
620 if( EnsureRawReadSize( 1 ) )
622 if( mbUseDecr )
623 mxDecrypter->Read( mrStrm, &nValue, 1 );
624 else
625 mrStrm.ReadUChar( nValue );
626 --mnRawRecLeft;
628 return nValue;
631 sal_Int16 XclImpStream::ReadInt16()
633 sal_Int16 nValue = 0;
634 if( EnsureRawReadSize( 2 ) )
636 if( mbUseDecr )
638 SVBT16 pnBuffer{0};
639 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
640 nValue = SVBT16ToInt16(pnBuffer);
642 else
643 mrStrm.ReadInt16( nValue );
644 mnRawRecLeft -= 2;
646 return nValue;
649 sal_uInt16 XclImpStream::ReaduInt16()
651 sal_uInt16 nValue = 0;
652 if( EnsureRawReadSize( 2 ) )
654 if( mbUseDecr )
656 SVBT16 pnBuffer{0};
657 mxDecrypter->Read( mrStrm, pnBuffer, 2 );
658 nValue = SVBT16ToUInt16( pnBuffer );
660 else
661 mrStrm.ReadUInt16( nValue );
662 mnRawRecLeft -= 2;
664 return nValue;
667 sal_Int32 XclImpStream::ReadInt32()
669 sal_Int32 nValue = 0;
670 if( EnsureRawReadSize( 4 ) )
672 if( mbUseDecr )
674 SVBT32 pnBuffer{0};
675 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
676 nValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
678 else
679 mrStrm.ReadInt32( nValue );
680 mnRawRecLeft -= 4;
682 return nValue;
685 sal_uInt32 XclImpStream::ReaduInt32()
687 sal_uInt32 nValue = 0;
688 if( EnsureRawReadSize( 4 ) )
690 if( mbUseDecr )
692 SVBT32 pnBuffer{0};
693 mxDecrypter->Read( mrStrm, pnBuffer, 4 );
694 nValue = SVBT32ToUInt32( pnBuffer );
696 else
697 mrStrm.ReadUInt32( nValue );
698 mnRawRecLeft -= 4;
700 return nValue;
703 double XclImpStream::ReadDouble()
705 double nValue = 0;
706 if( EnsureRawReadSize( 8 ) )
708 if( mbUseDecr )
710 SVBT64 pnBuffer{0};
711 mxDecrypter->Read( mrStrm, pnBuffer, 8 );
712 nValue = SVBT64ToDouble( pnBuffer );
714 else
715 mrStrm.ReadDouble( nValue );
716 mnRawRecLeft -= 8;
718 return nValue;
721 std::size_t XclImpStream::Read( void* pData, std::size_t nBytes )
723 std::size_t nRet = 0;
724 if( mbValid && pData && (nBytes > 0) )
726 sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( pData );
727 std::size_t nBytesLeft = nBytes;
729 while( mbValid && (nBytesLeft > 0) )
731 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
732 sal_uInt16 nReadRet = ReadRawData( pnBuffer, nReadSize );
733 nRet += nReadRet;
734 mbValid = (nReadSize == nReadRet);
735 OSL_ENSURE( mbValid, "XclImpStream::Read - stream read error" );
736 pnBuffer += nReadRet;
737 nBytesLeft -= nReadRet;
738 if( mbValid && (nBytesLeft > 0) )
739 JumpToNextContinue();
740 OSL_ENSURE( mbValid, "XclImpStream::Read - record overread" );
743 return nRet;
746 std::size_t XclImpStream::CopyToStream( SvStream& rOutStrm, std::size_t nBytes )
748 std::size_t nRet = 0;
749 if (mbValid && nBytes)
751 const std::size_t nMaxBuffer = 4096;
752 std::vector<sal_uInt8> aBuffer(o3tl::sanitizing_min(nBytes, nMaxBuffer));
753 std::size_t nBytesLeft = nBytes;
755 while (mbValid)
757 if (!nBytesLeft)
758 break;
759 std::size_t nReadSize = o3tl::sanitizing_min(nBytesLeft, nMaxBuffer);
760 nRet += Read(aBuffer.data(), nReadSize);
761 // writing more bytes than read results in invalid memory access
762 SAL_WARN_IF(nRet != nReadSize, "sc", "read less bytes than requested");
763 rOutStrm.WriteBytes(aBuffer.data(), nReadSize);
764 nBytesLeft -= nReadSize;
767 return nRet;
770 void XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
772 if( mbValidRec )
774 PushPosition();
775 RestorePosition( maFirstRec );
776 CopyToStream( rOutStrm, GetRecSize() );
777 PopPosition();
781 void XclImpStream::Seek( std::size_t nPos )
783 if( !mbValidRec )
784 return;
786 std::size_t nCurrPos = GetRecPos();
787 if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
789 RestorePosition( maFirstRec );
790 Ignore( nPos );
792 else if( nPos > nCurrPos ) // forward
794 Ignore( nPos - nCurrPos );
798 void XclImpStream::Ignore( std::size_t nBytes )
800 // implementation similar to Read(), but without really reading anything
801 std::size_t nBytesLeft = nBytes;
802 while (mbValid)
804 if (!nBytesLeft)
805 break;
806 sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
807 mbValid = checkSeek(mrStrm, mrStrm.Tell() + nReadSize);
808 mnRawRecLeft = mnRawRecLeft - nReadSize;
809 nBytesLeft -= nReadSize;
810 if (mbValid && nBytesLeft > 0)
811 JumpToNextContinue();
812 OSL_ENSURE( mbValid, "XclImpStream::Ignore - record overread" );
816 std::size_t XclImpStream::ReadUniStringExtHeader(
817 bool& rb16Bit, bool& rbRich, bool& rbFareast,
818 sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
820 OSL_ENSURE( !::get_flag( nFlags, EXC_STRF_UNKNOWN ), "XclImpStream::ReadUniStringExt - unknown flags" );
821 rb16Bit = ::get_flag( nFlags, EXC_STRF_16BIT );
822 rbRich = ::get_flag( nFlags, EXC_STRF_RICH );
823 rbFareast = ::get_flag( nFlags, EXC_STRF_FAREAST );
824 rnFormatRuns = rbRich ? ReaduInt16() : 0;
825 rnExtInf = rbFareast ? ReaduInt32() : 0;
826 return rnExtInf + 4 * rnFormatRuns;
829 std::size_t XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
831 bool bRich, bFareast;
832 sal_uInt16 nCrun;
833 sal_uInt32 nExtInf;
834 return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
837 OUString XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
839 OUStringBuffer aRet(o3tl::sanitizing_min<sal_uInt16>(nChars, mnRawRecLeft / (b16Bit ? 2 : 1)));
840 sal_uInt16 nCharsLeft = nChars;
841 sal_uInt16 nReadSize;
843 while (IsValid() && nCharsLeft)
845 if( b16Bit )
847 nReadSize = o3tl::sanitizing_min<sal_uInt16>(nCharsLeft, mnRawRecLeft / 2);
848 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
849 "XclImpStream::ReadRawUniString - missing a byte" );
851 else
852 nReadSize = GetMaxRawReadSize( nCharsLeft );
854 std::unique_ptr<sal_Unicode[]> pcBuffer(new sal_Unicode[nReadSize + 1]);
856 sal_Unicode* pcUniChar = pcBuffer.get();
857 sal_Unicode* pcEndChar = pcBuffer.get() + nReadSize;
859 if( b16Bit )
861 sal_uInt16 nReadChar;
862 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
864 nReadChar = ReaduInt16();
865 (*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
868 else
870 sal_uInt8 nReadChar;
871 for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
873 nReadChar = ReaduInt8();
874 (*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
878 *pcEndChar = '\0';
879 // this has the side-effect of only copying as far as the first null, which appears to be intentional. e.g.
880 // see tdf#124318
881 aRet.append( pcBuffer.get() );
883 nCharsLeft = nCharsLeft - nReadSize;
884 if( nCharsLeft > 0 )
885 JumpToNextStringContinue( b16Bit );
888 return aRet.makeStringAndClear();
891 OUString XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
893 bool b16Bit;
894 std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
895 OUString aRet( ReadRawUniString( nChars, b16Bit ) );
896 Ignore( nExtSize );
897 return aRet;
900 OUString XclImpStream::ReadUniString( sal_uInt16 nChars )
902 return ReadUniString( nChars, ReaduInt8() );
905 OUString XclImpStream::ReadUniString()
907 return ReadUniString( ReaduInt16() );
910 void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
912 sal_uInt16 nCharsLeft = nChars;
913 sal_uInt16 nReadSize;
915 while( IsValid() && (nCharsLeft > 0) )
917 if( b16Bit )
919 nReadSize = o3tl::sanitizing_min<sal_uInt16>(nCharsLeft, mnRawRecLeft / 2);
920 OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
921 "XclImpStream::IgnoreRawUniString - missing a byte" );
922 Ignore( nReadSize * 2 );
924 else
926 nReadSize = GetMaxRawReadSize( nCharsLeft );
927 Ignore( nReadSize );
930 nCharsLeft = nCharsLeft - nReadSize;
931 if( nCharsLeft > 0 )
932 JumpToNextStringContinue( b16Bit );
936 void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
938 bool b16Bit;
939 std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
940 IgnoreRawUniString( nChars, b16Bit );
941 Ignore( nExtSize );
944 void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
946 IgnoreUniString( nChars, ReaduInt8() );
949 OUString XclImpStream::ReadRawByteString( sal_uInt16 nChars )
951 nChars = GetMaxRawReadSize(nChars);
952 std::unique_ptr<char[]> pcBuffer(new char[ nChars + 1 ]);
953 sal_uInt16 nCharsRead = ReadRawData( pcBuffer.get(), nChars );
954 pcBuffer[ nCharsRead ] = '\0';
955 OUString aRet( pcBuffer.get(), strlen(pcBuffer.get()), mrRoot.GetTextEncoding() );
956 return aRet;
959 OUString XclImpStream::ReadByteString( bool b16BitLen )
961 return ReadRawByteString( b16BitLen ? ReaduInt16() : ReaduInt8() );
964 // private --------------------------------------------------------------------
966 void XclImpStream::StorePosition( XclImpStreamPos& rPos )
968 rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
971 void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
973 rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
974 SetupDecrypter();
977 bool XclImpStream::ReadNextRawRecHeader()
979 bool bRet = checkSeek(mrStrm, mnNextRecPos) && (mnNextRecPos + 4 <= mnStreamSize);
980 if (bRet)
982 mrStrm.ReadUInt16( mnRawRecId ).ReadUInt16( mnRawRecSize );
983 bRet = mrStrm.good();
985 return bRet;
988 void XclImpStream::SetupDecrypter()
990 if( mxDecrypter )
991 mxDecrypter->Update( mrStrm, mnRawRecSize );
994 void XclImpStream::SetupRawRecord()
996 // pre: mnRawRecSize contains current raw record size
997 // pre: mrStrm points to start of raw record data
998 mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
999 mnRawRecLeft = mnRawRecSize;
1000 mnCurrRecSize += mnRawRecSize;
1001 SetupDecrypter(); // decrypter works on raw record level
1004 void XclImpStream::SetupRecord()
1006 mnRecId = mnRawRecId;
1007 mnAltContId = EXC_ID_UNKNOWN;
1008 mnCurrRecSize = 0;
1009 mnComplRecSize = mnRawRecSize;
1010 mbHasComplRec = !mbCont;
1011 SetupRawRecord();
1012 SetNulSubstChar();
1013 EnableDecryption();
1014 StorePosition( maFirstRec );
1017 bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
1019 return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
1022 bool XclImpStream::JumpToNextContinue()
1024 mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
1025 if( mbValid ) // do not setup a following non-CONTINUE record
1026 SetupRawRecord();
1027 return mbValid;
1030 bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
1032 OSL_ENSURE( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
1034 if( mbCont && (GetRecLeft() > 0) )
1036 JumpToNextContinue();
1038 else if( mnRecId == EXC_ID_CONT )
1040 // CONTINUE handling is off, but we have started reading in a CONTINUE record
1041 // -> start next CONTINUE for TXO import
1042 mbValidRec = ReadNextRawRecHeader() && ((mnRawRecId != 0) || (mnRawRecSize > 0));
1043 mbValid = mbValidRec && (mnRawRecId == EXC_ID_CONT);
1044 // we really start a new record here - no chance to return to string origin
1045 if( mbValid )
1046 SetupRecord();
1048 else
1049 mbValid = false;
1051 if( mbValid )
1052 rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
1053 return mbValid;
1056 bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
1058 if( mbValid && nBytes )
1060 while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
1061 mbValid = mbValid && (nBytes <= mnRawRecLeft);
1062 OSL_ENSURE( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
1064 return mbValid;
1067 sal_uInt16 XclImpStream::GetMaxRawReadSize( std::size_t nBytes ) const
1069 return static_cast<sal_uInt16>(o3tl::sanitizing_min<std::size_t>(nBytes, mnRawRecLeft));
1072 sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
1074 OSL_ENSURE( (nBytes <= mnRawRecLeft), "XclImpStream::ReadRawData - record overread" );
1075 sal_uInt16 nRet = 0;
1076 if( mbUseDecr )
1077 nRet = mxDecrypter->Read( mrStrm, pData, nBytes );
1078 else
1079 nRet = static_cast<sal_uInt16>(mrStrm.ReadBytes(pData, nBytes));
1080 mnRawRecLeft = mnRawRecLeft - nRet;
1081 return nRet;
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */