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