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