blob: 11dd69d01d65f4bf0911b74ea72490758e4ba422 [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/olehelper.hxx"
#include <rtl/ustrbuf.hxx>
#include "oox/helper/binaryinputstream.hxx"
#include "oox/helper/graphichelper.hxx"
#include "oox/token/tokens.hxx"
namespace oox {
namespace ole {
// ============================================================================
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
// ============================================================================
namespace {
const sal_uInt32 OLE_COLORTYPE_MASK = 0xFF000000;
const sal_uInt32 OLE_COLORTYPE_CLIENT = 0x00000000;
const sal_uInt32 OLE_COLORTYPE_PALETTE = 0x01000000;
const sal_uInt32 OLE_COLORTYPE_BGR = 0x02000000;
const sal_uInt32 OLE_COLORTYPE_SYSCOLOR = 0x80000000;
const sal_uInt32 OLE_PALETTECOLOR_MASK = 0x0000FFFF;
const sal_uInt32 OLE_BGRCOLOR_MASK = 0x00FFFFFF;
const sal_uInt32 OLE_SYSTEMCOLOR_MASK = 0x0000FFFF;
/** Swaps the red and blue component of the passed color. */
inline sal_uInt32 lclSwapRedBlue( sal_uInt32 nColor )
{
return static_cast< sal_uInt32 >( (nColor & 0xFF00FF00) | ((nColor & 0x0000FF) << 16) | ((nColor & 0xFF0000) >> 16) );
}
/** Returns the UNO RGB color from the passed encoded OLE BGR color. */
inline sal_Int32 lclDecodeBgrColor( sal_uInt32 nOleColor )
{
return static_cast< sal_Int32 >( lclSwapRedBlue( nOleColor ) & 0xFFFFFF );
}
// ----------------------------------------------------------------------------
const sal_Char* const OLE_GUID_URLMONIKER = "{79EAC9E0-BAF9-11CE-8C82-00AA004BA90B}";
const sal_Char* const OLE_GUID_FILEMONIKER = "{00000303-0000-0000-C000-000000000046}";
const sal_uInt32 OLE_STDPIC_ID = 0x0000746C;
const sal_uInt32 OLE_STDHLINK_VERSION = 2;
const sal_uInt32 OLE_STDHLINK_HASTARGET = 0x00000001; /// Has hyperlink moniker.
const sal_uInt32 OLE_STDHLINK_ABSOLUTE = 0x00000002; /// Absolute path.
const sal_uInt32 OLE_STDHLINK_HASLOCATION = 0x00000008; /// Has target location.
const sal_uInt32 OLE_STDHLINK_HASDISPLAY = 0x00000010; /// Has display string.
const sal_uInt32 OLE_STDHLINK_HASGUID = 0x00000020; /// Has identification GUID.
const sal_uInt32 OLE_STDHLINK_HASTIME = 0x00000040; /// Has creation time.
const sal_uInt32 OLE_STDHLINK_HASFRAME = 0x00000080; /// Has frame.
const sal_uInt32 OLE_STDHLINK_ASSTRING = 0x00000100; /// Hyperlink as simple string.
// ----------------------------------------------------------------------------
template< typename Type >
void lclAppendHex( OUStringBuffer& orBuffer, Type nValue )
{
const sal_Int32 nWidth = 2 * sizeof( Type );
static const sal_Unicode spcHexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
orBuffer.setLength( orBuffer.getLength() + nWidth );
for( sal_Int32 nCharIdx = orBuffer.getLength() - 1, nCharEnd = nCharIdx - nWidth; nCharIdx > nCharEnd; --nCharIdx, nValue >>= 4 )
orBuffer.setCharAt( nCharIdx, spcHexChars[ nValue & 0xF ] );
}
OUString lclReadStdHlinkString( BinaryInputStream& rInStrm, bool bUnicode )
{
OUString aRet;
sal_Int32 nChars = rInStrm.readInt32();
if( nChars > 0 )
{
sal_Int32 nReadChars = getLimitedValue< sal_Int32, sal_Int32 >( nChars, 0, SAL_MAX_UINT16 );
// byte strings are always in ANSI (Windows 1252) encoding
aRet = bUnicode ? rInStrm.readUnicodeArray( nReadChars, true ) : rInStrm.readCharArrayUC( nReadChars, RTL_TEXTENCODING_MS_1252, true );
// strings are NUL terminated, remove trailing NUL and possible other garbage
sal_Int32 nNulPos = aRet.indexOf( '\0' );
if( nNulPos >= 0 )
aRet = aRet.copy( 0, nNulPos );
// skip remaining chars
rInStrm.skip( (bUnicode ? 2 : 1) * (nChars - nReadChars) );
}
return aRet;
}
} // namespace
// ============================================================================
StdFontInfo::StdFontInfo() :
mnHeight( 0 ),
mnWeight( OLE_STDFONT_NORMAL ),
mnCharSet( WINDOWS_CHARSET_ANSI ),
mnFlags( 0 )
{
}
StdFontInfo::StdFontInfo( const ::rtl::OUString& rName, sal_uInt32 nHeight,
sal_uInt16 nWeight, sal_uInt16 nCharSet, sal_uInt8 nFlags ) :
maName( rName ),
mnHeight( nHeight ),
mnWeight( nWeight ),
mnCharSet( nCharSet ),
mnFlags( nFlags )
{
}
// ============================================================================
/*static*/ sal_Int32 OleHelper::decodeOleColor(
const GraphicHelper& rGraphicHelper, sal_uInt32 nOleColor, bool bDefaultColorBgr )
{
static const sal_Int32 spnSystemColors[] =
{
XML_scrollBar, XML_background, XML_activeCaption, XML_inactiveCaption,
XML_menu, XML_window, XML_windowFrame, XML_menuText,
XML_windowText, XML_captionText, XML_activeBorder, XML_inactiveBorder,
XML_appWorkspace, XML_highlight, XML_highlightText, XML_btnFace,
XML_btnShadow, XML_grayText, XML_btnText, XML_inactiveCaptionText,
XML_btnHighlight, XML_3dDkShadow, XML_3dLight, XML_infoText,
XML_infoBk
};
switch( nOleColor & OLE_COLORTYPE_MASK )
{
case OLE_COLORTYPE_CLIENT:
return bDefaultColorBgr ? lclDecodeBgrColor( nOleColor ) : rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK );
case OLE_COLORTYPE_PALETTE:
return rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK );
case OLE_COLORTYPE_BGR:
return lclDecodeBgrColor( nOleColor );
case OLE_COLORTYPE_SYSCOLOR:
return rGraphicHelper.getSystemColor( STATIC_ARRAY_SELECT( spnSystemColors, nOleColor & OLE_SYSTEMCOLOR_MASK, XML_TOKEN_INVALID ), API_RGB_WHITE );
}
OSL_ENSURE( false, "OleHelper::decodeOleColor - unknown color type" );
return API_RGB_BLACK;
}
/*static*/ sal_uInt32 OleHelper::encodeOleColor( sal_Int32 nRgbColor )
{
return OLE_COLORTYPE_BGR | lclSwapRedBlue( static_cast< sal_uInt32 >( nRgbColor & 0xFFFFFF ) );
}
/*static*/ OUString OleHelper::importGuid( BinaryInputStream& rInStrm )
{
OUStringBuffer aBuffer;
aBuffer.append( sal_Unicode( '{' ) );
lclAppendHex( aBuffer, rInStrm.readuInt32() );
aBuffer.append( sal_Unicode( '-' ) );
lclAppendHex( aBuffer, rInStrm.readuInt16() );
aBuffer.append( sal_Unicode( '-' ) );
lclAppendHex( aBuffer, rInStrm.readuInt16() );
aBuffer.append( sal_Unicode( '-' ) );
lclAppendHex( aBuffer, rInStrm.readuInt8() );
lclAppendHex( aBuffer, rInStrm.readuInt8() );
aBuffer.append( sal_Unicode( '-' ) );
for( int nIndex = 0; nIndex < 6; ++nIndex )
lclAppendHex( aBuffer, rInStrm.readuInt8() );
aBuffer.append( sal_Unicode( '}' ) );
return aBuffer.makeStringAndClear();
}
/*static*/ bool OleHelper::importStdFont( StdFontInfo& orFontInfo, BinaryInputStream& rInStrm, bool bWithGuid )
{
if( bWithGuid )
{
bool bIsStdFont = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDFONT );
OSL_ENSURE( bIsStdFont, "OleHelper::importStdFont - unexpected header GUID, expected StdFont" );
if( !bIsStdFont )
return false;
}
sal_uInt8 nVersion, nNameLen;
rInStrm >> nVersion >> orFontInfo.mnCharSet >> orFontInfo.mnFlags >> orFontInfo.mnWeight >> orFontInfo.mnHeight >> nNameLen;
// according to spec the name is ASCII
orFontInfo.maName = rInStrm.readCharArrayUC( nNameLen, RTL_TEXTENCODING_ASCII_US );
OSL_ENSURE( nVersion <= 1, "OleHelper::importStdFont - wrong version" );
return !rInStrm.isEof() && (nVersion <= 1);
}
/*static*/ bool OleHelper::importStdPic( StreamDataSequence& orGraphicData, BinaryInputStream& rInStrm, bool bWithGuid )
{
if( bWithGuid )
{
bool bIsStdPic = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDPIC );
OSL_ENSURE( bIsStdPic, "OleHelper::importStdPic - unexpected header GUID, expected StdPic" );
if( !bIsStdPic )
return false;
}
sal_uInt32 nStdPicId;
sal_Int32 nBytes;
rInStrm >> nStdPicId >> nBytes;
OSL_ENSURE( nStdPicId == OLE_STDPIC_ID, "OleHelper::importStdPic - unexpected header version" );
return !rInStrm.isEof() && (nStdPicId == OLE_STDPIC_ID) && (nBytes > 0) && (rInStrm.readData( orGraphicData, nBytes ) == nBytes);
}
/*static*/ bool OleHelper::importStdHlink( StdHlinkInfo& orHlinkInfo, BinaryInputStream& rInStrm, bool bWithGuid )
{
if( bWithGuid )
{
bool bIsStdHlink = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDHLINK );
OSL_ENSURE( bIsStdHlink, "OleHelper::importStdHlink - unexpected header GUID, expected StdHlink" );
if( !bIsStdHlink )
return false;
}
sal_uInt32 nVersion, nFlags;
rInStrm >> nVersion >> nFlags;
OSL_ENSURE( nVersion == OLE_STDHLINK_VERSION, "OleHelper::importStdHlink - unexpected header version" );
if( rInStrm.isEof() || (nVersion != OLE_STDHLINK_VERSION) )
return false;
// display string
if( getFlag( nFlags, OLE_STDHLINK_HASDISPLAY ) )
orHlinkInfo.maDisplay = lclReadStdHlinkString( rInStrm, true );
// frame string
if( getFlag( nFlags, OLE_STDHLINK_HASFRAME ) )
orHlinkInfo.maFrame = lclReadStdHlinkString( rInStrm, true );
// target
if( getFlag( nFlags, OLE_STDHLINK_HASTARGET ) )
{
if( getFlag( nFlags, OLE_STDHLINK_ASSTRING ) )
{
OSL_ENSURE( getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - link not absolute" );
orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, true );
}
else // hyperlink moniker
{
OUString aGuid = importGuid( rInStrm );
if( aGuid.equalsAscii( OLE_GUID_FILEMONIKER ) )
{
// file name, maybe relative and with directory up-count
sal_Int16 nUpLevels;
rInStrm >> nUpLevels;
OSL_ENSURE( (nUpLevels == 0) || !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - absolute filename with upcount" );
orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, false );
rInStrm.skip( 24 );
sal_Int32 nBytes = rInStrm.readInt32();
if( nBytes > 0 )
{
sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 );
sal_uInt16 nChars = getLimitedValue< sal_uInt16, sal_Int32 >( rInStrm.readInt32() / 2, 0, SAL_MAX_UINT16 );
rInStrm.skip( 2 ); // key value
orHlinkInfo.maTarget = rInStrm.readUnicodeArray( nChars ); // NOT null terminated
rInStrm.seek( nEndPos );
}
if( !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ) )
for( sal_Int16 nLevel = 0; nLevel < nUpLevels; ++nLevel )
orHlinkInfo.maTarget = CREATE_OUSTRING( "../" ) + orHlinkInfo.maTarget;
}
else if( aGuid.equalsAscii( OLE_GUID_URLMONIKER ) )
{
// URL, maybe relative and with leading '../'
sal_Int32 nBytes = rInStrm.readInt32();
sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 );
orHlinkInfo.maTarget = rInStrm.readNulUnicodeArray();
rInStrm.seek( nEndPos );
}
else
{
OSL_ENSURE( false, "OleHelper::importStdHlink - unsupported hyperlink moniker" );
return false;
}
}
}
// target location
if( getFlag( nFlags, OLE_STDHLINK_HASLOCATION ) )
orHlinkInfo.maLocation = lclReadStdHlinkString( rInStrm, true );
return !rInStrm.isEof();
}
// ============================================================================
} // namespace ole
} // namespace oox