xref: /aoo41x/main/oox/source/ole/vbainputstream.cxx (revision cdf0e10c)
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