Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "oox/ole/axbinaryreader.hxx"
21 :
22 : #include "oox/ole/olehelper.hxx"
23 :
24 : namespace oox {
25 : namespace ole {
26 :
27 : // ============================================================================
28 :
29 : using ::rtl::OUString;
30 :
31 : // ============================================================================
32 :
33 : namespace {
34 :
35 : const sal_uInt32 AX_STRING_SIZEMASK = 0x7FFFFFFF;
36 : const sal_uInt32 AX_STRING_COMPRESSED = 0x80000000;
37 :
38 : } // namespace
39 :
40 : // ============================================================================
41 :
42 20 : AxAlignedInputStream::AxAlignedInputStream( BinaryInputStream& rInStrm ) :
43 : BinaryStreamBase( false ),
44 : mpInStrm( &rInStrm ),
45 : mnStrmPos( 0 ),
46 20 : mnStrmSize( rInStrm.getRemaining() )
47 : {
48 20 : mbEof = mbEof || rInStrm.isEof();
49 20 : }
50 :
51 0 : sal_Int64 AxAlignedInputStream::size() const
52 : {
53 0 : return mpInStrm ? mnStrmSize : -1;
54 : }
55 :
56 38 : sal_Int64 AxAlignedInputStream::tell() const
57 : {
58 38 : return mpInStrm ? mnStrmPos : -1;
59 : }
60 :
61 38 : void AxAlignedInputStream::seek( sal_Int64 nPos )
62 : {
63 38 : mbEof = mbEof || (nPos < mnStrmPos);
64 38 : if( !mbEof )
65 38 : skip( static_cast< sal_Int32 >( nPos - mnStrmPos ) );
66 38 : }
67 :
68 0 : void AxAlignedInputStream::close()
69 : {
70 0 : mpInStrm = 0;
71 0 : mbEof = true;
72 0 : }
73 :
74 0 : sal_Int32 AxAlignedInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
75 : {
76 0 : sal_Int32 nReadSize = 0;
77 0 : if( !mbEof )
78 : {
79 0 : nReadSize = mpInStrm->readData( orData, nBytes, nAtomSize );
80 0 : mnStrmPos += nReadSize;
81 0 : mbEof = mpInStrm->isEof();
82 : }
83 0 : return nReadSize;
84 : }
85 :
86 146 : sal_Int32 AxAlignedInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
87 : {
88 146 : sal_Int32 nReadSize = 0;
89 146 : if( !mbEof )
90 : {
91 146 : nReadSize = mpInStrm->readMemory( opMem, nBytes, nAtomSize );
92 146 : mnStrmPos += nReadSize;
93 146 : mbEof = mpInStrm->isEof();
94 : }
95 146 : return nReadSize;
96 : }
97 :
98 206 : void AxAlignedInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
99 : {
100 206 : if( !mbEof )
101 : {
102 206 : mpInStrm->skip( nBytes, nAtomSize );
103 206 : mnStrmPos += nBytes;
104 206 : mbEof = mpInStrm->isEof();
105 : }
106 206 : }
107 :
108 134 : void AxAlignedInputStream::align( size_t nSize )
109 : {
110 134 : skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
111 134 : }
112 :
113 : // ============================================================================
114 :
115 : namespace {
116 :
117 18 : bool lclReadString( AxAlignedInputStream& rInStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString )
118 : {
119 18 : bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED );
120 18 : sal_uInt32 nBufSize = nSize & AX_STRING_SIZEMASK;
121 : // Unicode: simple strings store byte count, array strings store char count
122 18 : sal_Int32 nChars = static_cast< sal_Int32 >( nBufSize / ((bCompressed || bArrayString) ? 1 : 2) );
123 18 : bool bValidChars = nChars <= 65536;
124 : OSL_ENSURE( bValidChars, "lclReadString - string too long" );
125 18 : sal_Int64 nEndPos = rInStrm.tell() + nChars * (bCompressed ? 1 : 2);
126 18 : nChars = ::std::min< sal_Int32 >( nChars, 65536 );
127 18 : rValue = rInStrm.readCompressedUnicodeArray( nChars, bCompressed );
128 18 : rInStrm.seek( nEndPos );
129 18 : return bValidChars;
130 : }
131 :
132 : } // namespace
133 :
134 : // ----------------------------------------------------------------------------
135 :
136 28 : AxBinaryPropertyReader::ComplexProperty::~ComplexProperty()
137 : {
138 28 : }
139 :
140 10 : bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm )
141 : {
142 10 : rInStrm >> mrPairData.first >> mrPairData.second;
143 10 : return true;
144 : }
145 :
146 18 : bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm )
147 : {
148 18 : return lclReadString( rInStrm, mrValue, mnSize, false );
149 : }
150 :
151 0 : bool AxBinaryPropertyReader::StringArrayProperty::readProperty( AxAlignedInputStream& rInStrm )
152 : {
153 0 : sal_Int64 nEndPos = rInStrm.tell() + mnSize;
154 0 : while( rInStrm.tell() < nEndPos )
155 : {
156 0 : OUString aString;
157 0 : if( !lclReadString( rInStrm, aString, rInStrm.readuInt32(), true ) )
158 0 : return false;
159 0 : mrArray.push_back( aString );
160 : // every array string is aligned on 4 byte boundries
161 0 : rInStrm.align( 4 );
162 0 : }
163 0 : return true;
164 : }
165 :
166 0 : bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm )
167 : {
168 0 : mrGuid = OleHelper::importGuid( rInStrm );
169 0 : return true;
170 : }
171 :
172 0 : bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm )
173 : {
174 0 : return mrFontData.importGuidAndFont( rInStrm );
175 : }
176 :
177 0 : bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm )
178 : {
179 0 : return OleHelper::importStdPic( mrPicData, rInStrm, true );
180 : }
181 :
182 : // ----------------------------------------------------------------------------
183 :
184 20 : AxBinaryPropertyReader::AxBinaryPropertyReader( BinaryInputStream& rInStrm, bool b64BitPropFlags ) :
185 : maInStrm( rInStrm ),
186 20 : mbValid( true )
187 : {
188 : // version and size of property block
189 20 : maInStrm.skip( 2 );
190 20 : sal_uInt16 nBlockSize = maInStrm.readValue< sal_uInt16 >();
191 20 : mnPropsEnd = maInStrm.tell() + nBlockSize;
192 : // flagfield containing existing properties
193 20 : if( b64BitPropFlags )
194 2 : maInStrm >> mnPropFlags;
195 : else
196 18 : mnPropFlags = maInStrm.readuInt32();
197 20 : mnNextProp = 1;
198 20 : }
199 :
200 8 : void AxBinaryPropertyReader::readBoolProperty( bool& orbValue, bool bReverse )
201 : {
202 : // there is no data, the boolean value is equivalent to the property flag itself
203 8 : orbValue = startNextProperty() != bReverse;
204 8 : }
205 :
206 10 : void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData )
207 : {
208 10 : if( startNextProperty() )
209 10 : maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
210 10 : }
211 :
212 24 : void AxBinaryPropertyReader::readStringProperty( OUString& orValue )
213 : {
214 24 : if( startNextProperty() )
215 : {
216 18 : sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >();
217 18 : maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) );
218 : }
219 24 : }
220 :
221 0 : void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid )
222 : {
223 0 : if( startNextProperty() )
224 0 : maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) );
225 0 : }
226 :
227 0 : void AxBinaryPropertyReader::readFontProperty( AxFontData& orFontData )
228 : {
229 0 : if( startNextProperty() )
230 : {
231 0 : sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
232 0 : if( ensureValid( nData == -1 ) )
233 0 : maStreamProps.push_back( ComplexPropVector::value_type( new FontProperty( orFontData ) ) );
234 : }
235 0 : }
236 :
237 20 : void AxBinaryPropertyReader::readPictureProperty( StreamDataSequence& orPicData )
238 : {
239 20 : if( startNextProperty() )
240 : {
241 0 : sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
242 0 : if( ensureValid( nData == -1 ) )
243 0 : maStreamProps.push_back( ComplexPropVector::value_type( new PictureProperty( orPicData ) ) );
244 : }
245 20 : }
246 :
247 20 : bool AxBinaryPropertyReader::finalizeImport()
248 : {
249 : // read large properties
250 20 : maInStrm.align( 4 );
251 20 : if( ensureValid( mnPropFlags == 0 ) && !maLargeProps.empty() )
252 : {
253 42 : for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
254 : {
255 28 : ensureValid( (*aIt)->readProperty( maInStrm ) );
256 28 : maInStrm.align( 4 );
257 : }
258 : }
259 20 : maInStrm.seek( mnPropsEnd );
260 :
261 : // read stream properties (no stream alignment between properties!)
262 20 : if( ensureValid() && !maStreamProps.empty() )
263 0 : for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
264 0 : ensureValid( (*aIt)->readProperty( maInStrm ) );
265 :
266 20 : return mbValid;
267 : }
268 :
269 348 : bool AxBinaryPropertyReader::ensureValid( bool bCondition )
270 : {
271 348 : mbValid = mbValid && bCondition && !maInStrm.isEof();
272 348 : return mbValid;
273 : }
274 :
275 234 : bool AxBinaryPropertyReader::startNextProperty()
276 : {
277 234 : bool bHasProp = getFlag( mnPropFlags, mnNextProp );
278 234 : setFlag( mnPropFlags, mnNextProp, false );
279 234 : mnNextProp <<= 1;
280 234 : return ensureValid() && bHasProp;
281 : }
282 :
283 : // ============================================================================
284 :
285 : } // namespace ole
286 174 : } // namespace oox
287 :
288 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|