blob: cb72939da6322f7f180486c0305c3c31565ee968 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
#include <comphelper/docpasswordhelper.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include "xistream.hxx"
#include "xlstring.hxx"
#include "xiroot.hxx"
#include <vector>
using ::rtl::OString;
using ::rtl::OUString;
using ::rtl::OUStringToOString;
using namespace ::com::sun::star;
// ============================================================================
// Decryption
// ============================================================================
XclImpDecrypter::XclImpDecrypter() :
mnError( EXC_ENCR_ERROR_UNSUPP_CRYPT ),
mnOldPos( STREAM_SEEK_TO_END ),
mnRecSize( 0 )
{
}
XclImpDecrypter::XclImpDecrypter( const XclImpDecrypter& rSrc ) :
::comphelper::IDocPasswordVerifier(),
mnError( rSrc.mnError ),
mnOldPos( STREAM_SEEK_TO_END ),
mnRecSize( 0 )
{
}
XclImpDecrypter::~XclImpDecrypter()
{
}
XclImpDecrypterRef XclImpDecrypter::Clone() const
{
XclImpDecrypterRef xNewDecr;
if( IsValid() )
xNewDecr.reset( OnClone() );
return xNewDecr;
}
::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyPassword( const ::rtl::OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData )
{
o_rEncryptionData = OnVerifyPassword( rPassword );
mnError = o_rEncryptionData.getLength() ? ERRCODE_NONE : ERRCODE_ABORT;
return o_rEncryptionData.getLength() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
}
::comphelper::DocPasswordVerifierResult XclImpDecrypter::verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
{
bool bValid = OnVerifyEncryptionData( rEncryptionData );
mnError = bValid ? ERRCODE_NONE : ERRCODE_ABORT;
return bValid ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
}
void XclImpDecrypter::Update( SvStream& rStrm, sal_uInt16 nRecSize )
{
if( IsValid() )
{
sal_Size nNewPos = rStrm.Tell();
if( (mnOldPos != nNewPos) || (mnRecSize != nRecSize) )
{
OnUpdate( mnOldPos, nNewPos, nRecSize );
mnOldPos = nNewPos;
mnRecSize = nRecSize;
}
}
}
sal_uInt16 XclImpDecrypter::Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes )
{
sal_uInt16 nRet = 0;
if( pData && nBytes )
{
if( IsValid() )
{
Update( rStrm, mnRecSize );
nRet = OnRead( rStrm, reinterpret_cast< sal_uInt8* >( pData ), nBytes );
mnOldPos = rStrm.Tell();
}
else
nRet = static_cast< sal_uInt16 >( rStrm.Read( pData, nBytes ) );
}
return nRet;
}
// ----------------------------------------------------------------------------
XclImpBiff5Decrypter::XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ) :
mnKey( nKey ),
mnHash( nHash )
{
}
XclImpBiff5Decrypter::XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ) :
XclImpDecrypter( rSrc ),
maEncryptionData( rSrc.maEncryptionData ),
mnKey( rSrc.mnKey ),
mnHash( rSrc.mnHash )
{
if( IsValid() )
maCodec.InitCodec( maEncryptionData );
}
XclImpBiff5Decrypter* XclImpBiff5Decrypter::OnClone() const
{
return new XclImpBiff5Decrypter( *this );
}
uno::Sequence< beans::NamedValue > XclImpBiff5Decrypter::OnVerifyPassword( const ::rtl::OUString& rPassword )
{
maEncryptionData.realloc( 0 );
/* Convert password to a byte string. TODO: this needs some finetuning
according to the spec... */
OString aBytePassword = OUStringToOString( rPassword, osl_getThreadTextEncoding() );
sal_Int32 nLen = aBytePassword.getLength();
if( (0 < nLen) && (nLen < 16) )
{
// init codec
maCodec.InitKey( (sal_uInt8*)aBytePassword.getStr() );
if ( maCodec.VerifyKey( mnKey, mnHash ) )
{
maEncryptionData = maCodec.GetEncryptionData();
// since the export uses Std97 encryption always we have to request it here
::std::vector< sal_uInt16 > aPassVect( 16 );
::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
for( sal_Int32 nInd = 0; nInd < nLen; ++nInd, ++aIt )
*aIt = static_cast< sal_uInt16 >( rPassword.getStr()[nInd] );
uno::Sequence< sal_Int8 > aDocId = ::comphelper::DocPasswordHelper::GenerateRandomByteSequence( 16 );
OSL_ENSURE( aDocId.getLength() == 16, "Unexpected length of the senquence!" );
::msfilter::MSCodec_Std97 aCodec97;
aCodec97.InitKey( &aPassVect.front(), (sal_uInt8*)aDocId.getConstArray() );
// merge the EncryptionData, there should be no conflicts
::comphelper::SequenceAsHashMap aEncryptionHash( maEncryptionData );
aEncryptionHash.update( ::comphelper::SequenceAsHashMap( aCodec97.GetEncryptionData() ) );
aEncryptionHash >> maEncryptionData;
}
}
return maEncryptionData;
}
bool XclImpBiff5Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
{
maEncryptionData.realloc( 0 );
if( rEncryptionData.getLength() )
{
// init codec
maCodec.InitCodec( rEncryptionData );
if ( maCodec.VerifyKey( mnKey, mnHash ) )
maEncryptionData = rEncryptionData;
}
return maEncryptionData.getLength();
}
void XclImpBiff5Decrypter::OnUpdate( sal_Size /*nOldStrmPos*/, sal_Size nNewStrmPos, sal_uInt16 nRecSize )
{
maCodec.InitCipher();
maCodec.Skip( (nNewStrmPos + nRecSize) & 0x0F );
}
sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
{
sal_uInt16 nRet = static_cast< sal_uInt16 >( rStrm.Read( pnData, nBytes ) );
maCodec.Decode( pnData, nRet );
return nRet;
}
// ----------------------------------------------------------------------------
XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
maSalt( pnSalt, pnSalt + 16 ),
maVerifier( pnVerifier, pnVerifier + 16 ),
maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
{
}
XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ) :
XclImpDecrypter( rSrc ),
maEncryptionData( rSrc.maEncryptionData ),
maSalt( rSrc.maSalt ),
maVerifier( rSrc.maVerifier ),
maVerifierHash( rSrc.maVerifierHash )
{
if( IsValid() )
maCodec.InitCodec( maEncryptionData );
}
XclImpBiff8Decrypter* XclImpBiff8Decrypter::OnClone() const
{
return new XclImpBiff8Decrypter( *this );
}
uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const ::rtl::OUString& rPassword )
{
maEncryptionData.realloc( 0 );
sal_Int32 nLen = rPassword.getLength();
if( (0 < nLen) && (nLen < 16) )
{
// copy string to sal_uInt16 array
::std::vector< sal_uInt16 > aPassVect( 16 );
const sal_Unicode* pcChar = rPassword.getStr();
const sal_Unicode* pcCharEnd = pcChar + nLen;
::std::vector< sal_uInt16 >::iterator aIt = aPassVect.begin();
for( ; pcChar < pcCharEnd; ++pcChar, ++aIt )
*aIt = static_cast< sal_uInt16 >( *pcChar );
// init codec
maCodec.InitKey( &aPassVect.front(), &maSalt.front() );
if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
maEncryptionData = maCodec.GetEncryptionData();
}
return maEncryptionData;
}
bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData )
{
maEncryptionData.realloc( 0 );
if( rEncryptionData.getLength() )
{
// init codec
maCodec.InitCodec( rEncryptionData );
if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
maEncryptionData = rEncryptionData;
}
return maEncryptionData.getLength();
}
void XclImpBiff8Decrypter::OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 /*nRecSize*/ )
{
if( nNewStrmPos != nOldStrmPos )
{
sal_uInt32 nOldBlock = GetBlock( nOldStrmPos );
sal_uInt16 nOldOffset = GetOffset( nOldStrmPos );
sal_uInt32 nNewBlock = GetBlock( nNewStrmPos );
sal_uInt16 nNewOffset = GetOffset( nNewStrmPos );
/* Rekey cipher, if block changed or if previous offset in same block. */
if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
{
maCodec.InitCipher( nNewBlock );
nOldOffset = 0; // reset nOldOffset for next if() statement
}
/* Seek to correct offset. */
if( nNewOffset > nOldOffset )
maCodec.Skip( nNewOffset - nOldOffset );
}
}
sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes )
{
sal_uInt16 nRet = 0;
sal_uInt8* pnCurrData = pnData;
sal_uInt16 nBytesLeft = nBytes;
while( nBytesLeft )
{
sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - GetOffset( rStrm.Tell() );
sal_uInt16 nDecBytes = ::std::min< sal_uInt16 >( nBytesLeft, nBlockLeft );
// read the block from stream
nRet = nRet + static_cast< sal_uInt16 >( rStrm.Read( pnCurrData, nDecBytes ) );
// decode the block inplace
maCodec.Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
if( GetOffset( rStrm.Tell() ) == 0 )
maCodec.InitCipher( GetBlock( rStrm.Tell() ) );
pnCurrData += nDecBytes;
nBytesLeft = nBytesLeft - nDecBytes;
}
return nRet;
}
sal_uInt32 XclImpBiff8Decrypter::GetBlock( sal_Size nStrmPos ) const
{
return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE );
}
sal_uInt16 XclImpBiff8Decrypter::GetOffset( sal_Size nStrmPos ) const
{
return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE );
}
// ============================================================================
// Stream
// ============================================================================
XclImpStreamPos::XclImpStreamPos() :
mnPos( STREAM_SEEK_TO_BEGIN ),
mnNextPos( STREAM_SEEK_TO_BEGIN ),
mnCurrSize( 0 ),
mnRawRecId( EXC_ID_UNKNOWN ),
mnRawRecSize( 0 ),
mnRawRecLeft( 0 ),
mbValid( false )
{
}
void XclImpStreamPos::Set(
const SvStream& rStrm, sal_Size nNextPos, sal_Size nCurrSize,
sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft,
bool bValid )
{
mnPos = rStrm.Tell();
mnNextPos = nNextPos;
mnCurrSize = nCurrSize;
mnRawRecId = nRawRecId;
mnRawRecSize = nRawRecSize;
mnRawRecLeft = nRawRecLeft;
mbValid = bValid;
}
void XclImpStreamPos::Get(
SvStream& rStrm, sal_Size& rnNextPos, sal_Size& rnCurrSize,
sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft,
bool& rbValid ) const
{
rStrm.Seek( mnPos );
rnNextPos = mnNextPos;
rnCurrSize = mnCurrSize;
rnRawRecId = mnRawRecId;
rnRawRecSize = mnRawRecSize;
rnRawRecLeft = mnRawRecLeft;
rbValid = mbValid;
}
// ============================================================================
XclBiff XclImpStream::DetectBiffVersion( SvStream& rStrm )
{
XclBiff eBiff = EXC_BIFF_UNKNOWN;
rStrm.Seek( STREAM_SEEK_TO_BEGIN );
sal_uInt16 nBofId, nBofSize;
rStrm >> nBofId >> nBofSize;
if( (4 <= nBofSize) && (nBofSize <= 16) ) switch( nBofId )
{
case EXC_ID2_BOF:
eBiff = EXC_BIFF2;
break;
case EXC_ID3_BOF:
eBiff = EXC_BIFF3;
break;
case EXC_ID4_BOF:
eBiff = EXC_BIFF4;
break;
case EXC_ID5_BOF:
{
sal_uInt16 nVersion;
rStrm >> nVersion;
// #i23425# #i44031# #i62752# there are some *really* broken documents out there...
switch( nVersion & 0xFF00 )
{
case 0: eBiff = EXC_BIFF5; break; // #i44031# #i62752#
case EXC_BOF_BIFF2: eBiff = EXC_BIFF2; break;
case EXC_BOF_BIFF3: eBiff = EXC_BIFF3; break;
case EXC_BOF_BIFF4: eBiff = EXC_BIFF4; break;
case EXC_BOF_BIFF5: eBiff = EXC_BIFF5; break;
case EXC_BOF_BIFF8: eBiff = EXC_BIFF8; break;
default: DBG_ERROR1( "XclImpStream::DetectBiffVersion - unknown BIFF version: 0x%04hX", nVersion );
}
}
break;
}
return eBiff;
}
XclImpStream::XclImpStream( SvStream& rInStrm, const XclImpRoot& rRoot, bool bContLookup ) :
mrStrm( rInStrm ),
mrRoot( rRoot ),
mnGlobRecId( EXC_ID_UNKNOWN ),
mbGlobValidRec( false ),
mbHasGlobPos( false ),
mnNextRecPos( STREAM_SEEK_TO_BEGIN ),
mnCurrRecSize( 0 ),
mnComplRecSize( 0 ),
mbHasComplRec( false ),
mnRecId( EXC_ID_UNKNOWN ),
mnAltContId( EXC_ID_UNKNOWN ),
mnRawRecId( EXC_ID_UNKNOWN ),
mnRawRecSize( 0 ),
mnRawRecLeft( 0 ),
mcNulSubst( '?' ),
mbCont( bContLookup ),
mbUseDecr( false ),
mbValidRec( false ),
mbValid( false )
{
mrStrm.Seek( STREAM_SEEK_TO_END );
mnStreamSize = mrStrm.Tell();
mrStrm.Seek( STREAM_SEEK_TO_BEGIN );
DBG_ASSERT( mnStreamSize < STREAM_SEEK_TO_END, "XclImpStream::XclImpStream - stream error" );
}
XclImpStream::~XclImpStream()
{
}
bool XclImpStream::StartNextRecord()
{
maPosStack.clear();
/* #i4266# Counter to ignore zero records (id==len==0) (i.e. the application
"Crystal Report" writes zero records between other records) */
sal_Size nZeroRecCount = 5;
bool bIsZeroRec = false;
do
{
mbValidRec = ReadNextRawRecHeader();
bIsZeroRec = (mnRawRecId == 0) && (mnRawRecSize == 0);
if( bIsZeroRec ) --nZeroRecCount;
mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
}
while( mbValidRec && ((mbCont && IsContinueId( mnRawRecId )) || (bIsZeroRec && nZeroRecCount)) );
mbValidRec = mbValidRec && !bIsZeroRec;
mbValid = mbValidRec;
SetupRecord();
return mbValidRec;
}
bool XclImpStream::StartNextRecord( sal_Size nNextRecPos )
{
mnNextRecPos = nNextRecPos;
return StartNextRecord();
}
void XclImpStream::ResetRecord( bool bContLookup, sal_uInt16 nAltContId )
{
if( mbValidRec )
{
maPosStack.clear();
RestorePosition( maFirstRec );
mnCurrRecSize = mnComplRecSize = mnRawRecSize;
mbHasComplRec = !bContLookup;
mbCont = bContLookup;
mnAltContId = nAltContId;
EnableDecryption();
}
}
void XclImpStream::RewindRecord()
{
mnNextRecPos = maFirstRec.GetPos();
mbValid = mbValidRec = false;
}
void XclImpStream::SetDecrypter( XclImpDecrypterRef xDecrypter )
{
mxDecrypter = xDecrypter;
EnableDecryption();
SetupDecrypter();
}
void XclImpStream::CopyDecrypterFrom( const XclImpStream& rStrm )
{
XclImpDecrypterRef xNewDecr;
if( rStrm.mxDecrypter.is() )
xNewDecr = rStrm.mxDecrypter->Clone();
SetDecrypter( xNewDecr );
}
bool XclImpStream::HasValidDecrypter() const
{
return mxDecrypter.is() && mxDecrypter->IsValid();
}
void XclImpStream::EnableDecryption( bool bEnable )
{
mbUseDecr = bEnable && HasValidDecrypter();
}
// ----------------------------------------------------------------------------
void XclImpStream::PushPosition()
{
maPosStack.push_back( XclImpStreamPos() );
StorePosition( maPosStack.back() );
}
void XclImpStream::PopPosition()
{
DBG_ASSERT( !maPosStack.empty(), "XclImpStream::PopPosition - stack empty" );
if( !maPosStack.empty() )
{
RestorePosition( maPosStack.back() );
maPosStack.pop_back();
}
}
//UNUSED2008-05 void XclImpStream::RejectPosition()
//UNUSED2008-05 {
//UNUSED2008-05 DBG_ASSERT( !maPosStack.empty(), "XclImpStream::RejectPosition - stack empty" );
//UNUSED2008-05 if( !maPosStack.empty() )
//UNUSED2008-05 maPosStack.pop_back();
//UNUSED2008-05 }
void XclImpStream::StoreGlobalPosition()
{
StorePosition( maGlobPos );
mnGlobRecId = mnRecId;
mbGlobValidRec = mbValidRec;
mbHasGlobPos = true;
}
void XclImpStream::SeekGlobalPosition()
{
DBG_ASSERT( mbHasGlobPos, "XclImpStream::SeekGlobalPosition - no position stored" );
if( mbHasGlobPos )
{
RestorePosition( maGlobPos );
mnRecId = mnGlobRecId;
mnComplRecSize = mnCurrRecSize;
mbHasComplRec = !mbCont;
mbValidRec = mbGlobValidRec;
}
}
sal_Size XclImpStream::GetRecPos() const
{
return mbValid ? (mnCurrRecSize - mnRawRecLeft) : EXC_REC_SEEK_TO_END;
}
sal_Size XclImpStream::GetRecSize()
{
if( !mbHasComplRec )
{
PushPosition();
while( JumpToNextContinue() ) ; // JumpToNextContinue() adds up mnCurrRecSize
mnComplRecSize = mnCurrRecSize;
mbHasComplRec = true;
PopPosition();
}
return mnComplRecSize;
}
sal_Size XclImpStream::GetRecLeft()
{
return mbValid ? (GetRecSize() - GetRecPos()) : 0;
}
sal_uInt16 XclImpStream::GetNextRecId()
{
sal_uInt16 nRecId = EXC_ID_UNKNOWN;
if( mbValidRec )
{
PushPosition();
while( JumpToNextContinue() ) ; // skip following CONTINUE records
if( mnNextRecPos < mnStreamSize )
{
mrStrm.Seek( mnNextRecPos );
mrStrm >> nRecId;
}
PopPosition();
}
return nRecId;
}
// ----------------------------------------------------------------------------
XclImpStream& XclImpStream::operator>>( sal_Int8& rnValue )
{
if( EnsureRawReadSize( 1 ) )
{
if( mbUseDecr )
mxDecrypter->Read( mrStrm, &rnValue, 1 );
else
mrStrm >> rnValue;
--mnRawRecLeft;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( sal_uInt8& rnValue )
{
if( EnsureRawReadSize( 1 ) )
{
if( mbUseDecr )
mxDecrypter->Read( mrStrm, &rnValue, 1 );
else
mrStrm >> rnValue;
--mnRawRecLeft;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( sal_Int16& rnValue )
{
if( EnsureRawReadSize( 2 ) )
{
if( mbUseDecr )
{
SVBT16 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 2 );
rnValue = static_cast< sal_Int16 >( SVBT16ToShort( pnBuffer ) );
}
else
mrStrm >> rnValue;
mnRawRecLeft -= 2;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( sal_uInt16& rnValue )
{
if( EnsureRawReadSize( 2 ) )
{
if( mbUseDecr )
{
SVBT16 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 2 );
rnValue = SVBT16ToShort( pnBuffer );
}
else
mrStrm >> rnValue;
mnRawRecLeft -= 2;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( sal_Int32& rnValue )
{
if( EnsureRawReadSize( 4 ) )
{
if( mbUseDecr )
{
SVBT32 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 4 );
rnValue = static_cast< sal_Int32 >( SVBT32ToUInt32( pnBuffer ) );
}
else
mrStrm >> rnValue;
mnRawRecLeft -= 4;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( sal_uInt32& rnValue )
{
if( EnsureRawReadSize( 4 ) )
{
if( mbUseDecr )
{
SVBT32 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 4 );
rnValue = SVBT32ToUInt32( pnBuffer );
}
else
mrStrm >> rnValue;
mnRawRecLeft -= 4;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( float& rfValue )
{
if( EnsureRawReadSize( 4 ) )
{
if( mbUseDecr )
{
SVBT32 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 4 );
sal_uInt32 nValue = SVBT32ToUInt32( pnBuffer );
memcpy( &rfValue, &nValue, 4 );
}
else
mrStrm >> rfValue;
mnRawRecLeft -= 4;
}
return *this;
}
XclImpStream& XclImpStream::operator>>( double& rfValue )
{
if( EnsureRawReadSize( 8 ) )
{
if( mbUseDecr )
{
SVBT64 pnBuffer;
mxDecrypter->Read( mrStrm, pnBuffer, 8 );
rfValue = SVBT64ToDouble( pnBuffer );
}
else
mrStrm >> rfValue;
mnRawRecLeft -= 8;
}
return *this;
}
sal_Int8 XclImpStream::ReadInt8()
{
sal_Int8 nValue(0);
operator>>( nValue );
return nValue;
}
sal_uInt8 XclImpStream::ReaduInt8()
{
sal_uInt8 nValue(0);
operator>>( nValue );
return nValue;
}
sal_Int16 XclImpStream::ReadInt16()
{
sal_Int16 nValue(0);
operator>>( nValue );
return nValue;
}
sal_uInt16 XclImpStream::ReaduInt16()
{
sal_uInt16 nValue(0);
operator>>( nValue );
return nValue;
}
sal_Int32 XclImpStream::ReadInt32()
{
sal_Int32 nValue(0);
operator>>( nValue );
return nValue;
}
sal_uInt32 XclImpStream::ReaduInt32()
{
sal_uInt32 nValue(0);
operator>>( nValue );
return nValue;
}
float XclImpStream::ReadFloat()
{
float fValue(0.0);
operator>>( fValue );
return fValue;
}
double XclImpStream::ReadDouble()
{
double fValue(0.0);
operator>>( fValue );
return fValue;
}
sal_Size XclImpStream::Read( void* pData, sal_Size nBytes )
{
sal_Size nRet = 0;
if( mbValid && pData && (nBytes > 0) )
{
sal_uInt8* pnBuffer = reinterpret_cast< sal_uInt8* >( pData );
sal_Size nBytesLeft = nBytes;
while( mbValid && (nBytesLeft > 0) )
{
sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
sal_uInt16 nReadRet = ReadRawData( pnBuffer, nReadSize );
nRet += nReadRet;
mbValid = (nReadSize == nReadRet);
DBG_ASSERT( mbValid, "XclImpStream::Read - stream read error" );
pnBuffer += nReadRet;
nBytesLeft -= nReadRet;
if( mbValid && (nBytesLeft > 0) )
JumpToNextContinue();
DBG_ASSERT( mbValid, "XclImpStream::Read - record overread" );
}
}
return nRet;
}
sal_Size XclImpStream::CopyToStream( SvStream& rOutStrm, sal_Size nBytes )
{
sal_Size nRet = 0;
if( mbValid && (nBytes > 0) )
{
const sal_Size nMaxBuffer = 4096;
sal_uInt8* pnBuffer = new sal_uInt8[ ::std::min( nBytes, nMaxBuffer ) ];
sal_Size nBytesLeft = nBytes;
while( mbValid && (nBytesLeft > 0) )
{
sal_Size nReadSize = ::std::min( nBytesLeft, nMaxBuffer );
nRet += Read( pnBuffer, nReadSize );
rOutStrm.Write( pnBuffer, nReadSize );
nBytesLeft -= nReadSize;
}
delete[] pnBuffer;
}
return nRet;
}
sal_Size XclImpStream::CopyRecordToStream( SvStream& rOutStrm )
{
sal_Size nRet = 0;
if( mbValidRec )
{
PushPosition();
RestorePosition( maFirstRec );
nRet = CopyToStream( rOutStrm, GetRecSize() );
PopPosition();
}
return nRet;
}
void XclImpStream::Seek( sal_Size nPos )
{
if( mbValidRec )
{
sal_Size nCurrPos = GetRecPos();
if( !mbValid || (nPos < nCurrPos) ) // from invalid state or backward
{
RestorePosition( maFirstRec );
Ignore( nPos );
}
else if( nPos > nCurrPos ) // forward
{
Ignore( nPos - nCurrPos );
}
}
}
void XclImpStream::Ignore( sal_Size nBytes )
{
// implementation similar to Read(), but without really reading anything
sal_Size nBytesLeft = nBytes;
while( mbValid && (nBytesLeft > 0) )
{
sal_uInt16 nReadSize = GetMaxRawReadSize( nBytesLeft );
mrStrm.SeekRel( nReadSize );
mnRawRecLeft = mnRawRecLeft - nReadSize;
nBytesLeft -= nReadSize;
if( nBytesLeft > 0 )
JumpToNextContinue();
DBG_ASSERT( mbValid, "XclImpStream::Ignore - record overread" );
}
}
// ----------------------------------------------------------------------------
sal_Size XclImpStream::ReadUniStringExtHeader(
bool& rb16Bit, bool& rbRich, bool& rbFareast,
sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags )
{
DBG_ASSERT( !::get_flag( nFlags, EXC_STRF_UNKNOWN ), "XclImpStream::ReadUniStringExt - unknown flags" );
rb16Bit = ::get_flag( nFlags, EXC_STRF_16BIT );
rbRich = ::get_flag( nFlags, EXC_STRF_RICH );
rbFareast = ::get_flag( nFlags, EXC_STRF_FAREAST );
rnFormatRuns = rbRich ? ReaduInt16() : 0;
rnExtInf = rbFareast ? ReaduInt32() : 0;
return rnExtInf + 4 * rnFormatRuns;
}
sal_Size XclImpStream::ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags )
{
bool bRich, bFareast;
sal_uInt16 nCrun;
sal_uInt32 nExtInf;
return ReadUniStringExtHeader( rb16Bit, bRich, bFareast, nCrun, nExtInf, nFlags );
}
// ----------------------------------------------------------------------------
String XclImpStream::ReadRawUniString( sal_uInt16 nChars, bool b16Bit )
{
String aRet;
sal_uInt16 nCharsLeft = nChars;
sal_uInt16 nReadSize;
sal_Unicode* pcBuffer = new sal_Unicode[ nCharsLeft + 1 ];
while( IsValid() && (nCharsLeft > 0) )
{
if( b16Bit )
{
nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
DBG_ASSERT( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
"XclImpStream::ReadRawUniString - missing a byte" );
}
else
nReadSize = GetMaxRawReadSize( nCharsLeft );
sal_Unicode* pcUniChar = pcBuffer;
sal_Unicode* pcEndChar = pcBuffer + nReadSize;
if( b16Bit )
{
sal_uInt16 nReadChar;
for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
{
operator>>( nReadChar );
(*pcUniChar) = (nReadChar == EXC_NUL) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
}
}
else
{
sal_uInt8 nReadChar;
for( ; IsValid() && (pcUniChar < pcEndChar); ++pcUniChar )
{
operator>>( nReadChar );
(*pcUniChar) = (nReadChar == EXC_NUL_C) ? mcNulSubst : static_cast< sal_Unicode >( nReadChar );
}
}
*pcEndChar = '\0';
aRet.Append( pcBuffer );
nCharsLeft = nCharsLeft - nReadSize;
if( nCharsLeft > 0 )
JumpToNextStringContinue( b16Bit );
}
delete[] pcBuffer;
return aRet;
}
String XclImpStream::ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
{
bool b16Bit;
sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
String aRet( ReadRawUniString( nChars, b16Bit ) );
Ignore( nExtSize );
return aRet;
}
String XclImpStream::ReadUniString( sal_uInt16 nChars )
{
return ReadUniString( nChars, ReaduInt8() );
}
String XclImpStream::ReadUniString()
{
return ReadUniString( ReaduInt16() );
}
void XclImpStream::IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit )
{
sal_uInt16 nCharsLeft = nChars;
sal_uInt16 nReadSize;
while( IsValid() && (nCharsLeft > 0) )
{
if( b16Bit )
{
nReadSize = ::std::min< sal_uInt16 >( nCharsLeft, mnRawRecLeft / 2 );
DBG_ASSERT( (nReadSize <= nCharsLeft) || !(mnRawRecLeft & 0x1),
"XclImpStream::IgnoreRawUniString - missing a byte" );
Ignore( nReadSize * 2 );
}
else
{
nReadSize = GetMaxRawReadSize( nCharsLeft );
Ignore( nReadSize );
}
nCharsLeft = nCharsLeft - nReadSize;
if( nCharsLeft > 0 )
JumpToNextStringContinue( b16Bit );
}
}
void XclImpStream::IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags )
{
bool b16Bit;
sal_Size nExtSize = ReadUniStringExtHeader( b16Bit, nFlags );
IgnoreRawUniString( nChars, b16Bit );
Ignore( nExtSize );
}
void XclImpStream::IgnoreUniString( sal_uInt16 nChars )
{
IgnoreUniString( nChars, ReaduInt8() );
}
void XclImpStream::IgnoreUniString()
{
IgnoreUniString( ReaduInt16() );
}
// ----------------------------------------------------------------------------
String XclImpStream::ReadRawByteString( sal_uInt16 nChars )
{
sal_Char* pcBuffer = new sal_Char[ nChars + 1 ];
sal_uInt16 nCharsRead = ReadRawData( pcBuffer, nChars );
pcBuffer[ nCharsRead ] = '\0';
String aRet( pcBuffer, mrRoot.GetTextEncoding() );
delete[] pcBuffer;
return aRet;
}
String XclImpStream::ReadByteString( bool b16BitLen )
{
return ReadRawByteString( ReadByteStrLen( b16BitLen ) );
}
// private --------------------------------------------------------------------
void XclImpStream::StorePosition( XclImpStreamPos& rPos )
{
rPos.Set( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
}
void XclImpStream::RestorePosition( const XclImpStreamPos& rPos )
{
rPos.Get( mrStrm, mnNextRecPos, mnCurrRecSize, mnRawRecId, mnRawRecSize, mnRawRecLeft, mbValid );
SetupDecrypter();
}
bool XclImpStream::ReadNextRawRecHeader()
{
mrStrm.Seek( mnNextRecPos );
bool bRet = mnNextRecPos + 4 <= mnStreamSize;
if( bRet )
mrStrm >> mnRawRecId >> mnRawRecSize;
return bRet;
}
void XclImpStream::SetupDecrypter()
{
if( mxDecrypter.is() )
mxDecrypter->Update( mrStrm, mnRawRecSize );
}
void XclImpStream::SetupRawRecord()
{
// pre: mnRawRecSize contains current raw record size
// pre: mrStrm points to start of raw record data
mnNextRecPos = mrStrm.Tell() + mnRawRecSize;
mnRawRecLeft = mnRawRecSize;
mnCurrRecSize += mnRawRecSize;
SetupDecrypter(); // decrypter works on raw record level
}
void XclImpStream::SetupRecord()
{
mnRecId = mnRawRecId;
mnAltContId = EXC_ID_UNKNOWN;
mnCurrRecSize = 0;
mnComplRecSize = mnRawRecSize;
mbHasComplRec = !mbCont;
SetupRawRecord();
SetNulSubstChar();
EnableDecryption();
StorePosition( maFirstRec );
}
bool XclImpStream::IsContinueId( sal_uInt16 nRecId ) const
{
return (nRecId == EXC_ID_CONT) || (nRecId == mnAltContId);
}
bool XclImpStream::JumpToNextContinue()
{
mbValid = mbValid && mbCont && ReadNextRawRecHeader() && IsContinueId( mnRawRecId );
if( mbValid ) // do not setup a following non-CONTINUE record
SetupRawRecord();
return mbValid;
}
bool XclImpStream::JumpToNextStringContinue( bool& rb16Bit )
{
DBG_ASSERT( mnRawRecLeft == 0, "XclImpStream::JumpToNextStringContinue - unexpected garbage" );
if( mbCont && (GetRecLeft() > 0) )
{
JumpToNextContinue();
}
else if( mnRecId == EXC_ID_CONT )
{
// CONTINUE handling is off, but we have started reading in a CONTINUE record
// -> start next CONTINUE for TXO import
mbValidRec = ReadNextRawRecHeader() && ((mnRawRecId != 0) || (mnRawRecSize > 0));
mbValid = mbValidRec && (mnRawRecId == EXC_ID_CONT);
// we really start a new record here - no chance to return to string origin
if( mbValid )
SetupRecord();
}
else
mbValid = false;
if( mbValid )
rb16Bit = ::get_flag( ReaduInt8(), EXC_STRF_16BIT );
return mbValid;
}
bool XclImpStream::EnsureRawReadSize( sal_uInt16 nBytes )
{
if( mbValid && nBytes )
{
while( mbValid && !mnRawRecLeft ) JumpToNextContinue();
mbValid = mbValid && (nBytes <= mnRawRecLeft);
DBG_ASSERT( mbValid, "XclImpStream::EnsureRawReadSize - record overread" );
}
return mbValid;
}
sal_uInt16 XclImpStream::GetMaxRawReadSize( sal_Size nBytes ) const
{
return static_cast< sal_uInt16 >( ::std::min< sal_Size >( nBytes, mnRawRecLeft ) );
}
sal_uInt16 XclImpStream::ReadRawData( void* pData, sal_uInt16 nBytes )
{
DBG_ASSERT( (nBytes <= mnRawRecLeft), "XclImpStream::ReadRawData - record overread" );
sal_uInt16 nRet = 0;
if( mbUseDecr )
nRet = mxDecrypter->Read( mrStrm, pData, nBytes );
else
nRet = static_cast< sal_uInt16 >( mrStrm.Read( pData, nBytes ) );
mnRawRecLeft = mnRawRecLeft - nRet;
return nRet;
}
// ============================================================================