1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "oox/ole/olehelper.hxx" 29 30 #include <rtl/ustrbuf.hxx> 31 #include "oox/helper/binaryinputstream.hxx" 32 #include "oox/helper/graphichelper.hxx" 33 #include "oox/token/tokens.hxx" 34 35 namespace oox { 36 namespace ole { 37 38 // ============================================================================ 39 40 using ::rtl::OUString; 41 using ::rtl::OUStringBuffer; 42 43 // ============================================================================ 44 45 namespace { 46 47 const sal_uInt32 OLE_COLORTYPE_MASK = 0xFF000000; 48 const sal_uInt32 OLE_COLORTYPE_CLIENT = 0x00000000; 49 const sal_uInt32 OLE_COLORTYPE_PALETTE = 0x01000000; 50 const sal_uInt32 OLE_COLORTYPE_BGR = 0x02000000; 51 const sal_uInt32 OLE_COLORTYPE_SYSCOLOR = 0x80000000; 52 53 const sal_uInt32 OLE_PALETTECOLOR_MASK = 0x0000FFFF; 54 const sal_uInt32 OLE_BGRCOLOR_MASK = 0x00FFFFFF; 55 const sal_uInt32 OLE_SYSTEMCOLOR_MASK = 0x0000FFFF; 56 57 /** Swaps the red and blue component of the passed color. */ 58 inline sal_uInt32 lclSwapRedBlue( sal_uInt32 nColor ) 59 { 60 return static_cast< sal_uInt32 >( (nColor & 0xFF00FF00) | ((nColor & 0x0000FF) << 16) | ((nColor & 0xFF0000) >> 16) ); 61 } 62 63 /** Returns the UNO RGB color from the passed encoded OLE BGR color. */ 64 inline sal_Int32 lclDecodeBgrColor( sal_uInt32 nOleColor ) 65 { 66 return static_cast< sal_Int32 >( lclSwapRedBlue( nOleColor ) & 0xFFFFFF ); 67 } 68 69 // ---------------------------------------------------------------------------- 70 71 const sal_Char* const OLE_GUID_URLMONIKER = "{79EAC9E0-BAF9-11CE-8C82-00AA004BA90B}"; 72 const sal_Char* const OLE_GUID_FILEMONIKER = "{00000303-0000-0000-C000-000000000046}"; 73 74 const sal_uInt32 OLE_STDPIC_ID = 0x0000746C; 75 76 const sal_uInt32 OLE_STDHLINK_VERSION = 2; 77 const sal_uInt32 OLE_STDHLINK_HASTARGET = 0x00000001; /// Has hyperlink moniker. 78 const sal_uInt32 OLE_STDHLINK_ABSOLUTE = 0x00000002; /// Absolute path. 79 const sal_uInt32 OLE_STDHLINK_HASLOCATION = 0x00000008; /// Has target location. 80 const sal_uInt32 OLE_STDHLINK_HASDISPLAY = 0x00000010; /// Has display string. 81 const sal_uInt32 OLE_STDHLINK_HASGUID = 0x00000020; /// Has identification GUID. 82 const sal_uInt32 OLE_STDHLINK_HASTIME = 0x00000040; /// Has creation time. 83 const sal_uInt32 OLE_STDHLINK_HASFRAME = 0x00000080; /// Has frame. 84 const sal_uInt32 OLE_STDHLINK_ASSTRING = 0x00000100; /// Hyperlink as simple string. 85 86 // ---------------------------------------------------------------------------- 87 88 template< typename Type > 89 void lclAppendHex( OUStringBuffer& orBuffer, Type nValue ) 90 { 91 const sal_Int32 nWidth = 2 * sizeof( Type ); 92 static const sal_Unicode spcHexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 93 orBuffer.setLength( orBuffer.getLength() + nWidth ); 94 for( sal_Int32 nCharIdx = orBuffer.getLength() - 1, nCharEnd = nCharIdx - nWidth; nCharIdx > nCharEnd; --nCharIdx, nValue >>= 4 ) 95 orBuffer.setCharAt( nCharIdx, spcHexChars[ nValue & 0xF ] ); 96 } 97 98 OUString lclReadStdHlinkString( BinaryInputStream& rInStrm, bool bUnicode ) 99 { 100 OUString aRet; 101 sal_Int32 nChars = rInStrm.readInt32(); 102 if( nChars > 0 ) 103 { 104 sal_Int32 nReadChars = getLimitedValue< sal_Int32, sal_Int32 >( nChars, 0, SAL_MAX_UINT16 ); 105 // byte strings are always in ANSI (Windows 1252) encoding 106 aRet = bUnicode ? rInStrm.readUnicodeArray( nReadChars, true ) : rInStrm.readCharArrayUC( nReadChars, RTL_TEXTENCODING_MS_1252, true ); 107 // strings are NUL terminated, remove trailing NUL and possible other garbage 108 sal_Int32 nNulPos = aRet.indexOf( '\0' ); 109 if( nNulPos >= 0 ) 110 aRet = aRet.copy( 0, nNulPos ); 111 // skip remaining chars 112 rInStrm.skip( (bUnicode ? 2 : 1) * (nChars - nReadChars) ); 113 } 114 return aRet; 115 } 116 117 } // namespace 118 119 // ============================================================================ 120 121 StdFontInfo::StdFontInfo() : 122 mnHeight( 0 ), 123 mnWeight( OLE_STDFONT_NORMAL ), 124 mnCharSet( WINDOWS_CHARSET_ANSI ), 125 mnFlags( 0 ) 126 { 127 } 128 129 StdFontInfo::StdFontInfo( const ::rtl::OUString& rName, sal_uInt32 nHeight, 130 sal_uInt16 nWeight, sal_uInt16 nCharSet, sal_uInt8 nFlags ) : 131 maName( rName ), 132 mnHeight( nHeight ), 133 mnWeight( nWeight ), 134 mnCharSet( nCharSet ), 135 mnFlags( nFlags ) 136 { 137 } 138 139 // ============================================================================ 140 141 /*static*/ sal_Int32 OleHelper::decodeOleColor( 142 const GraphicHelper& rGraphicHelper, sal_uInt32 nOleColor, bool bDefaultColorBgr ) 143 { 144 static const sal_Int32 spnSystemColors[] = 145 { 146 XML_scrollBar, XML_background, XML_activeCaption, XML_inactiveCaption, 147 XML_menu, XML_window, XML_windowFrame, XML_menuText, 148 XML_windowText, XML_captionText, XML_activeBorder, XML_inactiveBorder, 149 XML_appWorkspace, XML_highlight, XML_highlightText, XML_btnFace, 150 XML_btnShadow, XML_grayText, XML_btnText, XML_inactiveCaptionText, 151 XML_btnHighlight, XML_3dDkShadow, XML_3dLight, XML_infoText, 152 XML_infoBk 153 }; 154 155 switch( nOleColor & OLE_COLORTYPE_MASK ) 156 { 157 case OLE_COLORTYPE_CLIENT: 158 return bDefaultColorBgr ? lclDecodeBgrColor( nOleColor ) : rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK ); 159 160 case OLE_COLORTYPE_PALETTE: 161 return rGraphicHelper.getPaletteColor( nOleColor & OLE_PALETTECOLOR_MASK ); 162 163 case OLE_COLORTYPE_BGR: 164 return lclDecodeBgrColor( nOleColor ); 165 166 case OLE_COLORTYPE_SYSCOLOR: 167 return rGraphicHelper.getSystemColor( STATIC_ARRAY_SELECT( spnSystemColors, nOleColor & OLE_SYSTEMCOLOR_MASK, XML_TOKEN_INVALID ), API_RGB_WHITE ); 168 } 169 OSL_ENSURE( false, "OleHelper::decodeOleColor - unknown color type" ); 170 return API_RGB_BLACK; 171 } 172 173 /*static*/ sal_uInt32 OleHelper::encodeOleColor( sal_Int32 nRgbColor ) 174 { 175 return OLE_COLORTYPE_BGR | lclSwapRedBlue( static_cast< sal_uInt32 >( nRgbColor & 0xFFFFFF ) ); 176 } 177 178 /*static*/ OUString OleHelper::importGuid( BinaryInputStream& rInStrm ) 179 { 180 OUStringBuffer aBuffer; 181 aBuffer.append( sal_Unicode( '{' ) ); 182 lclAppendHex( aBuffer, rInStrm.readuInt32() ); 183 aBuffer.append( sal_Unicode( '-' ) ); 184 lclAppendHex( aBuffer, rInStrm.readuInt16() ); 185 aBuffer.append( sal_Unicode( '-' ) ); 186 lclAppendHex( aBuffer, rInStrm.readuInt16() ); 187 aBuffer.append( sal_Unicode( '-' ) ); 188 lclAppendHex( aBuffer, rInStrm.readuInt8() ); 189 lclAppendHex( aBuffer, rInStrm.readuInt8() ); 190 aBuffer.append( sal_Unicode( '-' ) ); 191 for( int nIndex = 0; nIndex < 6; ++nIndex ) 192 lclAppendHex( aBuffer, rInStrm.readuInt8() ); 193 aBuffer.append( sal_Unicode( '}' ) ); 194 return aBuffer.makeStringAndClear(); 195 } 196 197 /*static*/ bool OleHelper::importStdFont( StdFontInfo& orFontInfo, BinaryInputStream& rInStrm, bool bWithGuid ) 198 { 199 if( bWithGuid ) 200 { 201 bool bIsStdFont = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDFONT ); 202 OSL_ENSURE( bIsStdFont, "OleHelper::importStdFont - unexpected header GUID, expected StdFont" ); 203 if( !bIsStdFont ) 204 return false; 205 } 206 207 sal_uInt8 nVersion, nNameLen; 208 rInStrm >> nVersion >> orFontInfo.mnCharSet >> orFontInfo.mnFlags >> orFontInfo.mnWeight >> orFontInfo.mnHeight >> nNameLen; 209 // according to spec the name is ASCII 210 orFontInfo.maName = rInStrm.readCharArrayUC( nNameLen, RTL_TEXTENCODING_ASCII_US ); 211 OSL_ENSURE( nVersion <= 1, "OleHelper::importStdFont - wrong version" ); 212 return !rInStrm.isEof() && (nVersion <= 1); 213 } 214 215 /*static*/ bool OleHelper::importStdPic( StreamDataSequence& orGraphicData, BinaryInputStream& rInStrm, bool bWithGuid ) 216 { 217 if( bWithGuid ) 218 { 219 bool bIsStdPic = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDPIC ); 220 OSL_ENSURE( bIsStdPic, "OleHelper::importStdPic - unexpected header GUID, expected StdPic" ); 221 if( !bIsStdPic ) 222 return false; 223 } 224 225 sal_uInt32 nStdPicId; 226 sal_Int32 nBytes; 227 rInStrm >> nStdPicId >> nBytes; 228 OSL_ENSURE( nStdPicId == OLE_STDPIC_ID, "OleHelper::importStdPic - unexpected header version" ); 229 return !rInStrm.isEof() && (nStdPicId == OLE_STDPIC_ID) && (nBytes > 0) && (rInStrm.readData( orGraphicData, nBytes ) == nBytes); 230 } 231 232 /*static*/ bool OleHelper::importStdHlink( StdHlinkInfo& orHlinkInfo, BinaryInputStream& rInStrm, bool bWithGuid ) 233 { 234 if( bWithGuid ) 235 { 236 bool bIsStdHlink = importGuid( rInStrm ).equalsAscii( OLE_GUID_STDHLINK ); 237 OSL_ENSURE( bIsStdHlink, "OleHelper::importStdHlink - unexpected header GUID, expected StdHlink" ); 238 if( !bIsStdHlink ) 239 return false; 240 } 241 242 sal_uInt32 nVersion, nFlags; 243 rInStrm >> nVersion >> nFlags; 244 OSL_ENSURE( nVersion == OLE_STDHLINK_VERSION, "OleHelper::importStdHlink - unexpected header version" ); 245 if( rInStrm.isEof() || (nVersion != OLE_STDHLINK_VERSION) ) 246 return false; 247 248 // display string 249 if( getFlag( nFlags, OLE_STDHLINK_HASDISPLAY ) ) 250 orHlinkInfo.maDisplay = lclReadStdHlinkString( rInStrm, true ); 251 // frame string 252 if( getFlag( nFlags, OLE_STDHLINK_HASFRAME ) ) 253 orHlinkInfo.maFrame = lclReadStdHlinkString( rInStrm, true ); 254 255 // target 256 if( getFlag( nFlags, OLE_STDHLINK_HASTARGET ) ) 257 { 258 if( getFlag( nFlags, OLE_STDHLINK_ASSTRING ) ) 259 { 260 OSL_ENSURE( getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - link not absolute" ); 261 orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, true ); 262 } 263 else // hyperlink moniker 264 { 265 OUString aGuid = importGuid( rInStrm ); 266 if( aGuid.equalsAscii( OLE_GUID_FILEMONIKER ) ) 267 { 268 // file name, maybe relative and with directory up-count 269 sal_Int16 nUpLevels; 270 rInStrm >> nUpLevels; 271 OSL_ENSURE( (nUpLevels == 0) || !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ), "OleHelper::importStdHlink - absolute filename with upcount" ); 272 orHlinkInfo.maTarget = lclReadStdHlinkString( rInStrm, false ); 273 rInStrm.skip( 24 ); 274 sal_Int32 nBytes = rInStrm.readInt32(); 275 if( nBytes > 0 ) 276 { 277 sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 ); 278 sal_uInt16 nChars = getLimitedValue< sal_uInt16, sal_Int32 >( rInStrm.readInt32() / 2, 0, SAL_MAX_UINT16 ); 279 rInStrm.skip( 2 ); // key value 280 orHlinkInfo.maTarget = rInStrm.readUnicodeArray( nChars ); // NOT null terminated 281 rInStrm.seek( nEndPos ); 282 } 283 if( !getFlag( nFlags, OLE_STDHLINK_ABSOLUTE ) ) 284 for( sal_Int16 nLevel = 0; nLevel < nUpLevels; ++nLevel ) 285 orHlinkInfo.maTarget = CREATE_OUSTRING( "../" ) + orHlinkInfo.maTarget; 286 } 287 else if( aGuid.equalsAscii( OLE_GUID_URLMONIKER ) ) 288 { 289 // URL, maybe relative and with leading '../' 290 sal_Int32 nBytes = rInStrm.readInt32(); 291 sal_Int64 nEndPos = rInStrm.tell() + ::std::max< sal_Int32 >( nBytes, 0 ); 292 orHlinkInfo.maTarget = rInStrm.readNulUnicodeArray(); 293 rInStrm.seek( nEndPos ); 294 } 295 else 296 { 297 OSL_ENSURE( false, "OleHelper::importStdHlink - unsupported hyperlink moniker" ); 298 return false; 299 } 300 } 301 } 302 303 // target location 304 if( getFlag( nFlags, OLE_STDHLINK_HASLOCATION ) ) 305 orHlinkInfo.maLocation = lclReadStdHlinkString( rInStrm, true ); 306 307 return !rInStrm.isEof(); 308 } 309 310 // ============================================================================ 311 312 } // namespace ole 313 } // namespace oox 314