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/axbinaryreader.hxx"
25
26 #include "oox/ole/olehelper.hxx"
27
28 namespace oox {
29 namespace ole {
30
31 // ============================================================================
32
33 using ::rtl::OUString;
34
35 // ============================================================================
36
37 namespace {
38
39 const sal_uInt32 AX_STRING_SIZEMASK = 0x7FFFFFFF;
40 const sal_uInt32 AX_STRING_COMPRESSED = 0x80000000;
41
42 } // namespace
43
44 // ============================================================================
45
AxAlignedInputStream(BinaryInputStream & rInStrm)46 AxAlignedInputStream::AxAlignedInputStream( BinaryInputStream& rInStrm ) :
47 BinaryStreamBase( false ),
48 mpInStrm( &rInStrm ),
49 mnStrmPos( 0 ),
50 mnStrmSize( rInStrm.getRemaining() )
51 {
52 mbEof = mbEof || rInStrm.isEof();
53 }
54
size() const55 sal_Int64 AxAlignedInputStream::size() const
56 {
57 return mpInStrm ? mnStrmSize : -1;
58 }
59
tell() const60 sal_Int64 AxAlignedInputStream::tell() const
61 {
62 return mpInStrm ? mnStrmPos : -1;
63 }
64
seek(sal_Int64 nPos)65 void AxAlignedInputStream::seek( sal_Int64 nPos )
66 {
67 mbEof = mbEof || (nPos < mnStrmPos);
68 if( !mbEof )
69 skip( static_cast< sal_Int32 >( nPos - mnStrmPos ) );
70 }
71
close()72 void AxAlignedInputStream::close()
73 {
74 mpInStrm = 0;
75 mbEof = true;
76 }
77
readData(StreamDataSequence & orData,sal_Int32 nBytes,size_t nAtomSize)78 sal_Int32 AxAlignedInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
79 {
80 sal_Int32 nReadSize = 0;
81 if( !mbEof )
82 {
83 nReadSize = mpInStrm->readData( orData, nBytes, nAtomSize );
84 mnStrmPos += nReadSize;
85 mbEof = mpInStrm->isEof();
86 }
87 return nReadSize;
88 }
89
readMemory(void * opMem,sal_Int32 nBytes,size_t nAtomSize)90 sal_Int32 AxAlignedInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
91 {
92 sal_Int32 nReadSize = 0;
93 if( !mbEof )
94 {
95 nReadSize = mpInStrm->readMemory( opMem, nBytes, nAtomSize );
96 mnStrmPos += nReadSize;
97 mbEof = mpInStrm->isEof();
98 }
99 return nReadSize;
100 }
101
skip(sal_Int32 nBytes,size_t nAtomSize)102 void AxAlignedInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
103 {
104 if( !mbEof )
105 {
106 mpInStrm->skip( nBytes, nAtomSize );
107 mnStrmPos += nBytes;
108 mbEof = mpInStrm->isEof();
109 }
110 }
111
align(size_t nSize)112 void AxAlignedInputStream::align( size_t nSize )
113 {
114 skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
115 }
116
117 // ============================================================================
118
AxFontData()119 AxFontData::AxFontData() :
120 mnFontEffects( 0 ),
121 mnFontHeight( 160 ),
122 mnFontCharSet( WINDOWS_CHARSET_DEFAULT ),
123 mnHorAlign( AX_FONTDATA_LEFT ),
124 mbDblUnderline( false )
125 {
126 }
127
getHeightPoints() const128 sal_Int16 AxFontData::getHeightPoints() const
129 {
130 /* MSO uses weird font sizes:
131 1pt->30, 2pt->45, 3pt->60, 4pt->75, 5pt->105, 6pt->120, 7pt->135,
132 8pt->165, 9pt->180, 10pt->195, 11pt->225, ... */
133 return getLimitedValue< sal_Int16, sal_Int32 >( (mnFontHeight + 10) / 20, 1, SAL_MAX_INT16 );
134 }
135
setHeightPoints(sal_Int16 nPoints)136 void AxFontData::setHeightPoints( sal_Int16 nPoints )
137 {
138 mnFontHeight = getLimitedValue< sal_Int32, sal_Int32 >( ((nPoints * 4 + 1) / 3) * 15, 30, 4294967 );
139 }
140
importBinaryModel(BinaryInputStream & rInStrm)141 bool AxFontData::importBinaryModel( BinaryInputStream& rInStrm )
142 {
143 AxBinaryPropertyReader aReader( rInStrm );
144 aReader.readStringProperty( maFontName );
145 aReader.readIntProperty< sal_uInt32 >( mnFontEffects );
146 aReader.readIntProperty< sal_Int32 >( mnFontHeight );
147 aReader.skipIntProperty< sal_Int32 >(); // font offset
148 aReader.readIntProperty< sal_uInt8 >( mnFontCharSet );
149 aReader.skipIntProperty< sal_uInt8 >(); // font pitch/family
150 aReader.readIntProperty< sal_uInt8 >( mnHorAlign );
151 aReader.skipIntProperty< sal_uInt16 >(); // font weight
152 mbDblUnderline = false;
153 return aReader.finalizeImport();
154 }
155
importStdFont(BinaryInputStream & rInStrm)156 bool AxFontData::importStdFont( BinaryInputStream& rInStrm )
157 {
158 StdFontInfo aFontInfo;
159 if( OleHelper::importStdFont( aFontInfo, rInStrm, false ) )
160 {
161 maFontName = aFontInfo.maName;
162 mnFontEffects = 0;
163 setFlag( mnFontEffects, AX_FONTDATA_BOLD, aFontInfo.mnWeight >= OLE_STDFONT_BOLD );
164 setFlag( mnFontEffects, AX_FONTDATA_ITALIC, getFlag( aFontInfo.mnFlags, OLE_STDFONT_ITALIC ) );
165 setFlag( mnFontEffects, AX_FONTDATA_UNDERLINE, getFlag( aFontInfo.mnFlags, OLE_STDFONT_UNDERLINE ) );
166 setFlag( mnFontEffects, AX_FONTDATA_STRIKEOUT, getFlag( aFontInfo.mnFlags,OLE_STDFONT_STRIKE ) );
167 mbDblUnderline = false;
168 // StdFont stores font height in 1/10,000 of points
169 setHeightPoints( getLimitedValue< sal_Int16, sal_Int32 >( aFontInfo.mnHeight / 10000, 0, SAL_MAX_INT16 ) );
170 mnFontCharSet = aFontInfo.mnCharSet;
171 mnHorAlign = AX_FONTDATA_LEFT;
172 return true;
173 }
174 return false;
175 }
176
importGuidAndFont(BinaryInputStream & rInStrm)177 bool AxFontData::importGuidAndFont( BinaryInputStream& rInStrm )
178 {
179 OUString aGuid = OleHelper::importGuid( rInStrm );
180 if( aGuid.equalsAscii( AX_GUID_CFONT ) )
181 return importBinaryModel( rInStrm );
182 if( aGuid.equalsAscii( OLE_GUID_STDFONT ) )
183 return importStdFont( rInStrm );
184 return false;
185 }
186
187 // ============================================================================
188
189 namespace {
190
lclReadString(AxAlignedInputStream & rInStrm,OUString & rValue,sal_uInt32 nSize,bool bArrayString)191 bool lclReadString( AxAlignedInputStream& rInStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString )
192 {
193 bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED );
194 sal_uInt32 nBufSize = nSize & AX_STRING_SIZEMASK;
195 // Unicode: simple strings store byte count, array strings store char count
196 sal_Int32 nChars = static_cast< sal_Int32 >( nBufSize / ((bCompressed || bArrayString) ? 1 : 2) );
197 bool bValidChars = nChars <= 65536;
198 OSL_ENSURE( bValidChars, "lclReadString - string too long" );
199 sal_Int64 nEndPos = rInStrm.tell() + nChars * (bCompressed ? 1 : 2);
200 nChars = ::std::min< sal_Int32 >( nChars, 65536 );
201 rValue = rInStrm.readCompressedUnicodeArray( nChars, bCompressed );
202 rInStrm.seek( nEndPos );
203 return bValidChars;
204 }
205
206 } // namespace
207
208 // ----------------------------------------------------------------------------
209
~ComplexProperty()210 AxBinaryPropertyReader::ComplexProperty::~ComplexProperty()
211 {
212 }
213
readProperty(AxAlignedInputStream & rInStrm)214 bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm )
215 {
216 rInStrm >> mrPairData.first >> mrPairData.second;
217 return true;
218 }
219
readProperty(AxAlignedInputStream & rInStrm)220 bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm )
221 {
222 return lclReadString( rInStrm, mrValue, mnSize, false );
223 }
224
readProperty(AxAlignedInputStream & rInStrm)225 bool AxBinaryPropertyReader::StringArrayProperty::readProperty( AxAlignedInputStream& rInStrm )
226 {
227 sal_Int64 nEndPos = rInStrm.tell() + mnSize;
228 while( rInStrm.tell() < nEndPos )
229 {
230 OUString aString;
231 if( !lclReadString( rInStrm, aString, rInStrm.readuInt32(), true ) )
232 return false;
233 mrArray.push_back( aString );
234 // every array string is aligned on 4 byte boundaries
235 rInStrm.align( 4 );
236 }
237 return true;
238 }
239
readProperty(AxAlignedInputStream & rInStrm)240 bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm )
241 {
242 mrGuid = OleHelper::importGuid( rInStrm );
243 return true;
244 }
245
readProperty(AxAlignedInputStream & rInStrm)246 bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm )
247 {
248 return mrFontData.importGuidAndFont( rInStrm );
249 }
250
readProperty(AxAlignedInputStream & rInStrm)251 bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm )
252 {
253 return OleHelper::importStdPic( mrPicData, rInStrm, true );
254 }
255
256 // ----------------------------------------------------------------------------
257
AxBinaryPropertyReader(BinaryInputStream & rInStrm,bool b64BitPropFlags)258 AxBinaryPropertyReader::AxBinaryPropertyReader( BinaryInputStream& rInStrm, bool b64BitPropFlags ) :
259 maInStrm( rInStrm ),
260 mbValid( true )
261 {
262 // version and size of property block
263 maInStrm.skip( 2 );
264 sal_uInt16 nBlockSize = maInStrm.readValue< sal_uInt16 >();
265 mnPropsEnd = maInStrm.tell() + nBlockSize;
266 // flagfield containing existing properties
267 if( b64BitPropFlags )
268 maInStrm >> mnPropFlags;
269 else
270 mnPropFlags = maInStrm.readuInt32();
271 mnNextProp = 1;
272 }
273
readBoolProperty(bool & orbValue,bool bReverse)274 void AxBinaryPropertyReader::readBoolProperty( bool& orbValue, bool bReverse )
275 {
276 // there is no data, the boolean value is equivalent to the property flag itself
277 orbValue = startNextProperty() != bReverse;
278 }
279
readPairProperty(AxPairData & orPairData)280 void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData )
281 {
282 if( startNextProperty() )
283 maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
284 }
285
readStringProperty(OUString & orValue)286 void AxBinaryPropertyReader::readStringProperty( OUString& orValue )
287 {
288 if( startNextProperty() )
289 {
290 sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >();
291 maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) );
292 }
293 }
294
readStringArrayProperty(AxStringArray & orArray)295 void AxBinaryPropertyReader::readStringArrayProperty( AxStringArray& orArray )
296 {
297 if( startNextProperty() )
298 {
299 sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >();
300 maLargeProps.push_back( ComplexPropVector::value_type( new StringArrayProperty( orArray, nSize ) ) );
301 }
302 }
303
readGuidProperty(::rtl::OUString & orGuid)304 void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid )
305 {
306 if( startNextProperty() )
307 maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) );
308 }
309
readFontProperty(AxFontData & orFontData)310 void AxBinaryPropertyReader::readFontProperty( AxFontData& orFontData )
311 {
312 if( startNextProperty() )
313 {
314 sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
315 if( ensureValid( nData == -1 ) )
316 maStreamProps.push_back( ComplexPropVector::value_type( new FontProperty( orFontData ) ) );
317 }
318 }
319
readPictureProperty(StreamDataSequence & orPicData)320 void AxBinaryPropertyReader::readPictureProperty( StreamDataSequence& orPicData )
321 {
322 if( startNextProperty() )
323 {
324 sal_Int16 nData = maInStrm.readAligned< sal_Int16 >();
325 if( ensureValid( nData == -1 ) )
326 maStreamProps.push_back( ComplexPropVector::value_type( new PictureProperty( orPicData ) ) );
327 }
328 }
329
finalizeImport()330 bool AxBinaryPropertyReader::finalizeImport()
331 {
332 // read large properties
333 maInStrm.align( 4 );
334 if( ensureValid( mnPropFlags == 0 ) && !maLargeProps.empty() )
335 {
336 for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
337 {
338 ensureValid( (*aIt)->readProperty( maInStrm ) );
339 maInStrm.align( 4 );
340 }
341 }
342 maInStrm.seek( mnPropsEnd );
343
344 // read stream properties (no stream alignment between properties!)
345 if( ensureValid() && !maStreamProps.empty() )
346 for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt )
347 ensureValid( (*aIt)->readProperty( maInStrm ) );
348
349 return mbValid;
350 }
351
ensureValid(bool bCondition)352 bool AxBinaryPropertyReader::ensureValid( bool bCondition )
353 {
354 mbValid = mbValid && bCondition && !maInStrm.isEof();
355 return mbValid;
356 }
357
startNextProperty()358 bool AxBinaryPropertyReader::startNextProperty()
359 {
360 bool bHasProp = getFlag( mnPropFlags, mnNextProp );
361 setFlag( mnPropFlags, mnNextProp, false );
362 mnNextProp <<= 1;
363 return ensureValid() && bHasProp;
364 }
365
366 // ============================================================================
367
368 } // namespace ole
369 } // namespace oox
370