xref: /trunk/main/oox/source/ole/axbinaryreader.cxx (revision ca5ec200)
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 
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 
55 sal_Int64 AxAlignedInputStream::size() const
56 {
57     return mpInStrm ? mnStrmSize : -1;
58 }
59 
60 sal_Int64 AxAlignedInputStream::tell() const
61 {
62     return mpInStrm ? mnStrmPos : -1;
63 }
64 
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 
72 void AxAlignedInputStream::close()
73 {
74     mpInStrm = 0;
75     mbEof = true;
76 }
77 
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 
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 
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 
112 void AxAlignedInputStream::align( size_t nSize )
113 {
114     skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) );
115 }
116 
117 // ============================================================================
118 
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 
128 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 
136 void AxFontData::setHeightPoints( sal_Int16 nPoints )
137 {
138     mnFontHeight = getLimitedValue< sal_Int32, sal_Int32 >( ((nPoints * 4 + 1) / 3) * 15, 30, 4294967 );
139 }
140 
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 
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 
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 
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 
210 AxBinaryPropertyReader::ComplexProperty::~ComplexProperty()
211 {
212 }
213 
214 bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm )
215 {
216     rInStrm >> mrPairData.first >> mrPairData.second;
217     return true;
218 }
219 
220 bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm )
221 {
222     return lclReadString( rInStrm, mrValue, mnSize, false );
223 }
224 
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 boundries
235         rInStrm.align( 4 );
236     }
237     return true;
238 }
239 
240 bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm )
241 {
242     mrGuid = OleHelper::importGuid( rInStrm );
243     return true;
244 }
245 
246 bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm )
247 {
248     return mrFontData.importGuidAndFont( rInStrm );
249 }
250 
251 bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm )
252 {
253     return OleHelper::importStdPic( mrPicData, rInStrm, true );
254 }
255 
256 // ----------------------------------------------------------------------------
257 
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 
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 
280 void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData )
281 {
282     if( startNextProperty() )
283         maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) );
284 }
285 
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 
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 
304 void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid )
305 {
306     if( startNextProperty() )
307         maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) );
308 }
309 
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 
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 
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 
352 bool AxBinaryPropertyReader::ensureValid( bool bCondition )
353 {
354     mbValid = mbValid && bCondition && !maInStrm.isEof();
355     return mbValid;
356 }
357 
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