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