1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <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>
31 
32 #include <vector>
33 #include <memory>
34 
35 using namespace ::com::sun::star;
36 
37 // Decryption
XclImpDecrypter()38 XclImpDecrypter::XclImpDecrypter() :
39     mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
40     mnOldPos( STREAM_SEEK_TO_END ),
41     mnRecSize( 0 )
42 {
43 }
44 
XclImpDecrypter(const XclImpDecrypter & rSrc)45 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
46     ::comphelper::IDocPasswordVerifier(),
47     mnError( rSrc.mnError ),
48     mnOldPos( STREAM_SEEK_TO_END ),
49     mnRecSize( 0 )
50 {
51 }
52 
~XclImpDecrypter()53 XclImpDecrypter::~XclImpDecrypter()
54 {
55 }
56 
Clone() const57 XclImpDecrypterRef XclImpDecrypter::Clone() const
58 {
59     XclImpDecrypterRef xNewDecr;
60     if( IsValid() )
61         xNewDecr.reset( OnClone() );
62     return xNewDecr;
63 }
64 
verifyPassword(const OUString & rPassword,uno::Sequence<beans::NamedValue> & o_rEncryptionData)65 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
66 {
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;
70 }
71 
verifyEncryptionData(const uno::Sequence<beans::NamedValue> & rEncryptionData)72 ::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
73 {
74     bool bValid = OnVerifyEncryptionData( rEncryptionData );
75     mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
76     return bValid ? ::comphelper::DocPasswordVerifierResult::OK : ::comphelper::DocPasswordVerifierResult::WrongPassword;
77 }
78 
Update(const SvStream & rStrm,sal_uInt16 nRecSize)79 void XclImpDecrypter::Update( const SvStream& rStrm, sal_uInt16 nRecSize )
80 {
81     if( IsValid() )
82     {
83         sal_uInt64 const nNewPos = rStrm.Tell();
84         if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
85         {
86             OnUpdate( mnOldPos, nNewPos, nRecSize );
87             mnOldPos = nNewPos;
88             mnRecSize = nRecSize;
89         }
90     }
91 }
92 
Read(SvStream & rStrm,void * pData,sal_uInt16 nBytes)93 sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
94 {
95     sal_uInt16 nRet = 0;
96     if( pData && nBytes )
97     {
98         if( IsValid() )
99         {
100             Update( rStrm, mnRecSize );
101             nRet = OnRead( rStrm, static_cast< sal_uInt8* >( pData ), nBytes );
102             mnOldPos = rStrm.Tell();
103         }
104         else
105             nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pData, nBytes));
106     }
107     return nRet;
108 }
109 
XclImpBiff5Decrypter(sal_uInt16 nKey,sal_uInt16 nHash)110 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
111     mnKey( nKey ),
112     mnHash( nHash )
113 {
114 }
115 
XclImpBiff5Decrypter(const XclImpBiff5Decrypter & rSrc)116 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
117     XclImpDecrypter( rSrc ),
118     maEncryptionData( rSrc.maEncryptionData ),
119     mnKey( rSrc.mnKey ),
120     mnHash( rSrc.mnHash )
121 {
122     if( IsValid() )
123         maCodec.InitCodec( maEncryptionData );
124 }
125 
OnClone() const126 XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
127 {
128     return new XclImpBiff5Decrypter( *this );
129 }
130 
OnVerifyPassword(const OUString & rPassword)131 uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const OUString& rPassword )
132 {
133     maEncryptionData.realloc( 0 );
134 
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) )
140     {
141         // init codec
142         maCodec.InitKey( reinterpret_cast<sal_uInt8 const *>(aBytePassword.getStr()) );
143 
144         if ( maCodec.VerifyKey( mnKey, mnHash ) )
145         {
146             maEncryptionData = maCodec.GetEncryptionData();
147 
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;
155                 });
156 
157             uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
158             OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the sequence!" );
159 
160             ::msfilter::MSCodec_Std97 aCodec97;
161             aCodec97.InitKey(aPassVect.data(), reinterpret_cast<sal_uInt8 const *>(aDocId.getConstArray()));
162 
163             // merge the EncryptionData, there should be no conflicts
164             ::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
165             aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
166             aEncryptionHash >> maEncryptionData;
167         }
168     }
169 
170     return maEncryptionData;
171 }
172 
OnVerifyEncryptionData(const uno::Sequence<beans::NamedValue> & rEncryptionData)173 bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
174 {
175     maEncryptionData.realloc( 0 );
176 
177     if( rEncryptionData.hasElements() )
178     {
179         // init codec
180         maCodec.InitCodec( rEncryptionData );
181 
182         if ( maCodec.VerifyKey( mnKey, mnHash ) )
183             maEncryptionData = rEncryptionData;
184     }
185 
186     return maEncryptionData.hasElements();
187 }
188 
OnUpdate(std::size_t,std::size_t nNewStrmPos,sal_uInt16 nRecSize)189 void XclImpBiff5Decrypter::OnUpdate( std::size_t /*nOldStrmPos*/, std::size_t nNewStrmPos, sal_uInt16 nRecSize )
190 {
191     maCodec.InitCipher();
192     maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
193 }
194 
OnRead(SvStream & rStrm,sal_uInt8 * pnData,sal_uInt16 nBytes)195 sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
196 {
197     sal_uInt16 nRet = static_cast<sal_uInt16>(rStrm.ReadBytes(pnData, nBytes));
198     maCodec.Decode( pnData, nRet );
199     return nRet;
200 }
201 
XclImpBiff8Decrypter(const std::vector<sal_uInt8> & rSalt,const std::vector<sal_uInt8> & rVerifier,const std::vector<sal_uInt8> & rVerifierHash)202 XclImpBiff8Decrypter::XclImpBiff8Decrypter(const std::vector<sal_uInt8>& rSalt,
203                                            const std::vector<sal_uInt8>& rVerifier,
204                                            const std::vector<sal_uInt8>& rVerifierHash)
205     : maSalt(rSalt)
206     , maVerifier(rVerifier)
207     , maVerifierHash(rVerifierHash)
208     , mpCodec(nullptr)
209 {
210 }
211 
XclImpBiff8Decrypter(const XclImpBiff8Decrypter & rSrc)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)
219 {
220 }
221 
XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter & rSrc)222 XclImpBiff8StdDecrypter::XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter& rSrc)
223     : XclImpBiff8Decrypter(rSrc)
224 {
225     mpCodec = &maCodec;
226     if (IsValid())
227         maCodec.InitCodec(maEncryptionData);
228 }
229 
OnClone() const230 XclImpBiff8StdDecrypter* XclImpBiff8StdDecrypter::OnClone() const
231 {
232     return new XclImpBiff8StdDecrypter(*this);
233 }
234 
XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter & rSrc)235 XclImpBiff8CryptoAPIDecrypter::XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter& rSrc)
236     : XclImpBiff8Decrypter(rSrc)
237 {
238     mpCodec = &maCodec;
239     if (IsValid())
240         maCodec.InitCodec(maEncryptionData);
241 }
242 
OnClone() const243 XclImpBiff8CryptoAPIDecrypter* XclImpBiff8CryptoAPIDecrypter::OnClone() const
244 {
245     return new XclImpBiff8CryptoAPIDecrypter(*this);
246 }
247 
OnVerifyPassword(const OUString & rPassword)248 uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
249 {
250     maEncryptionData.realloc( 0 );
251 
252     sal_Int32 nLen = rPassword.getLength();
253     if( (0 < nLen) && (nLen < 16) )
254     {
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;
262             });
263 
264         // init codec
265         mpCodec->InitKey(aPassVect.data(), maSalt.data());
266         if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
267             maEncryptionData = mpCodec->GetEncryptionData();
268     }
269 
270     return maEncryptionData;
271 }
272 
OnVerifyEncryptionData(const uno::Sequence<beans::NamedValue> & rEncryptionData)273 bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
274 {
275     maEncryptionData.realloc( 0 );
276 
277     if( rEncryptionData.hasElements() )
278     {
279         // init codec
280         mpCodec->InitCodec( rEncryptionData );
281 
282         if (mpCodec->VerifyKey(maVerifier.data(), maVerifierHash.data()))
283             maEncryptionData = rEncryptionData;
284     }
285 
286     return maEncryptionData.hasElements();
287 }
288 
OnUpdate(std::size_t nOldStrmPos,std::size_t nNewStrmPos,sal_uInt16)289 void XclImpBiff8Decrypter::OnUpdate( std::size_t nOldStrmPos, std::size_t nNewStrmPos, sal_uInt16 /*nRecSize*/ )
290 {
291     if( nNewStrmPos == nOldStrmPos )
292         return;
293 
294     sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
295     sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
296 
297     sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
298     sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
299 
300     /*  Rekey cipher, if block changed or if previous offset in same block. */
301     if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
302     {
303         mpCodec->InitCipher( nNewBlock );
304         nOldOffset = 0;     // reset nOldOffset for next if() statement
305     }
306 
307     /*  Seek to correct offset. */
308     if( nNewOffset > nOldOffset )
309         mpCodec->Skip( nNewOffset - nOldOffset );
310 }
311 
OnRead(SvStream & rStrm,sal_uInt8 * pnData,sal_uInt16 nBytes)312 sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
313 {
314     sal_uInt16 nRet = 0;
315 
316     sal_uInt8* pnCurrData = pnData;
317     sal_uInt16 nBytesLeft = nBytes;
318     while( nBytesLeft )
319     {
320         sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
321         sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
322 
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() ) );
329 
330         pnCurrData += nDecBytes;
331         nBytesLeft = nBytesLeft - nDecBytes;
332     }
333 
334     return nRet;
335 }
336 
GetBlock(std::size_t nStrmPos)337 sal_uInt32 XclImpBiff8Decrypter::GetBlock( std::size_t nStrmPos )
338 {
339     return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
340 }
341 
GetOffset(std::size_t nStrmPos)342 sal_uInt16 XclImpBiff8Decrypter::GetOffset( std::size_t nStrmPos )
343 {
344     return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
345 }
346 
347 // Stream
XclImpStreamPos()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 )
356 {
357 }
358 
Set(const SvStream & rStrm,std::size_t nNextPos,std::size_t nCurrSize,sal_uInt16 nRawRecId,sal_uInt16 nRawRecSize,sal_uInt16 nRawRecLeft,bool bValid)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 )
363 {
364     mnPos = rStrm.Tell();
365     mnNextPos = nNextPos;
366     mnCurrSize = nCurrSize;
367     mnRawRecId = nRawRecId;
368     mnRawRecSize = nRawRecSize;
369     mnRawRecLeft = nRawRecLeft;
370     mbValid = bValid;
371 }
372 
Get(SvStream & rStrm,std::size_t & rnNextPos,std::size_t & rnCurrSize,sal_uInt16 & rnRawRecId,sal_uInt16 & rnRawRecSize,sal_uInt16 & rnRawRecLeft,bool & rbValid) const373 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
377 {
378     rStrm.Seek( mnPos );
379     rnNextPos = mnNextPos;
380     rnCurrSize = mnCurrSize;
381     rnRawRecId = mnRawRecId;
382     rnRawRecSize = mnRawRecSize;
383     rnRawRecLeft = mnRawRecLeft;
384     rbValid = mbValid;
385 }
386 
DetectBiffVersion(SvStream & rStrm)387 XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
388 {
389     XclBiff eBiff = EXC_BIFF_UNKNOWN;
390 
391     rStrm.Seek( STREAM_SEEK_TO_BEGIN );
392     sal_uInt16 nBofId(0), nBofSize(0);
393     rStrm.ReadUInt16( nBofId ).ReadUInt16( nBofSize );
394 
395     if (rStrm.good() && 4 <= nBofSize && nBofSize <= 16) switch( nBofId )
396     {
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:
407         {
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 )
412             {
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 );
420             }
421         }
422         break;
423     }
424     return eBiff;
425 }
426 
XclImpStream(SvStream & rInStrm,const XclImpRoot & rRoot)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 )
447 {
448     mnStreamSize = mrStrm.TellEnd();
449     mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
450 }
451 
~XclImpStream()452 XclImpStream::~XclImpStream()
453 {
454 }
455 
StartNextRecord()456 bool XclImpStream::StartNextRecord()
457 {
458     maPosStack.clear();
459 
460     /*  #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
461         "Crystal Report" writes zero records between other records) */
462     std::size_t nZeroRecCount = 5;
463     bool bIsZeroRec = false;
464 
465     do
466     {
467         mbValidRec = ReadNextRawRecHeader();
468         bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
469         if( bIsZeroRec ) --nZeroRecCount;
470         mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
471     }
472     while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
473 
474     mbValidRec = mbValidRec && !bIsZeroRec;
475     mbValid = mbValidRec;
476     SetupRecord();
477 
478     return mbValidRec;
479 }
480 
StartNextRecord(std::size_t nNextRecPos)481 bool XclImpStream::StartNextRecord( std::size_t nNextRecPos )
482 {
483     mnNextRecPos = nNextRecPos;
484     return StartNextRecord();
485 }
486 
ResetRecord(bool bContLookup,sal_uInt16 nAltContId)487 void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
488 {
489     if( mbValidRec )
490     {
491         maPosStack.clear();
492         RestorePosition( maFirstRec );
493         mnCurrRecSize = mnComplRecSize = mnRawRecSize;
494         mbHasComplRec = !bContLookup;
495         mbCont = bContLookup;
496         mnAltContId = nAltContId;
497         EnableDecryption();
498     }
499 }
500 
RewindRecord()501 void XclImpStream::RewindRecord()
502 {
503     mnNextRecPos = maFirstRec.GetPos();
504     mbValid = mbValidRec = false;
505 }
506 
SetDecrypter(XclImpDecrypterRef const & xDecrypter)507 void XclImpStream::SetDecrypter( XclImpDecrypterRef const & xDecrypter )
508 {
509     mxDecrypter = xDecrypter;
510     EnableDecryption();
511     SetupDecrypter();
512 }
513 
CopyDecrypterFrom(const XclImpStream & rStrm)514 void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
515 {
516     XclImpDecrypterRef xNewDecr;
517     if( rStrm.mxDecrypter )
518         xNewDecr = rStrm.mxDecrypter->Clone();
519     SetDecrypter( xNewDecr );
520 }
521 
EnableDecryption(bool bEnable)522 void XclImpStream::EnableDecryption( bool bEnable )
523 {
524     mbUseDecr = bEnable && mxDecrypter && mxDecrypter->IsValid();
525 }
526 
PushPosition()527 void XclImpStream::PushPosition()
528 {
529     maPosStack.emplace_back( );
530     StorePosition( maPosStack.back() );
531 }
532 
PopPosition()533 void XclImpStream::PopPosition()
534 {
535     OSL_ENSURE( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
536     if( !maPosStack.empty() )
537     {
538         RestorePosition( maPosStack.back() );
539         maPosStack.pop_back();
540     }
541 }
542 
StoreGlobalPosition()543 void XclImpStream::StoreGlobalPosition()
544 {
545     StorePosition( maGlobPos );
546     mnGlobRecId = mnRecId;
547     mbGlobValidRec = mbValidRec;
548     mbHasGlobPos = true;
549 }
550 
SeekGlobalPosition()551 void XclImpStream::SeekGlobalPosition()
552 {
553     OSL_ENSURE( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
554     if( mbHasGlobPos )
555     {
556         RestorePosition( maGlobPos );
557         mnRecId = mnGlobRecId;
558         mnComplRecSize = mnCurrRecSize;
559         mbHasComplRec = !mbCont;
560         mbValidRec = mbGlobValidRec;
561     }
562 }
563 
GetRecPos() const564 std::size_t XclImpStream::GetRecPos() const
565 {
566     return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
567 }
568 
GetRecSize()569 std::size_t XclImpStream::GetRecSize()
570 {
571     if( !mbHasComplRec )
572     {
573         PushPosition();
574         while( JumpToNextContinue() ) ;  // JumpToNextContinue() adds up mnCurrRecSize
575         mnComplRecSize = mnCurrRecSize;
576         mbHasComplRec = true;
577         PopPosition();
578     }
579     return mnComplRecSize;
580 }
581 
GetRecLeft()582 std::size_t XclImpStream::GetRecLeft()
583 {
584     return mbValid ? (GetRecSize() - GetRecPos()) : 0;
585 }
586 
GetNextRecId()587 sal_uInt16 XclImpStream::GetNextRecId()
588 {
589     sal_uInt16 nRecId = EXC_ID_UNKNOWN;
590     if( mbValidRec )
591     {
592         PushPosition();
593         while( JumpToNextContinue() ) ;  // skip following CONTINUE records
594         if( mnNextRecPos < mnStreamSize )
595         {
596             mrStrm.Seek( mnNextRecPos );
597             mrStrm.ReadUInt16( nRecId );
598         }
599         PopPosition();
600     }
601     return nRecId;
602 }
603 
PeekRecId(std::size_t nPos)604 sal_uInt16 XclImpStream::PeekRecId( std::size_t nPos )
605 {
606     sal_uInt16 nRecId = EXC_ID_UNKNOWN;
607     if (mbValidRec && nPos < mnStreamSize)
608     {
609         sal_uInt64 const nCurPos = mrStrm.Tell();
610         mrStrm.Seek(nPos);
611         mrStrm.ReadUInt16( nRecId );
612         mrStrm.Seek(nCurPos);
613     }
614     return nRecId;
615 }
616 
ReaduInt8()617 sal_uInt8 XclImpStream::ReaduInt8()
618 {
619     sal_uInt8 nValue = 0;
620     if( EnsureRawReadSize( 1 ) )
621     {
622         if( mbUseDecr )
623             mxDecrypter->Read( mrStrm, &nValue, 1 );
624         else
625             mrStrm.ReadUChar( nValue );
626         --mnRawRecLeft;
627     }
628     return nValue;
629 }
630 
ReadInt16()631 sal_Int16 XclImpStream::ReadInt16()
632 {
633     sal_Int16 nValue = 0;
634     if( EnsureRawReadSize( 2 ) )
635     {
636         if( mbUseDecr )
637         {
638             SVBT16 pnBuffer;
639             mxDecrypter->Read( mrStrm, pnBuffer, 2 );
640             nValue = static_cast< sal_Int16 >( SVBT16ToUInt16( pnBuffer ) );
641         }
642         else
643             mrStrm.ReadInt16( nValue );
644         mnRawRecLeft -= 2;
645     }
646     return nValue;
647 }
648 
ReaduInt16()649 sal_uInt16 XclImpStream::ReaduInt16()
650 {
651     sal_uInt16 nValue = 0;
652     if( EnsureRawReadSize( 2 ) )
653     {
654         if( mbUseDecr )
655         {
656             SVBT16 pnBuffer;
657             mxDecrypter->Read( mrStrm, pnBuffer, 2 );
658             nValue = SVBT16ToUInt16( pnBuffer );
659         }
660         else
661             mrStrm.ReadUInt16( nValue );
662         mnRawRecLeft -= 2;
663     }
664     return nValue;
665 }
666 
ReadInt32()667 sal_Int32 XclImpStream::ReadInt32()
668 {
669     sal_Int32 nValue = 0;
670     if( EnsureRawReadSize( 4 ) )
671     {
672         if( mbUseDecr )
673         {
674             SVBT32 pnBuffer;
675             mxDecrypter->Read( mrStrm, pnBuffer, 4 );
676             nValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
677         }
678         else
679             mrStrm.ReadInt32( nValue );
680         mnRawRecLeft -= 4;
681     }
682     return nValue;
683 }
684 
ReaduInt32()685 sal_uInt32 XclImpStream::ReaduInt32()
686 {
687     sal_uInt32 nValue = 0;
688     if( EnsureRawReadSize( 4 ) )
689     {
690         if( mbUseDecr )
691         {
692             SVBT32 pnBuffer;
693             mxDecrypter->Read( mrStrm, pnBuffer, 4 );
694             nValue = SVBT32ToUInt32( pnBuffer );
695         }
696         else
697             mrStrm.ReadUInt32( nValue );
698         mnRawRecLeft -= 4;
699     }
700     return nValue;
701 }
702 
ReadDouble()703 double XclImpStream::ReadDouble()
704 {
705     double nValue = 0;
706     if( EnsureRawReadSize( 8 ) )
707     {
708         if( mbUseDecr )
709         {
710             SVBT64 pnBuffer;
711             mxDecrypter->Read( mrStrm, pnBuffer, 8 );
712             nValue = SVBT64ToDouble( pnBuffer );
713         }
714         else
715             mrStrm.ReadDouble( nValue );
716         mnRawRecLeft -= 8;
717     }
718     return nValue;
719 }
720 
Read(void * pData,std::size_t nBytes)721 std::size_t XclImpStream::Read( void* pData, std::size_t nBytes )
722 {
723     std::size_t nRet = 0;
724     if( mbValid && pData && (nBytes > 0) )
725     {
726         sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( pData );
727         std::size_t nBytesLeft = nBytes;
728 
729         while( mbValid && (nBytesLeft > 0) )
730         {
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" );
741         }
742     }
743     return nRet;
744 }
745 
CopyToStream(SvStream & rOutStrm,std::size_t nBytes)746 std::size_t XclImpStream::CopyToStream( SvStream& rOutStrm, std::size_t nBytes )
747 {
748     std::size_t nRet = 0;
749     if (mbValid && nBytes)
750     {
751         const std::size_t nMaxBuffer = 4096;
752         std::vector<sal_uInt8> aBuffer(o3tl::sanitizing_min(nBytes, nMaxBuffer));
753         std::size_t nBytesLeft = nBytes;
754 
755         while (mbValid)
756         {
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;
765         }
766     }
767     return nRet;
768 }
769 
CopyRecordToStream(SvStream & rOutStrm)770 void XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
771 {
772     if( mbValidRec )
773     {
774         PushPosition();
775         RestorePosition( maFirstRec );
776         CopyToStream( rOutStrm, GetRecSize() );
777         PopPosition();
778     }
779 }
780 
Seek(std::size_t nPos)781 void XclImpStream::Seek( std::size_t nPos )
782 {
783     if( !mbValidRec )
784         return;
785 
786     std::size_t nCurrPos = GetRecPos();
787     if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
788     {
789         RestorePosition( maFirstRec );
790         Ignore( nPos );
791     }
792     else if( nPos > nCurrPos )          // forward
793     {
794         Ignore( nPos - nCurrPos );
795     }
796 }
797 
Ignore(std::size_t nBytes)798 void XclImpStream::Ignore( std::size_t nBytes )
799 {
800     // implementation similar to Read(), but without really reading anything
801     std::size_t nBytesLeft = nBytes;
802     while (mbValid)
803     {
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" );
813     }
814 }
815 
ReadUniStringExtHeader(bool & rb16Bit,bool & rbRich,bool & rbFareast,sal_uInt16 & rnFormatRuns,sal_uInt32 & rnExtInf,sal_uInt8 nFlags)816 std::size_t XclImpStream::ReadUniStringExtHeader(
817         bool& rb16Bit, bool& rbRich, bool& rbFareast,
818         sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
819 {
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;
827 }
828 
ReadUniStringExtHeader(bool & rb16Bit,sal_uInt8 nFlags)829 std::size_t XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
830 {
831     bool bRich, bFareast;
832     sal_uInt16 nCrun;
833     sal_uInt32 nExtInf;
834     return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
835 }
836 
ReadRawUniString(sal_uInt16 nChars,bool b16Bit)837 OUString XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
838 {
839     OUStringBuffer aRet(o3tl::sanitizing_min<sal_uInt16>(nChars, mnRawRecLeft / (b16Bit ? 2 : 1)));
840     sal_uInt16 nCharsLeft = nChars;
841     sal_uInt16 nReadSize;
842 
843     while (IsValid() && nCharsLeft)
844     {
845         if( b16Bit )
846         {
847             nReadSize = o3tl::sanitizing_min<sal_uInt16>(nCharsLeft, mnRawRecLeft / 2);
848             OSL_ENSURE( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
849                 "XclImpStream::ReadRawUniString - missing a byte" );
850         }
851         else
852             nReadSize = GetMaxRawReadSize( nCharsLeft );
853 
854         std::unique_ptr<sal_Unicode[]> pcBuffer(new sal_Unicode[nReadSize + 1]);
855 
856         sal_Unicode* pcUniChar = pcBuffer.get();
857         sal_Unicode* pcEndChar = pcBuffer.get() + nReadSize;
858 
859         if( b16Bit )
860         {
861             sal_uInt16 nReadChar;
862             for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
863             {
864                 nReadChar = ReaduInt16();
865                 (*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
866             }
867         }
868         else
869         {
870             sal_uInt8 nReadChar;
871             for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
872             {
873                 nReadChar = ReaduInt8();
874                 (*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
875             }
876         }
877 
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() );
882 
883         nCharsLeft = nCharsLeft - nReadSize;
884         if( nCharsLeft > 0 )
885             JumpToNextStringContinue( b16Bit );
886     }
887 
888     return aRet.makeStringAndClear();
889 }
890 
ReadUniString(sal_uInt16 nChars,sal_uInt8 nFlags)891 OUString XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
892 {
893     bool b16Bit;
894     std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
895     OUString aRet( ReadRawUniString( nChars, b16Bit ) );
896     Ignore( nExtSize );
897     return aRet;
898 }
899 
ReadUniString(sal_uInt16 nChars)900 OUString XclImpStream::ReadUniString( sal_uInt16 nChars )
901 {
902     return ReadUniString( nChars, ReaduInt8() );
903 }
904 
ReadUniString()905 OUString XclImpStream::ReadUniString()
906 {
907     return ReadUniString( ReaduInt16() );
908 }
909 
IgnoreRawUniString(sal_uInt16 nChars,bool b16Bit)910 void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
911 {
912     sal_uInt16 nCharsLeft = nChars;
913     sal_uInt16 nReadSize;
914 
915     while( IsValid() && (nCharsLeft > 0) )
916     {
917         if( b16Bit )
918         {
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 );
923         }
924         else
925         {
926             nReadSize = GetMaxRawReadSize( nCharsLeft );
927             Ignore( nReadSize );
928         }
929 
930         nCharsLeft = nCharsLeft - nReadSize;
931         if( nCharsLeft > 0 )
932             JumpToNextStringContinue( b16Bit );
933     }
934 }
935 
IgnoreUniString(sal_uInt16 nChars,sal_uInt8 nFlags)936 void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
937 {
938     bool b16Bit;
939     std::size_t nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
940     IgnoreRawUniString( nChars, b16Bit );
941     Ignore( nExtSize );
942 }
943 
IgnoreUniString(sal_uInt16 nChars)944 void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
945 {
946     IgnoreUniString( nChars, ReaduInt8() );
947 }
948 
ReadRawByteString(sal_uInt16 nChars)949 OUString XclImpStream::ReadRawByteString( sal_uInt16 nChars )
950 {
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;
957 }
958 
ReadByteString(bool b16BitLen)959 OUString XclImpStream::ReadByteString( bool b16BitLen )
960 {
961     return ReadRawByteString( b16BitLen ? ReaduInt16() : ReaduInt8() );
962 }
963 
964 // private --------------------------------------------------------------------
965 
StorePosition(XclImpStreamPos & rPos)966 void XclImpStream::StorePosition( XclImpStreamPos& rPos )
967 {
968     rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
969 }
970 
RestorePosition(const XclImpStreamPos & rPos)971 void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
972 {
973     rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
974     SetupDecrypter();
975 }
976 
ReadNextRawRecHeader()977 bool XclImpStream::ReadNextRawRecHeader()
978 {
979     bool bRet = checkSeek(mrStrm, mnNextRecPos) && (mnNextRecPos + 4 <= mnStreamSize);
980     if (bRet)
981     {
982         mrStrm.ReadUInt16( mnRawRecId ).ReadUInt16( mnRawRecSize );
983         bRet = mrStrm.good();
984     }
985     return bRet;
986 }
987 
SetupDecrypter()988 void XclImpStream::SetupDecrypter()
989 {
990     if( mxDecrypter )
991         mxDecrypter->Update( mrStrm, mnRawRecSize );
992 }
993 
SetupRawRecord()994 void XclImpStream::SetupRawRecord()
995 {
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
1002 }
1003 
SetupRecord()1004 void XclImpStream::SetupRecord()
1005 {
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 );
1015 }
1016 
IsContinueId(sal_uInt16 nRecId) const1017 bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
1018 {
1019     return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
1020 }
1021 
JumpToNextContinue()1022 bool XclImpStream::JumpToNextContinue()
1023 {
1024     mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
1025     if( mbValid )   // do not setup a following non-CONTINUE record
1026         SetupRawRecord();
1027     return mbValid;
1028 }
1029 
JumpToNextStringContinue(bool & rb16Bit)1030 bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
1031 {
1032     OSL_ENSURE( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
1033 
1034     if( mbCont && (GetRecLeft() > 0) )
1035     {
1036         JumpToNextContinue();
1037     }
1038     else if( mnRecId == EXC_ID_CONT )
1039     {
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();
1047     }
1048     else
1049         mbValid = false;
1050 
1051     if( mbValid )
1052         rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
1053     return mbValid;
1054 }
1055 
EnsureRawReadSize(sal_uInt16 nBytes)1056 bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
1057 {
1058     if( mbValid && nBytes )
1059     {
1060         while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
1061         mbValid = mbValid && (nBytes <= mnRawRecLeft);
1062         OSL_ENSURE( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
1063     }
1064     return mbValid;
1065 }
1066 
GetMaxRawReadSize(std::size_t nBytes) const1067 sal_uInt16 XclImpStream::GetMaxRawReadSize( std::size_t nBytes ) const
1068 {
1069     return static_cast<sal_uInt16>(o3tl::sanitizing_min<std::size_t>(nBytes, mnRawRecLeft));
1070 }
1071 
ReadRawData(void * pData,sal_uInt16 nBytes)1072 sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
1073 {
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;
1082 }
1083 
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1085