/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "oox/ole/axbinaryreader.hxx" #include "oox/ole/olehelper.hxx" namespace oox { namespace ole { // ============================================================================ using ::rtl::OUString; // ============================================================================ namespace { const sal_uInt32 AX_STRING_SIZEMASK = 0x7FFFFFFF; const sal_uInt32 AX_STRING_COMPRESSED = 0x80000000; } // namespace // ============================================================================ AxAlignedInputStream::AxAlignedInputStream( BinaryInputStream& rInStrm ) : BinaryStreamBase( false ), mpInStrm( &rInStrm ), mnStrmPos( 0 ), mnStrmSize( rInStrm.getRemaining() ) { mbEof = mbEof || rInStrm.isEof(); } sal_Int64 AxAlignedInputStream::size() const { return mpInStrm ? mnStrmSize : -1; } sal_Int64 AxAlignedInputStream::tell() const { return mpInStrm ? mnStrmPos : -1; } void AxAlignedInputStream::seek( sal_Int64 nPos ) { mbEof = mbEof || (nPos < mnStrmPos); if( !mbEof ) skip( static_cast< sal_Int32 >( nPos - mnStrmPos ) ); } void AxAlignedInputStream::close() { mpInStrm = 0; mbEof = true; } sal_Int32 AxAlignedInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize ) { sal_Int32 nReadSize = 0; if( !mbEof ) { nReadSize = mpInStrm->readData( orData, nBytes, nAtomSize ); mnStrmPos += nReadSize; mbEof = mpInStrm->isEof(); } return nReadSize; } sal_Int32 AxAlignedInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize ) { sal_Int32 nReadSize = 0; if( !mbEof ) { nReadSize = mpInStrm->readMemory( opMem, nBytes, nAtomSize ); mnStrmPos += nReadSize; mbEof = mpInStrm->isEof(); } return nReadSize; } void AxAlignedInputStream::skip( sal_Int32 nBytes, size_t nAtomSize ) { if( !mbEof ) { mpInStrm->skip( nBytes, nAtomSize ); mnStrmPos += nBytes; mbEof = mpInStrm->isEof(); } } void AxAlignedInputStream::align( size_t nSize ) { skip( static_cast< sal_Int32 >( (nSize - (mnStrmPos % nSize)) % nSize ) ); } // ============================================================================ AxFontData::AxFontData() : mnFontEffects( 0 ), mnFontHeight( 160 ), mnFontCharSet( WINDOWS_CHARSET_DEFAULT ), mnHorAlign( AX_FONTDATA_LEFT ), mbDblUnderline( false ) { } sal_Int16 AxFontData::getHeightPoints() const { /* MSO uses weird font sizes: 1pt->30, 2pt->45, 3pt->60, 4pt->75, 5pt->105, 6pt->120, 7pt->135, 8pt->165, 9pt->180, 10pt->195, 11pt->225, ... */ return getLimitedValue< sal_Int16, sal_Int32 >( (mnFontHeight + 10) / 20, 1, SAL_MAX_INT16 ); } void AxFontData::setHeightPoints( sal_Int16 nPoints ) { mnFontHeight = getLimitedValue< sal_Int32, sal_Int32 >( ((nPoints * 4 + 1) / 3) * 15, 30, 4294967 ); } bool AxFontData::importBinaryModel( BinaryInputStream& rInStrm ) { AxBinaryPropertyReader aReader( rInStrm ); aReader.readStringProperty( maFontName ); aReader.readIntProperty< sal_uInt32 >( mnFontEffects ); aReader.readIntProperty< sal_Int32 >( mnFontHeight ); aReader.skipIntProperty< sal_Int32 >(); // font offset aReader.readIntProperty< sal_uInt8 >( mnFontCharSet ); aReader.skipIntProperty< sal_uInt8 >(); // font pitch/family aReader.readIntProperty< sal_uInt8 >( mnHorAlign ); aReader.skipIntProperty< sal_uInt16 >(); // font weight mbDblUnderline = false; return aReader.finalizeImport(); } bool AxFontData::importStdFont( BinaryInputStream& rInStrm ) { StdFontInfo aFontInfo; if( OleHelper::importStdFont( aFontInfo, rInStrm, false ) ) { maFontName = aFontInfo.maName; mnFontEffects = 0; setFlag( mnFontEffects, AX_FONTDATA_BOLD, aFontInfo.mnWeight >= OLE_STDFONT_BOLD ); setFlag( mnFontEffects, AX_FONTDATA_ITALIC, getFlag( aFontInfo.mnFlags, OLE_STDFONT_ITALIC ) ); setFlag( mnFontEffects, AX_FONTDATA_UNDERLINE, getFlag( aFontInfo.mnFlags, OLE_STDFONT_UNDERLINE ) ); setFlag( mnFontEffects, AX_FONTDATA_STRIKEOUT, getFlag( aFontInfo.mnFlags,OLE_STDFONT_STRIKE ) ); mbDblUnderline = false; // StdFont stores font height in 1/10,000 of points setHeightPoints( getLimitedValue< sal_Int16, sal_Int32 >( aFontInfo.mnHeight / 10000, 0, SAL_MAX_INT16 ) ); mnFontCharSet = aFontInfo.mnCharSet; mnHorAlign = AX_FONTDATA_LEFT; return true; } return false; } bool AxFontData::importGuidAndFont( BinaryInputStream& rInStrm ) { OUString aGuid = OleHelper::importGuid( rInStrm ); if( aGuid.equalsAscii( AX_GUID_CFONT ) ) return importBinaryModel( rInStrm ); if( aGuid.equalsAscii( OLE_GUID_STDFONT ) ) return importStdFont( rInStrm ); return false; } // ============================================================================ namespace { bool lclReadString( AxAlignedInputStream& rInStrm, OUString& rValue, sal_uInt32 nSize, bool bArrayString ) { bool bCompressed = getFlag( nSize, AX_STRING_COMPRESSED ); sal_uInt32 nBufSize = nSize & AX_STRING_SIZEMASK; // Unicode: simple strings store byte count, array strings store char count sal_Int32 nChars = static_cast< sal_Int32 >( nBufSize / ((bCompressed || bArrayString) ? 1 : 2) ); bool bValidChars = nChars <= 65536; OSL_ENSURE( bValidChars, "lclReadString - string too long" ); sal_Int64 nEndPos = rInStrm.tell() + nChars * (bCompressed ? 1 : 2); nChars = ::std::min< sal_Int32 >( nChars, 65536 ); rValue = rInStrm.readCompressedUnicodeArray( nChars, bCompressed ); rInStrm.seek( nEndPos ); return bValidChars; } } // namespace // ---------------------------------------------------------------------------- AxBinaryPropertyReader::ComplexProperty::~ComplexProperty() { } bool AxBinaryPropertyReader::PairProperty::readProperty( AxAlignedInputStream& rInStrm ) { rInStrm >> mrPairData.first >> mrPairData.second; return true; } bool AxBinaryPropertyReader::StringProperty::readProperty( AxAlignedInputStream& rInStrm ) { return lclReadString( rInStrm, mrValue, mnSize, false ); } bool AxBinaryPropertyReader::StringArrayProperty::readProperty( AxAlignedInputStream& rInStrm ) { sal_Int64 nEndPos = rInStrm.tell() + mnSize; while( rInStrm.tell() < nEndPos ) { OUString aString; if( !lclReadString( rInStrm, aString, rInStrm.readuInt32(), true ) ) return false; mrArray.push_back( aString ); // every array string is aligned on 4 byte boundaries rInStrm.align( 4 ); } return true; } bool AxBinaryPropertyReader::GuidProperty::readProperty( AxAlignedInputStream& rInStrm ) { mrGuid = OleHelper::importGuid( rInStrm ); return true; } bool AxBinaryPropertyReader::FontProperty::readProperty( AxAlignedInputStream& rInStrm ) { return mrFontData.importGuidAndFont( rInStrm ); } bool AxBinaryPropertyReader::PictureProperty::readProperty( AxAlignedInputStream& rInStrm ) { return OleHelper::importStdPic( mrPicData, rInStrm, true ); } // ---------------------------------------------------------------------------- AxBinaryPropertyReader::AxBinaryPropertyReader( BinaryInputStream& rInStrm, bool b64BitPropFlags ) : maInStrm( rInStrm ), mbValid( true ) { // version and size of property block maInStrm.skip( 2 ); sal_uInt16 nBlockSize = maInStrm.readValue< sal_uInt16 >(); mnPropsEnd = maInStrm.tell() + nBlockSize; // flagfield containing existing properties if( b64BitPropFlags ) maInStrm >> mnPropFlags; else mnPropFlags = maInStrm.readuInt32(); mnNextProp = 1; } void AxBinaryPropertyReader::readBoolProperty( bool& orbValue, bool bReverse ) { // there is no data, the boolean value is equivalent to the property flag itself orbValue = startNextProperty() != bReverse; } void AxBinaryPropertyReader::readPairProperty( AxPairData& orPairData ) { if( startNextProperty() ) maLargeProps.push_back( ComplexPropVector::value_type( new PairProperty( orPairData ) ) ); } void AxBinaryPropertyReader::readStringProperty( OUString& orValue ) { if( startNextProperty() ) { sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >(); maLargeProps.push_back( ComplexPropVector::value_type( new StringProperty( orValue, nSize ) ) ); } } void AxBinaryPropertyReader::readStringArrayProperty( AxStringArray& orArray ) { if( startNextProperty() ) { sal_uInt32 nSize = maInStrm.readAligned< sal_uInt32 >(); maLargeProps.push_back( ComplexPropVector::value_type( new StringArrayProperty( orArray, nSize ) ) ); } } void AxBinaryPropertyReader::readGuidProperty( ::rtl::OUString& orGuid ) { if( startNextProperty() ) maLargeProps.push_back( ComplexPropVector::value_type( new GuidProperty( orGuid ) ) ); } void AxBinaryPropertyReader::readFontProperty( AxFontData& orFontData ) { if( startNextProperty() ) { sal_Int16 nData = maInStrm.readAligned< sal_Int16 >(); if( ensureValid( nData == -1 ) ) maStreamProps.push_back( ComplexPropVector::value_type( new FontProperty( orFontData ) ) ); } } void AxBinaryPropertyReader::readPictureProperty( StreamDataSequence& orPicData ) { if( startNextProperty() ) { sal_Int16 nData = maInStrm.readAligned< sal_Int16 >(); if( ensureValid( nData == -1 ) ) maStreamProps.push_back( ComplexPropVector::value_type( new PictureProperty( orPicData ) ) ); } } bool AxBinaryPropertyReader::finalizeImport() { // read large properties maInStrm.align( 4 ); if( ensureValid( mnPropFlags == 0 ) && !maLargeProps.empty() ) { for( ComplexPropVector::iterator aIt = maLargeProps.begin(), aEnd = maLargeProps.end(); ensureValid() && (aIt != aEnd); ++aIt ) { ensureValid( (*aIt)->readProperty( maInStrm ) ); maInStrm.align( 4 ); } } maInStrm.seek( mnPropsEnd ); // read stream properties (no stream alignment between properties!) if( ensureValid() && !maStreamProps.empty() ) for( ComplexPropVector::iterator aIt = maStreamProps.begin(), aEnd = maStreamProps.end(); ensureValid() && (aIt != aEnd); ++aIt ) ensureValid( (*aIt)->readProperty( maInStrm ) ); return mbValid; } bool AxBinaryPropertyReader::ensureValid( bool bCondition ) { mbValid = mbValid && bCondition && !maInStrm.isEof(); return mbValid; } bool AxBinaryPropertyReader::startNextProperty() { bool bHasProp = getFlag( mnPropFlags, mnNextProp ); setFlag( mnPropFlags, mnNextProp, false ); mnNextProp <<= 1; return ensureValid() && bHasProp; } // ============================================================================ } // namespace ole } // namespace oox