1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: vbainputstream.cxx,v $
10 * $Revision: 1.1.2.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/ole/vbainputstream.hxx"
32 #include <osl/diagnose.h>
39 const sal_uInt8 VBASTREAM_SIGNATURE
= 1;
41 const sal_uInt16 VBACHUNK_SIGMASK
= 0x7000;
42 const sal_uInt16 VBACHUNK_SIG
= 0x3000;
43 const sal_uInt16 VBACHUNK_COMPRESSED
= 0x8000;
44 const sal_uInt16 VBACHUNK_LENMASK
= 0x0FFF;
48 // ============================================================================
50 VbaInputStream::VbaInputStream( BinaryInputStream
& rInStrm
) :
54 maChunk
.reserve( 4096 );
56 sal_uInt8 nSig
= mrInStrm
.readuInt8();
57 OSL_ENSURE( nSig
== VBASTREAM_SIGNATURE
, "VbaInputStream::VbaInputStream - wrong signature" );
58 mbEof
= nSig
!= VBASTREAM_SIGNATURE
;
61 sal_Int32
VbaInputStream::readData( StreamDataSequence
& orData
, sal_Int32 nBytes
)
66 orData
.realloc( ::std::max
< sal_Int32
>( nBytes
, 0 ) );
69 nRet
= readMemory( orData
.getArray(), nBytes
);
71 orData
.realloc( nRet
);
77 sal_Int32
VbaInputStream::readMemory( void* opMem
, sal_Int32 nBytes
)
80 sal_uInt8
* opnMem
= reinterpret_cast< sal_uInt8
* >( opMem
);
81 while( (nBytes
> 0) && updateChunk() )
83 sal_Int32 nChunkLeft
= static_cast< sal_Int32
>( maChunk
.size() - mnChunkPos
);
84 sal_Int32 nReadBytes
= ::std::min( nBytes
, nChunkLeft
);
85 memcpy( opnMem
, &*(maChunk
.begin() + mnChunkPos
), nReadBytes
);
87 mnChunkPos
+= static_cast< size_t >( nReadBytes
);
94 void VbaInputStream::skip( sal_Int32 nBytes
)
96 while( (nBytes
> 0) && updateChunk() )
98 sal_Int32 nChunkLeft
= static_cast< sal_Int32
>( maChunk
.size() - mnChunkPos
);
99 sal_Int32 nSkipBytes
= ::std::min( nBytes
, nChunkLeft
);
100 mnChunkPos
+= static_cast< size_t >( nSkipBytes
);
101 nBytes
-= nSkipBytes
;
105 // private --------------------------------------------------------------------
107 bool VbaInputStream::updateChunk()
109 if( mbEof
|| (mnChunkPos
< maChunk
.size()) ) return !mbEof
;
111 // try to read next chunk header, this may trigger EOF
112 sal_uInt16 nHeader
= mrInStrm
.readuInt16();
113 mbEof
= mrInStrm
.isEof();
114 if( mbEof
) return false;
116 // check header signature
117 OSL_ENSURE( (nHeader
& VBACHUNK_SIGMASK
) == VBACHUNK_SIG
, "VbaInputStream::updateChunk - invalid chunk signature" );
118 mbEof
= (nHeader
& VBACHUNK_SIGMASK
) != VBACHUNK_SIG
;
119 if( mbEof
) return false;
121 // decode length of chunk data and compression flag
122 bool bCompressed
= getFlag( nHeader
, VBACHUNK_COMPRESSED
);
123 sal_uInt16 nChunkLen
= (nHeader
& VBACHUNK_LENMASK
) + 1;
124 OSL_ENSURE( bCompressed
|| (nChunkLen
== 4096), "VbaInputStream::updateChunk - invalid uncompressed chunk size" );
128 sal_uInt8 nBitCount
= 4;
129 sal_uInt16 nChunkPos
= 0;
130 while( !mbEof
&& !mrInStrm
.isEof() && (nChunkPos
< nChunkLen
) )
132 sal_uInt8 nTokenFlags
= mrInStrm
.readuInt8();
134 for( int nBit
= 0; !mbEof
&& !mrInStrm
.isEof() && (nBit
< 8) && (nChunkPos
< nChunkLen
); ++nBit
, nTokenFlags
>>= 1 )
136 if( nTokenFlags
& 1 )
138 sal_uInt16 nCopyToken
= mrInStrm
.readuInt16();
139 nChunkPos
= nChunkPos
+ 2;
140 // update bit count used for offset/length in the token
141 while( static_cast< size_t >( 1 << nBitCount
) < maChunk
.size() ) ++nBitCount
;
142 // extract length from lower (16-nBitCount) bits, plus 3
143 sal_uInt16 nLength
= extractValue
< sal_uInt16
>( nCopyToken
, 0, 16 - nBitCount
) + 3;
144 // extract offset from high nBitCount bits, plus 1
145 sal_uInt16 nOffset
= extractValue
< sal_uInt16
>( nCopyToken
, 16 - nBitCount
, nBitCount
) + 1;
146 mbEof
= (nOffset
> maChunk
.size()) || (maChunk
.size() + nLength
> 4096);
147 OSL_ENSURE( !mbEof
, "VbaInputStream::updateChunk - invalid offset or size in copy token" );
150 // append data to buffer
151 maChunk
.resize( maChunk
.size() + nLength
);
152 sal_uInt8
* pnTo
= &*(maChunk
.end() - nLength
);
153 const sal_uInt8
* pnEnd
= pnTo
+ nLength
;
154 const sal_uInt8
* pnFrom
= pnTo
- nOffset
;
155 // offset may be less than length, effectively duplicating source data several times
156 size_t nRunLen
= ::std::min
< size_t >( nLength
, nOffset
);
157 while( pnTo
< pnEnd
)
159 size_t nStepLen
= ::std::min
< size_t >( nRunLen
, pnEnd
- pnTo
);
160 memcpy( pnTo
, pnFrom
, nStepLen
);
167 maChunk
.resize( maChunk
.size() + 1 );
168 mrInStrm
>> maChunk
.back();
176 maChunk
.resize( nChunkLen
);
177 mrInStrm
.readMemory( &maChunk
.front(), nChunkLen
);
184 // ============================================================================