1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
28 #include <xistream.hxx>
29 #include <xlstring.hxx>
35 using namespace ::com::sun::star
;
38 XclImpDecrypter::XclImpDecrypter() :
39 mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT
),
40 mnOldPos( STREAM_SEEK_TO_END
),
45 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter
& rSrc
) :
46 ::comphelper::IDocPasswordVerifier(),
47 mnError( rSrc
.mnError
),
48 mnOldPos( STREAM_SEEK_TO_END
),
53 XclImpDecrypter::~XclImpDecrypter()
57 XclImpDecrypterRef
XclImpDecrypter::Clone() const
59 XclImpDecrypterRef xNewDecr
;
61 xNewDecr
.reset( OnClone() );
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
)
83 sal_uInt64
const nNewPos
= rStrm
.Tell();
84 if( (mnOldPos
!= nNewPos
) || (mnRecSize
!= nRecSize
) )
86 OnUpdate( mnOldPos
, nNewPos
, nRecSize
);
93 sal_uInt16
XclImpDecrypter::Read( SvStream
& rStrm
, void* pData
, sal_uInt16 nBytes
)
100 Update( rStrm
, mnRecSize
);
101 nRet
= OnRead( rStrm
, static_cast< sal_uInt8
* >( pData
), nBytes
);
102 mnOldPos
= rStrm
.Tell();
105 nRet
= static_cast<sal_uInt16
>(rStrm
.ReadBytes(pData
, nBytes
));
110 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey
, sal_uInt16 nHash
) :
116 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter
& rSrc
) :
117 XclImpDecrypter( rSrc
),
118 maEncryptionData( rSrc
.maEncryptionData
),
120 mnHash( rSrc
.mnHash
)
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) )
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 );
151 std::for_each(aPassVect
.begin(), aPassVect
.begin() + nLen
,
152 [&rPassword
, &nInd
](sal_uInt16
& rPass
) {
153 rPass
= static_cast< sal_uInt16
>( rPassword
[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() )
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
);
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
))
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
)
222 XclImpBiff8StdDecrypter::XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter
& rSrc
)
223 : XclImpBiff8Decrypter(rSrc
)
227 maCodec
.InitCodec(maEncryptionData
);
230 XclImpBiff8StdDecrypter
* XclImpBiff8StdDecrypter::OnClone() const
232 return new XclImpBiff8StdDecrypter(*this);
235 XclImpBiff8CryptoAPIDecrypter::XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter
& rSrc
)
236 : XclImpBiff8Decrypter(rSrc
)
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
);
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() )
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
)
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
)
316 sal_uInt8
* pnCurrData
= pnData
;
317 sal_uInt16 nBytesLeft
= nBytes
;
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
;
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
);
348 XclImpStreamPos::XclImpStreamPos() :
349 mnPos( STREAM_SEEK_TO_BEGIN
),
350 mnNextPos( STREAM_SEEK_TO_BEGIN
),
352 mnRawRecId( EXC_ID_UNKNOWN
),
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
,
364 mnPos
= rStrm
.Tell();
365 mnNextPos
= nNextPos
;
366 mnCurrSize
= nCurrSize
;
367 mnRawRecId
= nRawRecId
;
368 mnRawRecSize
= nRawRecSize
;
369 mnRawRecLeft
= nRawRecLeft
;
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
379 rnNextPos
= mnNextPos
;
380 rnCurrSize
= mnCurrSize
;
381 rnRawRecId
= mnRawRecId
;
382 rnRawRecSize
= mnRawRecSize
;
383 rnRawRecLeft
= mnRawRecLeft
;
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
)
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
);
427 XclImpStream::XclImpStream( SvStream
& rInStrm
, const XclImpRoot
& rRoot
) :
430 mnGlobRecId( EXC_ID_UNKNOWN
),
431 mbGlobValidRec( false ),
432 mbHasGlobPos( false ),
433 mnNextRecPos( STREAM_SEEK_TO_BEGIN
),
436 mbHasComplRec( false ),
437 mnRecId( EXC_ID_UNKNOWN
),
438 mnAltContId( EXC_ID_UNKNOWN
),
439 mnRawRecId( EXC_ID_UNKNOWN
),
448 mnStreamSize
= mrStrm
.TellEnd();
449 mrStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
452 XclImpStream::~XclImpStream()
456 bool XclImpStream::StartNextRecord()
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
;
481 bool XclImpStream::StartNextRecord( std::size_t nNextRecPos
)
483 mnNextRecPos
= nNextRecPos
;
484 return StartNextRecord();
487 void XclImpStream::ResetRecord( bool bContLookup
, sal_uInt16 nAltContId
)
492 RestorePosition( maFirstRec
);
493 mnCurrRecSize
= mnComplRecSize
= mnRawRecSize
;
494 mbHasComplRec
= !bContLookup
;
495 mbCont
= bContLookup
;
496 mnAltContId
= nAltContId
;
501 void XclImpStream::RewindRecord()
503 mnNextRecPos
= maFirstRec
.GetPos();
504 mbValid
= mbValidRec
= false;
507 void XclImpStream::SetDecrypter( XclImpDecrypterRef
const & xDecrypter
)
509 mxDecrypter
= xDecrypter
;
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
;
551 void XclImpStream::SeekGlobalPosition()
553 OSL_ENSURE( mbHasGlobPos
, "XclImpStream::SeekGlobalPosition - no position stored" );
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()
574 while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
575 mnComplRecSize
= mnCurrRecSize
;
576 mbHasComplRec
= true;
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
;
593 while( JumpToNextContinue() ) ; // skip following CONTINUE records
594 if( mnNextRecPos
< mnStreamSize
)
596 mrStrm
.Seek( mnNextRecPos
);
597 mrStrm
.ReadUInt16( 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();
611 mrStrm
.ReadUInt16( nRecId
);
612 mrStrm
.Seek(nCurPos
);
617 sal_uInt8
XclImpStream::ReaduInt8()
619 sal_uInt8 nValue
= 0;
620 if( EnsureRawReadSize( 1 ) )
623 mxDecrypter
->Read( mrStrm
, &nValue
, 1 );
625 mrStrm
.ReadUChar( nValue
);
631 sal_Int16
XclImpStream::ReadInt16()
633 sal_Int16 nValue
= 0;
634 if( EnsureRawReadSize( 2 ) )
639 mxDecrypter
->Read( mrStrm
, pnBuffer
, 2 );
640 nValue
= SVBT16ToInt16(pnBuffer
);
643 mrStrm
.ReadInt16( nValue
);
649 sal_uInt16
XclImpStream::ReaduInt16()
651 sal_uInt16 nValue
= 0;
652 if( EnsureRawReadSize( 2 ) )
657 mxDecrypter
->Read( mrStrm
, pnBuffer
, 2 );
658 nValue
= SVBT16ToUInt16( pnBuffer
);
661 mrStrm
.ReadUInt16( nValue
);
667 sal_Int32
XclImpStream::ReadInt32()
669 sal_Int32 nValue
= 0;
670 if( EnsureRawReadSize( 4 ) )
675 mxDecrypter
->Read( mrStrm
, pnBuffer
, 4 );
676 nValue
= static_cast< sal_Int32
>( SVBT32ToUInt32( pnBuffer
) );
679 mrStrm
.ReadInt32( nValue
);
685 sal_uInt32
XclImpStream::ReaduInt32()
687 sal_uInt32 nValue
= 0;
688 if( EnsureRawReadSize( 4 ) )
693 mxDecrypter
->Read( mrStrm
, pnBuffer
, 4 );
694 nValue
= SVBT32ToUInt32( pnBuffer
);
697 mrStrm
.ReadUInt32( nValue
);
703 double XclImpStream::ReadDouble()
706 if( EnsureRawReadSize( 8 ) )
711 mxDecrypter
->Read( mrStrm
, pnBuffer
, 8 );
712 nValue
= SVBT64ToDouble( pnBuffer
);
715 mrStrm
.ReadDouble( 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
);
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" );
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
;
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
;
770 void XclImpStream::CopyRecordToStream( SvStream
& rOutStrm
)
775 RestorePosition( maFirstRec
);
776 CopyToStream( rOutStrm
, GetRecSize() );
781 void XclImpStream::Seek( std::size_t nPos
)
786 std::size_t nCurrPos
= GetRecPos();
787 if( !mbValid
|| (nPos
< nCurrPos
) ) // from invalid state or backward
789 RestorePosition( maFirstRec
);
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
;
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
;
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
)
847 nReadSize
= o3tl::sanitizing_min
<sal_uInt16
>(nCharsLeft
, mnRawRecLeft
/ 2);
848 OSL_ENSURE( (nReadSize
<= nCharsLeft
) || !(mnRawRecLeft
& 0x1),
849 "XclImpStream::ReadRawUniString - missing a byte" );
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
;
861 sal_uInt16 nReadChar
;
862 for( ; IsValid() && (pcUniChar
< pcEndChar
); ++pcUniChar
)
864 nReadChar
= ReaduInt16();
865 (*pcUniChar
) = (nReadChar
== EXC_NUL
) ? mcNulSubst
: static_cast< sal_Unicode
>( nReadChar
);
871 for( ; IsValid() && (pcUniChar
< pcEndChar
); ++pcUniChar
)
873 nReadChar
= ReaduInt8();
874 (*pcUniChar
) = (nReadChar
== EXC_NUL_C
) ? mcNulSubst
: static_cast< sal_Unicode
>( nReadChar
);
879 // this has the side-effect of only copying as far as the first null, which appears to be intentional. e.g.
881 aRet
.append( pcBuffer
.get() );
883 nCharsLeft
= nCharsLeft
- nReadSize
;
885 JumpToNextStringContinue( b16Bit
);
888 return aRet
.makeStringAndClear();
891 OUString
XclImpStream::ReadUniString( sal_uInt16 nChars
, sal_uInt8 nFlags
)
894 std::size_t nExtSize
= ReadUniStringExtHeader( b16Bit
, nFlags
);
895 OUString
aRet( ReadRawUniString( nChars
, b16Bit
) );
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) )
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 );
926 nReadSize
= GetMaxRawReadSize( nCharsLeft
);
930 nCharsLeft
= nCharsLeft
- nReadSize
;
932 JumpToNextStringContinue( b16Bit
);
936 void XclImpStream::IgnoreUniString( sal_uInt16 nChars
, sal_uInt8 nFlags
)
939 std::size_t nExtSize
= ReadUniStringExtHeader( b16Bit
, nFlags
);
940 IgnoreRawUniString( nChars
, b16Bit
);
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() );
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
);
977 bool XclImpStream::ReadNextRawRecHeader()
979 bool bRet
= checkSeek(mrStrm
, mnNextRecPos
) && (mnNextRecPos
+ 4 <= mnStreamSize
);
982 mrStrm
.ReadUInt16( mnRawRecId
).ReadUInt16( mnRawRecSize
);
983 bRet
= mrStrm
.good();
988 void XclImpStream::SetupDecrypter()
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
;
1009 mnComplRecSize
= mnRawRecSize
;
1010 mbHasComplRec
= !mbCont
;
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
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
1052 rb16Bit
= ::get_flag( ReaduInt8(), EXC_STRF_16BIT
);
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" );
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;
1077 nRet
= mxDecrypter
->Read( mrStrm
, pData
, nBytes
);
1079 nRet
= static_cast<sal_uInt16
>(mrStrm
.ReadBytes(pData
, nBytes
));
1080 mnRawRecLeft
= mnRawRecLeft
- nRet
;
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */