xref: /trunk/main/oox/source/ole/vbainputstream.cxx (revision ca5ec200)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include "oox/ole/vbainputstream.hxx"
25 #include <osl/diagnose.h>
26 
27 namespace oox {
28 namespace ole {
29 
30 // ============================================================================
31 
32 namespace {
33 
34 const sal_uInt8 VBASTREAM_SIGNATURE         = 1;
35 
36 const sal_uInt16 VBACHUNK_SIGMASK           = 0x7000;
37 const sal_uInt16 VBACHUNK_SIG               = 0x3000;
38 const sal_uInt16 VBACHUNK_COMPRESSED        = 0x8000;
39 const sal_uInt16 VBACHUNK_LENMASK           = 0x0FFF;
40 
41 } // namespace
42 
43 // ============================================================================
44 
VbaInputStream(BinaryInputStream & rInStrm)45 VbaInputStream::VbaInputStream( BinaryInputStream& rInStrm ) :
46     BinaryStreamBase( false ),
47     mpInStrm( &rInStrm ),
48     mnChunkPos( 0 )
49 {
50     maChunk.reserve( 4096 );
51 
52     sal_uInt8 nSig = rInStrm.readuInt8();
53     OSL_ENSURE( nSig == VBASTREAM_SIGNATURE, "VbaInputStream::VbaInputStream - wrong signature" );
54     mbEof = mbEof || rInStrm.isEof() || (nSig != VBASTREAM_SIGNATURE);
55 }
56 
size() const57 sal_Int64 VbaInputStream::size() const
58 {
59     return -1;
60 }
61 
tell() const62 sal_Int64 VbaInputStream::tell() const
63 {
64     return -1;
65 }
66 
seek(sal_Int64)67 void VbaInputStream::seek( sal_Int64 )
68 {
69 }
70 
close()71 void VbaInputStream::close()
72 {
73     mpInStrm = 0;
74     mbEof = true;
75 }
76 
readData(StreamDataSequence & orData,sal_Int32 nBytes,size_t nAtomSize)77 sal_Int32 VbaInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
78 {
79     sal_Int32 nRet = 0;
80     if( !mbEof )
81     {
82         orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
83         if( nBytes > 0 )
84         {
85             nRet = readMemory( orData.getArray(), nBytes, nAtomSize );
86             if( nRet < nBytes )
87                 orData.realloc( nRet );
88         }
89     }
90     return nRet;
91 }
92 
readMemory(void * opMem,sal_Int32 nBytes,size_t)93 sal_Int32 VbaInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t /*nAtomSize*/ )
94 {
95     sal_Int32 nRet = 0;
96     sal_uInt8* opnMem = reinterpret_cast< sal_uInt8* >( opMem );
97     while( (nBytes > 0) && updateChunk() )
98     {
99         sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos );
100         sal_Int32 nReadBytes = ::std::min( nBytes, nChunkLeft );
101         memcpy( opnMem, &*(maChunk.begin() + mnChunkPos), nReadBytes );
102         opnMem += nReadBytes;
103         mnChunkPos += static_cast< size_t >( nReadBytes );
104         nBytes -= nReadBytes;
105         nRet += nReadBytes;
106     }
107     return nRet;
108 }
109 
skip(sal_Int32 nBytes,size_t)110 void VbaInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
111 {
112     while( (nBytes > 0) && updateChunk() )
113     {
114         sal_Int32 nChunkLeft = static_cast< sal_Int32 >( maChunk.size() - mnChunkPos );
115         sal_Int32 nSkipBytes = ::std::min( nBytes, nChunkLeft );
116         mnChunkPos += static_cast< size_t >( nSkipBytes );
117         nBytes -= nSkipBytes;
118     }
119 }
120 
121 // private --------------------------------------------------------------------
122 
updateChunk()123 bool VbaInputStream::updateChunk()
124 {
125     if( mbEof || (mnChunkPos < maChunk.size()) ) return !mbEof;
126 
127     // try to read next chunk header, this may trigger EOF
128     sal_uInt16 nHeader = mpInStrm->readuInt16();
129     mbEof = mpInStrm->isEof();
130     if( mbEof ) return false;
131 
132     // check header signature
133     OSL_ENSURE( (nHeader & VBACHUNK_SIGMASK) == VBACHUNK_SIG, "VbaInputStream::updateChunk - invalid chunk signature" );
134     mbEof = (nHeader & VBACHUNK_SIGMASK) != VBACHUNK_SIG;
135     if( mbEof ) return false;
136 
137     // decode length of chunk data and compression flag
138     bool bCompressed = getFlag( nHeader, VBACHUNK_COMPRESSED );
139     sal_uInt16 nChunkLen = (nHeader & VBACHUNK_LENMASK) + 1;
140     OSL_ENSURE( bCompressed || (nChunkLen == 4096), "VbaInputStream::updateChunk - invalid uncompressed chunk size" );
141     if( bCompressed )
142     {
143         maChunk.clear();
144         sal_uInt8 nBitCount = 4;
145         sal_uInt16 nChunkPos = 0;
146         while( !mbEof && !mpInStrm->isEof() && (nChunkPos < nChunkLen) )
147         {
148             sal_uInt8 nTokenFlags = mpInStrm->readuInt8();
149             ++nChunkPos;
150             for( int nBit = 0; !mbEof && !mpInStrm->isEof() && (nBit < 8) && (nChunkPos < nChunkLen); ++nBit, nTokenFlags >>= 1 )
151             {
152                 if( nTokenFlags & 1 )
153                 {
154                     sal_uInt16 nCopyToken = mpInStrm->readuInt16();
155                     nChunkPos = nChunkPos + 2;
156                     // update bit count used for offset/length in the token
157                     while( static_cast< size_t >( 1 << nBitCount ) < maChunk.size() ) ++nBitCount;
158                     // extract length from lower (16-nBitCount) bits, plus 3
159                     sal_uInt16 nLength = extractValue< sal_uInt16 >( nCopyToken, 0, 16 - nBitCount ) + 3;
160                     // extract offset from high nBitCount bits, plus 1
161                     sal_uInt16 nOffset = extractValue< sal_uInt16 >( nCopyToken, 16 - nBitCount, nBitCount ) + 1;
162                     mbEof = (nOffset > maChunk.size()) || (maChunk.size() + nLength > 4096);
163                     OSL_ENSURE( !mbEof, "VbaInputStream::updateChunk - invalid offset or size in copy token" );
164                     if( !mbEof )
165                     {
166                         // append data to buffer
167                         maChunk.resize( maChunk.size() + nLength );
168                         sal_uInt8* pnTo = &*(maChunk.end() - nLength);
169                         const sal_uInt8* pnEnd = pnTo + nLength;
170                         const sal_uInt8* pnFrom = pnTo - nOffset;
171                         // offset may be less than length, effectively duplicating source data several times
172                         size_t nRunLen = ::std::min< size_t >( nLength, nOffset );
173                         while( pnTo < pnEnd )
174                         {
175                             size_t nStepLen = ::std::min< size_t >( nRunLen, pnEnd - pnTo );
176                             memcpy( pnTo, pnFrom, nStepLen );
177                             pnTo += nStepLen;
178                         }
179                     }
180                 }
181                 else
182                 {
183                     maChunk.resize( maChunk.size() + 1 );
184                     *mpInStrm >> maChunk.back();
185                     ++nChunkPos;
186                 }
187             }
188         }
189     }
190     else
191     {
192         maChunk.resize( nChunkLen );
193         mpInStrm->readMemory( &maChunk.front(), nChunkLen );
194     }
195 
196     mnChunkPos = 0;
197     return !mbEof;
198 }
199 
200 // ============================================================================
201 
202 } // namespace ole
203 } // namespace oox
204 
205