1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/ole/vbainputstream.hxx" 29 #include <osl/diagnose.h> 30 31 namespace oox { 32 namespace ole { 33 34 // ============================================================================ 35 36 namespace { 37 38 const sal_uInt8 VBASTREAM_SIGNATURE = 1; 39 40 const sal_uInt16 VBACHUNK_SIGMASK = 0x7000; 41 const sal_uInt16 VBACHUNK_SIG = 0x3000; 42 const sal_uInt16 VBACHUNK_COMPRESSED = 0x8000; 43 const sal_uInt16 VBACHUNK_LENMASK = 0x0FFF; 44 45 } // namespace 46 47 // ============================================================================ 48 49 VbaInputStream::VbaInputStream( BinaryInputStream& rInStrm ) : 50 BinaryStreamBase( false ), 51 mpInStrm( &rInStrm ), 52 mnChunkPos( 0 ) 53 { 54 maChunk.reserve( 4096 ); 55 56 sal_uInt8 nSig = rInStrm.readuInt8(); 57 OSL_ENSURE( nSig == VBASTREAM_SIGNATURE, "VbaInputStream::VbaInputStream - wrong signature" ); 58 mbEof = mbEof || rInStrm.isEof() || (nSig != VBASTREAM_SIGNATURE); 59 } 60 61 sal_Int64 VbaInputStream::size() const 62 { 63 return -1; 64 } 65 66 sal_Int64 VbaInputStream::tell() const 67 { 68 return -1; 69 } 70 71 void VbaInputStream::seek( sal_Int64 ) 72 { 73 } 74 75 void VbaInputStream::close() 76 { 77 mpInStrm = 0; 78 mbEof = true; 79 } 80 81 sal_Int32 VbaInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize ) 82 { 83 sal_Int32 nRet = 0; 84 if( !mbEof ) 85 { 86 orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) ); 87 if( nBytes > 0 ) 88 { 89 nRet = readMemory( orData.getArray(), nBytes, nAtomSize ); 90 if( nRet < nBytes ) 91 orData.realloc( nRet ); 92 } 93 } 94 return nRet; 95 } 96 97 sal_Int32 VbaInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t /*nAtomSize*/ ) 98 { 99 sal_Int32 nRet = 0; 100 sal_uInt8* opnMem = reinterpret_cast< sal_uInt8* >( opMem ); 101 while( (nBytes > 0) && updateChunk() ) 102 { 103 sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos ); 104 sal_Int32 nReadBytes = ::std::min( nBytes, nChunkLeft ); 105 memcpy( opnMem, &*(maChunk.begin() + mnChunkPos), nReadBytes ); 106 opnMem += nReadBytes; 107 mnChunkPos += static_cast< size_t >( nReadBytes ); 108 nBytes -= nReadBytes; 109 nRet += nReadBytes; 110 } 111 return nRet; 112 } 113 114 void VbaInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ ) 115 { 116 while( (nBytes > 0) && updateChunk() ) 117 { 118 sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos ); 119 sal_Int32 nSkipBytes = ::std::min( nBytes, nChunkLeft ); 120 mnChunkPos += static_cast< size_t >( nSkipBytes ); 121 nBytes -= nSkipBytes; 122 } 123 } 124 125 // private -------------------------------------------------------------------- 126 127 bool VbaInputStream::updateChunk() 128 { 129 if( mbEof || (mnChunkPos < maChunk.size()) ) return !mbEof; 130 131 // try to read next chunk header, this may trigger EOF 132 sal_uInt16 nHeader = mpInStrm->readuInt16(); 133 mbEof = mpInStrm->isEof(); 134 if( mbEof ) return false; 135 136 // check header signature 137 OSL_ENSURE( (nHeader & VBACHUNK_SIGMASK) == VBACHUNK_SIG, "VbaInputStream::updateChunk - invalid chunk signature" ); 138 mbEof = (nHeader & VBACHUNK_SIGMASK) != VBACHUNK_SIG; 139 if( mbEof ) return false; 140 141 // decode length of chunk data and compression flag 142 bool bCompressed = getFlag( nHeader, VBACHUNK_COMPRESSED ); 143 sal_uInt16 nChunkLen = (nHeader & VBACHUNK_LENMASK) + 1; 144 OSL_ENSURE( bCompressed || (nChunkLen == 4096), "VbaInputStream::updateChunk - invalid uncompressed chunk size" ); 145 if( bCompressed ) 146 { 147 maChunk.clear(); 148 sal_uInt8 nBitCount = 4; 149 sal_uInt16 nChunkPos = 0; 150 while( !mbEof && !mpInStrm->isEof() && (nChunkPos < nChunkLen) ) 151 { 152 sal_uInt8 nTokenFlags = mpInStrm->readuInt8(); 153 ++nChunkPos; 154 for( int nBit = 0; !mbEof && !mpInStrm->isEof() && (nBit < 8) && (nChunkPos < nChunkLen); ++nBit, nTokenFlags >>= 1 ) 155 { 156 if( nTokenFlags & 1 ) 157 { 158 sal_uInt16 nCopyToken = mpInStrm->readuInt16(); 159 nChunkPos = nChunkPos + 2; 160 // update bit count used for offset/length in the token 161 while( static_cast< size_t >( 1 << nBitCount ) < maChunk.size() ) ++nBitCount; 162 // extract length from lower (16-nBitCount) bits, plus 3 163 sal_uInt16 nLength = extractValue< sal_uInt16 >( nCopyToken, 0, 16 - nBitCount ) + 3; 164 // extract offset from high nBitCount bits, plus 1 165 sal_uInt16 nOffset = extractValue< sal_uInt16 >( nCopyToken, 16 - nBitCount, nBitCount ) + 1; 166 mbEof = (nOffset > maChunk.size()) || (maChunk.size() + nLength > 4096); 167 OSL_ENSURE( !mbEof, "VbaInputStream::updateChunk - invalid offset or size in copy token" ); 168 if( !mbEof ) 169 { 170 // append data to buffer 171 maChunk.resize( maChunk.size() + nLength ); 172 sal_uInt8* pnTo = &*(maChunk.end() - nLength); 173 const sal_uInt8* pnEnd = pnTo + nLength; 174 const sal_uInt8* pnFrom = pnTo - nOffset; 175 // offset may be less than length, effectively duplicating source data several times 176 size_t nRunLen = ::std::min< size_t >( nLength, nOffset ); 177 while( pnTo < pnEnd ) 178 { 179 size_t nStepLen = ::std::min< size_t >( nRunLen, pnEnd - pnTo ); 180 memcpy( pnTo, pnFrom, nStepLen ); 181 pnTo += nStepLen; 182 } 183 } 184 } 185 else 186 { 187 maChunk.resize( maChunk.size() + 1 ); 188 *mpInStrm >> maChunk.back(); 189 ++nChunkPos; 190 } 191 } 192 } 193 } 194 else 195 { 196 maChunk.resize( nChunkLen ); 197 mpInStrm->readMemory( &maChunk.front(), nChunkLen ); 198 } 199 200 mnChunkPos = 0; 201 return !mbEof; 202 } 203 204 // ============================================================================ 205 206 } // namespace ole 207 } // namespace oox 208 209