/************************************************************** * * 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_scfilt.hxx" #include #include #include "xistream.hxx" #include "xlstring.hxx" #include "xiroot.hxx" #include 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; } // ============================================================================