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