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 "xistream.hxx"
25 #include "xlstring.hxx"
29 #include <boost/scoped_array.hpp>
31 using namespace ::com::sun::star
;
34 XclImpDecrypter::XclImpDecrypter() :
35 mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT
),
36 mnOldPos( STREAM_SEEK_TO_END
),
41 XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter
& rSrc
) :
42 ::comphelper::IDocPasswordVerifier(),
43 mnError( rSrc
.mnError
),
44 mnOldPos( STREAM_SEEK_TO_END
),
49 XclImpDecrypter::~XclImpDecrypter()
53 XclImpDecrypterRef
XclImpDecrypter::Clone() const
55 XclImpDecrypterRef xNewDecr
;
57 xNewDecr
.reset( OnClone() );
61 ::comphelper::DocPasswordVerifierResult
XclImpDecrypter::verifyPassword( const OUString
& rPassword
, uno::Sequence
< beans::NamedValue
>& o_rEncryptionData
)
63 o_rEncryptionData
= OnVerifyPassword( rPassword
);
64 mnError
= o_rEncryptionData
.getLength() ? ERRCODE_NONE
: ERRCODE_ABORT
;
65 return o_rEncryptionData
.getLength() ? ::comphelper::DocPasswordVerifierResult_OK
: ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD
;
68 ::comphelper::DocPasswordVerifierResult
XclImpDecrypter::verifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
)
70 bool bValid
= OnVerifyEncryptionData( rEncryptionData
);
71 mnError
= bValid
? ERRCODE_NONE
: ERRCODE_ABORT
;
72 return bValid
? ::comphelper::DocPasswordVerifierResult_OK
: ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD
;
75 void XclImpDecrypter::Update( SvStream
& rStrm
, sal_uInt16 nRecSize
)
79 sal_uInt64
const nNewPos
= rStrm
.Tell();
80 if( (mnOldPos
!= nNewPos
) || (mnRecSize
!= nRecSize
) )
82 OnUpdate( mnOldPos
, nNewPos
, nRecSize
);
89 sal_uInt16
XclImpDecrypter::Read( SvStream
& rStrm
, void* pData
, sal_uInt16 nBytes
)
96 Update( rStrm
, mnRecSize
);
97 nRet
= OnRead( rStrm
, static_cast< sal_uInt8
* >( pData
), nBytes
);
98 mnOldPos
= rStrm
.Tell();
101 nRet
= static_cast< sal_uInt16
>( rStrm
.Read( pData
, nBytes
) );
106 XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey
, sal_uInt16 nHash
) :
112 XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter
& rSrc
) :
113 XclImpDecrypter( rSrc
),
114 maEncryptionData( rSrc
.maEncryptionData
),
116 mnHash( rSrc
.mnHash
)
119 maCodec
.InitCodec( maEncryptionData
);
122 XclImpBiff5Decrypter
* XclImpBiff5Decrypter::OnClone() const
124 return new XclImpBiff5Decrypter( *this );
127 uno::Sequence
< beans::NamedValue
> XclImpBiff5Decrypter::OnVerifyPassword( const OUString
& rPassword
)
129 maEncryptionData
.realloc( 0 );
131 /* Convert password to a byte string. TODO: this needs some finetuning
132 according to the spec... */
133 OString aBytePassword
= OUStringToOString( rPassword
, osl_getThreadTextEncoding() );
134 sal_Int32 nLen
= aBytePassword
.getLength();
135 if( (0 < nLen
) && (nLen
< 16) )
138 maCodec
.InitKey( reinterpret_cast<sal_uInt8
const *>(aBytePassword
.getStr()) );
140 if ( maCodec
.VerifyKey( mnKey
, mnHash
) )
142 maEncryptionData
= maCodec
.GetEncryptionData();
144 // since the export uses Std97 encryption always we have to request it here
145 ::std::vector
< sal_uInt16
> aPassVect( 16 );
146 ::std::vector
< sal_uInt16
>::iterator aIt
= aPassVect
.begin();
147 for( sal_Int32 nInd
= 0; nInd
< nLen
; ++nInd
, ++aIt
)
148 *aIt
= static_cast< sal_uInt16
>( rPassword
[nInd
] );
150 uno::Sequence
< sal_Int8
> aDocId
= ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
151 OSL_ENSURE( aDocId
.getLength() == 16, "Unexpected length of the senquence!" );
153 ::msfilter::MSCodec_Std97 aCodec97
;
154 aCodec97
.InitKey( &aPassVect
.front(), reinterpret_cast<sal_uInt8
const *>(aDocId
.getConstArray()) );
156 // merge the EncryptionData, there should be no conflicts
157 ::comphelper::SequenceAsHashMap
aEncryptionHash( maEncryptionData
);
158 aEncryptionHash
.update( ::comphelper::SequenceAsHashMap( aCodec97
.GetEncryptionData() ) );
159 aEncryptionHash
>> maEncryptionData
;
163 return maEncryptionData
;
166 bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
)
168 maEncryptionData
.realloc( 0 );
170 if( rEncryptionData
.getLength() )
173 maCodec
.InitCodec( rEncryptionData
);
175 if ( maCodec
.VerifyKey( mnKey
, mnHash
) )
176 maEncryptionData
= rEncryptionData
;
179 return maEncryptionData
.getLength();
182 void XclImpBiff5Decrypter::OnUpdate( sal_Size
/*nOldStrmPos*/, sal_Size nNewStrmPos
, sal_uInt16 nRecSize
)
184 maCodec
.InitCipher();
185 maCodec
.Skip( (nNewStrmPos
+ nRecSize
) & 0x0F );
188 sal_uInt16
XclImpBiff5Decrypter::OnRead( SvStream
& rStrm
, sal_uInt8
* pnData
, sal_uInt16 nBytes
)
190 sal_uInt16 nRet
= static_cast< sal_uInt16
>( rStrm
.Read( pnData
, nBytes
) );
191 maCodec
.Decode( pnData
, nRet
);
195 XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt
[ 16 ],
196 sal_uInt8 pnVerifier
[ 16 ], sal_uInt8 pnVerifierHash
[ 16 ] ) :
197 maSalt( pnSalt
, pnSalt
+ 16 ),
198 maVerifier( pnVerifier
, pnVerifier
+ 16 ),
199 maVerifierHash( pnVerifierHash
, pnVerifierHash
+ 16 )
203 XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter
& rSrc
) :
204 XclImpDecrypter( rSrc
),
205 maEncryptionData( rSrc
.maEncryptionData
),
206 maSalt( rSrc
.maSalt
),
207 maVerifier( rSrc
.maVerifier
),
208 maVerifierHash( rSrc
.maVerifierHash
)
211 maCodec
.InitCodec( maEncryptionData
);
214 XclImpBiff8Decrypter
* XclImpBiff8Decrypter::OnClone() const
216 return new XclImpBiff8Decrypter( *this );
219 uno::Sequence
< beans::NamedValue
> XclImpBiff8Decrypter::OnVerifyPassword( const OUString
& rPassword
)
221 maEncryptionData
.realloc( 0 );
223 sal_Int32 nLen
= rPassword
.getLength();
224 if( (0 < nLen
) && (nLen
< 16) )
226 // copy string to sal_uInt16 array
227 ::std::vector
< sal_uInt16
> aPassVect( 16 );
228 const sal_Unicode
* pcChar
= rPassword
.getStr();
229 const sal_Unicode
* pcCharEnd
= pcChar
+ nLen
;
230 ::std::vector
< sal_uInt16
>::iterator aIt
= aPassVect
.begin();
231 for( ; pcChar
< pcCharEnd
; ++pcChar
, ++aIt
)
232 *aIt
= static_cast< sal_uInt16
>( *pcChar
);
235 maCodec
.InitKey( &aPassVect
.front(), &maSalt
.front() );
236 if ( maCodec
.VerifyKey( &maVerifier
.front(), &maVerifierHash
.front() ) )
237 maEncryptionData
= maCodec
.GetEncryptionData();
240 return maEncryptionData
;
243 bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence
< beans::NamedValue
>& rEncryptionData
)
245 maEncryptionData
.realloc( 0 );
247 if( rEncryptionData
.getLength() )
250 maCodec
.InitCodec( rEncryptionData
);
252 if ( maCodec
.VerifyKey( &maVerifier
.front(), &maVerifierHash
.front() ) )
253 maEncryptionData
= rEncryptionData
;
256 return maEncryptionData
.getLength();
259 void XclImpBiff8Decrypter::OnUpdate( sal_Size nOldStrmPos
, sal_Size nNewStrmPos
, sal_uInt16
/*nRecSize*/ )
261 if( nNewStrmPos
!= nOldStrmPos
)
263 sal_uInt32 nOldBlock
= GetBlock( nOldStrmPos
);
264 sal_uInt16 nOldOffset
= GetOffset( nOldStrmPos
);
266 sal_uInt32 nNewBlock
= GetBlock( nNewStrmPos
);
267 sal_uInt16 nNewOffset
= GetOffset( nNewStrmPos
);
269 /* Rekey cipher, if block changed or if previous offset in same block. */
270 if( (nNewBlock
!= nOldBlock
) || (nNewOffset
< nOldOffset
) )
272 maCodec
.InitCipher( nNewBlock
);
273 nOldOffset
= 0; // reset nOldOffset for next if() statement
276 /* Seek to correct offset. */
277 if( nNewOffset
> nOldOffset
)
278 maCodec
.Skip( nNewOffset
- nOldOffset
);
282 sal_uInt16
XclImpBiff8Decrypter::OnRead( SvStream
& rStrm
, sal_uInt8
* pnData
, sal_uInt16 nBytes
)
286 sal_uInt8
* pnCurrData
= pnData
;
287 sal_uInt16 nBytesLeft
= nBytes
;
290 sal_uInt16 nBlockLeft
= EXC_ENCR_BLOCKSIZE
- GetOffset( rStrm
.Tell() );
291 sal_uInt16 nDecBytes
= ::std::min
< sal_uInt16
>( nBytesLeft
, nBlockLeft
);
293 // read the block from stream
294 nRet
= nRet
+ static_cast< sal_uInt16
>( rStrm
.Read( pnCurrData
, nDecBytes
) );
295 // decode the block inplace
296 maCodec
.Decode( pnCurrData
, nDecBytes
, pnCurrData
, nDecBytes
);
297 if( GetOffset( rStrm
.Tell() ) == 0 )
298 maCodec
.InitCipher( GetBlock( rStrm
.Tell() ) );
300 pnCurrData
+= nDecBytes
;
301 nBytesLeft
= nBytesLeft
- nDecBytes
;
307 sal_uInt32
XclImpBiff8Decrypter::GetBlock( sal_Size nStrmPos
)
309 return static_cast< sal_uInt32
>( nStrmPos
/ EXC_ENCR_BLOCKSIZE
);
312 sal_uInt16
XclImpBiff8Decrypter::GetOffset( sal_Size nStrmPos
)
314 return static_cast< sal_uInt16
>( nStrmPos
% EXC_ENCR_BLOCKSIZE
);
318 XclImpStreamPos::XclImpStreamPos() :
319 mnPos( STREAM_SEEK_TO_BEGIN
),
320 mnNextPos( STREAM_SEEK_TO_BEGIN
),
322 mnRawRecId( EXC_ID_UNKNOWN
),
329 void XclImpStreamPos::Set(
330 const SvStream
& rStrm
, sal_Size nNextPos
, sal_Size nCurrSize
,
331 sal_uInt16 nRawRecId
, sal_uInt16 nRawRecSize
, sal_uInt16 nRawRecLeft
,
334 mnPos
= rStrm
.Tell();
335 mnNextPos
= nNextPos
;
336 mnCurrSize
= nCurrSize
;
337 mnRawRecId
= nRawRecId
;
338 mnRawRecSize
= nRawRecSize
;
339 mnRawRecLeft
= nRawRecLeft
;
343 void XclImpStreamPos::Get(
344 SvStream
& rStrm
, sal_Size
& rnNextPos
, sal_Size
& rnCurrSize
,
345 sal_uInt16
& rnRawRecId
, sal_uInt16
& rnRawRecSize
, sal_uInt16
& rnRawRecLeft
,
346 bool& rbValid
) const
349 rnNextPos
= mnNextPos
;
350 rnCurrSize
= mnCurrSize
;
351 rnRawRecId
= mnRawRecId
;
352 rnRawRecSize
= mnRawRecSize
;
353 rnRawRecLeft
= mnRawRecLeft
;
357 XclBiff
XclImpStream::DetectBiffVersion( SvStream
& rStrm
)
359 XclBiff eBiff
= EXC_BIFF_UNKNOWN
;
361 rStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
362 sal_uInt16 nBofId
, nBofSize
;
363 rStrm
.ReadUInt16( nBofId
).ReadUInt16( nBofSize
);
365 if( (4 <= nBofSize
) && (nBofSize
<= 16) ) switch( nBofId
)
379 rStrm
.ReadUInt16( nVersion
);
380 // #i23425# #i44031# #i62752# there are some *really* broken documents out there...
381 switch( nVersion
& 0xFF00 )
383 case 0: eBiff
= EXC_BIFF5
; break; // #i44031# #i62752#
384 case EXC_BOF_BIFF2
: eBiff
= EXC_BIFF2
; break;
385 case EXC_BOF_BIFF3
: eBiff
= EXC_BIFF3
; break;
386 case EXC_BOF_BIFF4
: eBiff
= EXC_BIFF4
; break;
387 case EXC_BOF_BIFF5
: eBiff
= EXC_BIFF5
; break;
388 case EXC_BOF_BIFF8
: eBiff
= EXC_BIFF8
; break;
389 default: OSL_TRACE( "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x%04hX", nVersion
);
397 XclImpStream::XclImpStream( SvStream
& rInStrm
, const XclImpRoot
& rRoot
, bool bContLookup
) :
400 mnGlobRecId( EXC_ID_UNKNOWN
),
401 mbGlobValidRec( false ),
402 mbHasGlobPos( false ),
403 mnNextRecPos( STREAM_SEEK_TO_BEGIN
),
406 mbHasComplRec( false ),
407 mnRecId( EXC_ID_UNKNOWN
),
408 mnAltContId( EXC_ID_UNKNOWN
),
409 mnRawRecId( EXC_ID_UNKNOWN
),
413 mbCont( bContLookup
),
418 mrStrm
.Seek( STREAM_SEEK_TO_END
);
419 mnStreamSize
= mrStrm
.Tell();
420 mrStrm
.Seek( STREAM_SEEK_TO_BEGIN
);
423 XclImpStream::~XclImpStream()
427 bool XclImpStream::StartNextRecord()
431 /* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
432 "Crystal Report" writes zero records between other records) */
433 sal_Size nZeroRecCount
= 5;
434 bool bIsZeroRec
= false;
438 mbValidRec
= ReadNextRawRecHeader();
439 bIsZeroRec
= (mnRawRecId
== 0) && (mnRawRecSize
== 0);
440 if( bIsZeroRec
) --nZeroRecCount
;
441 mnNextRecPos
= mrStrm
.Tell() + mnRawRecSize
;
443 while( mbValidRec
&& ((mbCont
&& IsContinueId( mnRawRecId
)) || (bIsZeroRec
&& nZeroRecCount
)) );
445 mbValidRec
= mbValidRec
&& !bIsZeroRec
;
446 mbValid
= mbValidRec
;
452 bool XclImpStream::StartNextRecord( sal_Size nNextRecPos
)
454 mnNextRecPos
= nNextRecPos
;
455 return StartNextRecord();
458 void XclImpStream::ResetRecord( bool bContLookup
, sal_uInt16 nAltContId
)
463 RestorePosition( maFirstRec
);
464 mnCurrRecSize
= mnComplRecSize
= mnRawRecSize
;
465 mbHasComplRec
= !bContLookup
;
466 mbCont
= bContLookup
;
467 mnAltContId
= nAltContId
;
472 void XclImpStream::RewindRecord()
474 mnNextRecPos
= maFirstRec
.GetPos();
475 mbValid
= mbValidRec
= false;
478 void XclImpStream::SetDecrypter( XclImpDecrypterRef xDecrypter
)
480 mxDecrypter
= xDecrypter
;
485 void XclImpStream::CopyDecrypterFrom( const XclImpStream
& rStrm
)
487 XclImpDecrypterRef xNewDecr
;
488 if( rStrm
.mxDecrypter
)
489 xNewDecr
= rStrm
.mxDecrypter
->Clone();
490 SetDecrypter( xNewDecr
);
493 bool XclImpStream::HasValidDecrypter() const
495 return mxDecrypter
&& mxDecrypter
->IsValid();
498 void XclImpStream::EnableDecryption( bool bEnable
)
500 mbUseDecr
= bEnable
&& HasValidDecrypter();
503 void XclImpStream::PushPosition()
505 maPosStack
.push_back( XclImpStreamPos() );
506 StorePosition( maPosStack
.back() );
509 void XclImpStream::PopPosition()
511 OSL_ENSURE( !maPosStack
.empty(), "XclImpStream::PopPosition - stack empty" );
512 if( !maPosStack
.empty() )
514 RestorePosition( maPosStack
.back() );
515 maPosStack
.pop_back();
519 void XclImpStream::StoreGlobalPosition()
521 StorePosition( maGlobPos
);
522 mnGlobRecId
= mnRecId
;
523 mbGlobValidRec
= mbValidRec
;
527 void XclImpStream::SeekGlobalPosition()
529 OSL_ENSURE( mbHasGlobPos
, "XclImpStream::SeekGlobalPosition - no position stored" );
532 RestorePosition( maGlobPos
);
533 mnRecId
= mnGlobRecId
;
534 mnComplRecSize
= mnCurrRecSize
;
535 mbHasComplRec
= !mbCont
;
536 mbValidRec
= mbGlobValidRec
;
540 sal_Size
XclImpStream::GetRecPos() const
542 return mbValid
? (mnCurrRecSize
- mnRawRecLeft
) : EXC_REC_SEEK_TO_END
;
545 sal_Size
XclImpStream::GetRecSize()
550 while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
551 mnComplRecSize
= mnCurrRecSize
;
552 mbHasComplRec
= true;
555 return mnComplRecSize
;
558 sal_Size
XclImpStream::GetRecLeft()
560 return mbValid
? (GetRecSize() - GetRecPos()) : 0;
563 sal_uInt16
XclImpStream::GetNextRecId()
565 sal_uInt16 nRecId
= EXC_ID_UNKNOWN
;
569 while( JumpToNextContinue() ) ; // skip following CONTINUE records
570 if( mnNextRecPos
< mnStreamSize
)
572 mrStrm
.Seek( mnNextRecPos
);
573 mrStrm
.ReadUInt16( nRecId
);
580 sal_uInt16
XclImpStream::PeekRecId( sal_Size nPos
)
582 sal_uInt16 nRecId
= EXC_ID_UNKNOWN
;
583 if (mbValidRec
&& nPos
< mnStreamSize
)
585 sal_Size nCurPos
= mrStrm
.Tell();
587 mrStrm
.ReadUInt16( nRecId
);
588 mrStrm
.Seek(nCurPos
);
593 sal_uInt8
XclImpStream::ReaduInt8()
595 sal_uInt8 nValue
= 0;
596 if( EnsureRawReadSize( 1 ) )
599 mxDecrypter
->Read( mrStrm
, &nValue
, 1 );
601 mrStrm
.ReadUChar( nValue
);
607 sal_Int16
XclImpStream::ReadInt16()
609 sal_Int16 nValue
= 0;
610 if( EnsureRawReadSize( 2 ) )
615 mxDecrypter
->Read( mrStrm
, pnBuffer
, 2 );
616 nValue
= static_cast< sal_Int16
>( SVBT16ToShort( pnBuffer
) );
619 mrStrm
.ReadInt16( nValue
);
625 sal_uInt16
XclImpStream::ReaduInt16()
627 sal_uInt16 nValue
= 0;
628 if( EnsureRawReadSize( 2 ) )
633 mxDecrypter
->Read( mrStrm
, pnBuffer
, 2 );
634 nValue
= SVBT16ToShort( pnBuffer
);
637 mrStrm
.ReadUInt16( nValue
);
643 sal_Int32
XclImpStream::ReadInt32()
645 sal_Int32 nValue
= 0;
646 if( EnsureRawReadSize( 4 ) )
651 mxDecrypter
->Read( mrStrm
, pnBuffer
, 4 );
652 nValue
= static_cast< sal_Int32
>( SVBT32ToUInt32( pnBuffer
) );
655 mrStrm
.ReadInt32( nValue
);
661 sal_uInt32
XclImpStream::ReaduInt32()
663 sal_uInt32 nValue
= 0;
664 if( EnsureRawReadSize( 4 ) )
669 mxDecrypter
->Read( mrStrm
, pnBuffer
, 4 );
670 nValue
= SVBT32ToUInt32( pnBuffer
);
673 mrStrm
.ReadUInt32( nValue
);
679 double XclImpStream::ReadDouble()
682 if( EnsureRawReadSize( 8 ) )
687 mxDecrypter
->Read( mrStrm
, pnBuffer
, 8 );
688 nValue
= SVBT64ToDouble( pnBuffer
);
691 mrStrm
.ReadDouble( nValue
);
697 sal_Size
XclImpStream::Read( void* pData
, sal_Size nBytes
)
700 if( mbValid
&& pData
&& (nBytes
> 0) )
702 sal_uInt8
* pnBuffer
= static_cast< sal_uInt8
* >( pData
);
703 sal_Size nBytesLeft
= nBytes
;
705 while( mbValid
&& (nBytesLeft
> 0) )
707 sal_uInt16 nReadSize
= GetMaxRawReadSize( nBytesLeft
);
708 sal_uInt16 nReadRet
= ReadRawData( pnBuffer
, nReadSize
);
710 mbValid
= (nReadSize
== nReadRet
);
711 OSL_ENSURE( mbValid
, "XclImpStream::Read - stream read error" );
712 pnBuffer
+= nReadRet
;
713 nBytesLeft
-= nReadRet
;
714 if( mbValid
&& (nBytesLeft
> 0) )
715 JumpToNextContinue();
716 OSL_ENSURE( mbValid
, "XclImpStream::Read - record overread" );
722 sal_Size
XclImpStream::CopyToStream( SvStream
& rOutStrm
, sal_Size nBytes
)
725 if( mbValid
&& (nBytes
> 0) )
727 const sal_Size nMaxBuffer
= 4096;
728 boost::scoped_array
<sal_uInt8
> pnBuffer(new sal_uInt8
[ ::std::min( nBytes
, nMaxBuffer
) ]);
729 sal_Size nBytesLeft
= nBytes
;
731 while( mbValid
&& (nBytesLeft
> 0) )
733 sal_Size nReadSize
= ::std::min( nBytesLeft
, nMaxBuffer
);
734 nRet
+= Read( pnBuffer
.get(), nReadSize
);
735 // writing more bytes than read results in invalid memory access
736 SAL_WARN_IF(nRet
!= nReadSize
, "sc", "read less bytes than requested");
737 rOutStrm
.Write( pnBuffer
.get(), nReadSize
);
738 nBytesLeft
-= nReadSize
;
744 sal_Size
XclImpStream::CopyRecordToStream( SvStream
& rOutStrm
)
750 RestorePosition( maFirstRec
);
751 nRet
= CopyToStream( rOutStrm
, GetRecSize() );
757 void XclImpStream::Seek( sal_Size nPos
)
761 sal_Size nCurrPos
= GetRecPos();
762 if( !mbValid
|| (nPos
< nCurrPos
) ) // from invalid state or backward
764 RestorePosition( maFirstRec
);
767 else if( nPos
> nCurrPos
) // forward
769 Ignore( nPos
- nCurrPos
);
774 void XclImpStream::Ignore( sal_Size nBytes
)
776 // implementation similar to Read(), but without really reading anything
777 sal_Size nBytesLeft
= nBytes
;
778 while( mbValid
&& (nBytesLeft
> 0) )
780 sal_uInt16 nReadSize
= GetMaxRawReadSize( nBytesLeft
);
781 mrStrm
.SeekRel( nReadSize
);
782 mnRawRecLeft
= mnRawRecLeft
- nReadSize
;
783 nBytesLeft
-= nReadSize
;
785 JumpToNextContinue();
786 OSL_ENSURE( mbValid
, "XclImpStream::Ignore - record overread" );
790 sal_Size
XclImpStream::ReadUniStringExtHeader(
791 bool& rb16Bit
, bool& rbRich
, bool& rbFareast
,
792 sal_uInt16
& rnFormatRuns
, sal_uInt32
& rnExtInf
, sal_uInt8 nFlags
)
794 OSL_ENSURE( !::get_flag( nFlags
, EXC_STRF_UNKNOWN
), "XclImpStream::ReadUniStringExt - unknown flags" );
795 rb16Bit
= ::get_flag( nFlags
, EXC_STRF_16BIT
);
796 rbRich
= ::get_flag( nFlags
, EXC_STRF_RICH
);
797 rbFareast
= ::get_flag( nFlags
, EXC_STRF_FAREAST
);
798 rnFormatRuns
= rbRich
? ReaduInt16() : 0;
799 rnExtInf
= rbFareast
? ReaduInt32() : 0;
800 return rnExtInf
+ 4 * rnFormatRuns
;
803 sal_Size
XclImpStream::ReadUniStringExtHeader( bool& rb16Bit
, sal_uInt8 nFlags
)
805 bool bRich
, bFareast
;
808 return ReadUniStringExtHeader( rb16Bit
, bRich
, bFareast
, nCrun
, nExtInf
, nFlags
);
811 OUString
XclImpStream::ReadRawUniString( sal_uInt16 nChars
, bool b16Bit
)
814 sal_uInt16 nCharsLeft
= nChars
;
815 sal_uInt16 nReadSize
;
817 boost::scoped_array
<sal_Unicode
> pcBuffer(new sal_Unicode
[ nCharsLeft
+ 1 ]);
819 while( IsValid() && (nCharsLeft
> 0) )
823 nReadSize
= ::std::min
< sal_uInt16
>( nCharsLeft
, mnRawRecLeft
/ 2 );
824 OSL_ENSURE( (nReadSize
<= nCharsLeft
) || !(mnRawRecLeft
& 0x1),
825 "XclImpStream::ReadRawUniString - missing a byte" );
828 nReadSize
= GetMaxRawReadSize( nCharsLeft
);
830 sal_Unicode
* pcUniChar
= pcBuffer
.get();
831 sal_Unicode
* pcEndChar
= pcBuffer
.get() + nReadSize
;
835 sal_uInt16 nReadChar
;
836 for( ; IsValid() && (pcUniChar
< pcEndChar
); ++pcUniChar
)
838 nReadChar
= ReaduInt16();
839 (*pcUniChar
) = (nReadChar
== EXC_NUL
) ? mcNulSubst
: static_cast< sal_Unicode
>( nReadChar
);
845 for( ; IsValid() && (pcUniChar
< pcEndChar
); ++pcUniChar
)
847 nReadChar
= ReaduInt8();
848 (*pcUniChar
) = (nReadChar
== EXC_NUL_C
) ? mcNulSubst
: static_cast< sal_Unicode
>( nReadChar
);
853 aRet
+= OUString( pcBuffer
.get() );
855 nCharsLeft
= nCharsLeft
- nReadSize
;
857 JumpToNextStringContinue( b16Bit
);
863 OUString
XclImpStream::ReadUniString( sal_uInt16 nChars
, sal_uInt8 nFlags
)
866 sal_Size nExtSize
= ReadUniStringExtHeader( b16Bit
, nFlags
);
867 OUString
aRet( ReadRawUniString( nChars
, b16Bit
) );
872 OUString
XclImpStream::ReadUniString( sal_uInt16 nChars
)
874 return ReadUniString( nChars
, ReaduInt8() );
877 OUString
XclImpStream::ReadUniString()
879 return ReadUniString( ReaduInt16() );
882 void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars
, bool b16Bit
)
884 sal_uInt16 nCharsLeft
= nChars
;
885 sal_uInt16 nReadSize
;
887 while( IsValid() && (nCharsLeft
> 0) )
891 nReadSize
= ::std::min
< sal_uInt16
>( nCharsLeft
, mnRawRecLeft
/ 2 );
892 OSL_ENSURE( (nReadSize
<= nCharsLeft
) || !(mnRawRecLeft
& 0x1),
893 "XclImpStream::IgnoreRawUniString - missing a byte" );
894 Ignore( nReadSize
* 2 );
898 nReadSize
= GetMaxRawReadSize( nCharsLeft
);
902 nCharsLeft
= nCharsLeft
- nReadSize
;
904 JumpToNextStringContinue( b16Bit
);
908 void XclImpStream::IgnoreUniString( sal_uInt16 nChars
, sal_uInt8 nFlags
)
911 sal_Size nExtSize
= ReadUniStringExtHeader( b16Bit
, nFlags
);
912 IgnoreRawUniString( nChars
, b16Bit
);
916 void XclImpStream::IgnoreUniString( sal_uInt16 nChars
)
918 IgnoreUniString( nChars
, ReaduInt8() );
921 OUString
XclImpStream::ReadRawByteString( sal_uInt16 nChars
)
923 nChars
= GetMaxRawReadSize(nChars
);
924 boost::scoped_array
<sal_Char
> pcBuffer(new sal_Char
[ nChars
+ 1 ]);
925 sal_uInt16 nCharsRead
= ReadRawData( pcBuffer
.get(), nChars
);
926 pcBuffer
[ nCharsRead
] = '\0';
927 OUString
aRet( pcBuffer
.get(), strlen(pcBuffer
.get()), mrRoot
.GetTextEncoding() );
931 OUString
XclImpStream::ReadByteString( bool b16BitLen
)
933 return ReadRawByteString( ReadByteStrLen( b16BitLen
) );
936 // private --------------------------------------------------------------------
938 void XclImpStream::StorePosition( XclImpStreamPos
& rPos
)
940 rPos
.Set( mrStrm
, mnNextRecPos
, mnCurrRecSize
, mnRawRecId
, mnRawRecSize
, mnRawRecLeft
, mbValid
);
943 void XclImpStream::RestorePosition( const XclImpStreamPos
& rPos
)
945 rPos
.Get( mrStrm
, mnNextRecPos
, mnCurrRecSize
, mnRawRecId
, mnRawRecSize
, mnRawRecLeft
, mbValid
);
949 bool XclImpStream::ReadNextRawRecHeader()
951 sal_Size nSeekedPos
= mrStrm
.Seek( mnNextRecPos
);
952 bool bRet
= (nSeekedPos
== mnNextRecPos
) && (mnNextRecPos
+ 4 <= mnStreamSize
);
955 mrStrm
.ReadUInt16( mnRawRecId
).ReadUInt16( mnRawRecSize
);
956 bRet
= mrStrm
.good();
961 void XclImpStream::SetupDecrypter()
964 mxDecrypter
->Update( mrStrm
, mnRawRecSize
);
967 void XclImpStream::SetupRawRecord()
969 // pre: mnRawRecSize contains current raw record size
970 // pre: mrStrm points to start of raw record data
971 mnNextRecPos
= mrStrm
.Tell() + mnRawRecSize
;
972 mnRawRecLeft
= mnRawRecSize
;
973 mnCurrRecSize
+= mnRawRecSize
;
974 SetupDecrypter(); // decrypter works on raw record level
977 void XclImpStream::SetupRecord()
979 mnRecId
= mnRawRecId
;
980 mnAltContId
= EXC_ID_UNKNOWN
;
982 mnComplRecSize
= mnRawRecSize
;
983 mbHasComplRec
= !mbCont
;
987 StorePosition( maFirstRec
);
990 bool XclImpStream::IsContinueId( sal_uInt16 nRecId
) const
992 return (nRecId
== EXC_ID_CONT
) || (nRecId
== mnAltContId
);
995 bool XclImpStream::JumpToNextContinue()
997 mbValid
= mbValid
&& mbCont
&& ReadNextRawRecHeader() && IsContinueId( mnRawRecId
);
998 if( mbValid
) // do not setup a following non-CONTINUE record
1003 bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit
)
1005 OSL_ENSURE( mnRawRecLeft
== 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
1007 if( mbCont
&& (GetRecLeft() > 0) )
1009 JumpToNextContinue();
1011 else if( mnRecId
== EXC_ID_CONT
)
1013 // CONTINUE handling is off, but we have started reading in a CONTINUE record
1014 // -> start next CONTINUE for TXO import
1015 mbValidRec
= ReadNextRawRecHeader() && ((mnRawRecId
!= 0) || (mnRawRecSize
> 0));
1016 mbValid
= mbValidRec
&& (mnRawRecId
== EXC_ID_CONT
);
1017 // we really start a new record here - no chance to return to string origin
1025 rb16Bit
= ::get_flag( ReaduInt8(), EXC_STRF_16BIT
);
1029 bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes
)
1031 if( mbValid
&& nBytes
)
1033 while( mbValid
&& !mnRawRecLeft
) JumpToNextContinue();
1034 mbValid
= mbValid
&& (nBytes
<= mnRawRecLeft
);
1035 OSL_ENSURE( mbValid
, "XclImpStream::EnsureRawReadSize - record overread" );
1040 sal_uInt16
XclImpStream::GetMaxRawReadSize( sal_Size nBytes
) const
1042 return static_cast< sal_uInt16
>( ::std::min
< sal_Size
>( nBytes
, mnRawRecLeft
) );
1045 sal_uInt16
XclImpStream::ReadRawData( void* pData
, sal_uInt16 nBytes
)
1047 OSL_ENSURE( (nBytes
<= mnRawRecLeft
), "XclImpStream::ReadRawData - record overread" );
1048 sal_uInt16 nRet
= 0;
1050 nRet
= mxDecrypter
->Read( mrStrm
, pData
, nBytes
);
1052 nRet
= static_cast< sal_uInt16
>( mrStrm
.Read( pData
, nBytes
) );
1053 mnRawRecLeft
= mnRawRecLeft
- nRet
;
1057 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */