blob: 653a8703663cf4ec076ed00d1f632e41c5727371 [file] [log] [blame]
/**************************************************************
*
* 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 boundries
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