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