xref: /aoo42x/main/oox/source/ole/olehelper.cxx (revision cdf0e10c)
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