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/helper/attributelist.hxx"
29 
30 #include <osl/diagnose.h>
31 #include <rtl/ustrbuf.hxx>
32 #include "oox/token/tokenmap.hxx"
33 
34 namespace oox {
35 
36 // ============================================================================
37 
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::util;
40 using namespace ::com::sun::star::xml::sax;
41 
42 using ::rtl::OUString;
43 using ::rtl::OUStringBuffer;
44 
45 // ============================================================================
46 
47 namespace {
48 
49 const sal_Int32 XSTRING_ENCCHAR_LEN     = 7;
50 
51 bool lclAddHexDigit( sal_Unicode& orcChar, sal_Unicode cDigit, int nBitShift )
52 {
53     if( ('0' <= cDigit) && (cDigit <= '9') ) { orcChar |= ((cDigit - '0') << nBitShift); return true; }
54     if( ('a' <= cDigit) && (cDigit <= 'f') ) { orcChar |= ((cDigit - 'a' + 10) << nBitShift); return true; }
55     if( ('A' <= cDigit) && (cDigit <= 'F') ) { orcChar |= ((cDigit - 'A' + 10) << nBitShift); return true; }
56     return false;
57 }
58 
59 sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
60 {
61     sal_Unicode cChar = 0;
62     if( (pcEnd - rpcStr >= XSTRING_ENCCHAR_LEN) &&
63         (rpcStr[ 0 ] == '_') &&
64         (rpcStr[ 1 ] == 'x') &&
65         (rpcStr[ 6 ] == '_') &&
66         lclAddHexDigit( cChar, rpcStr[ 2 ], 12 ) &&
67         lclAddHexDigit( cChar, rpcStr[ 3 ], 8 ) &&
68         lclAddHexDigit( cChar, rpcStr[ 4 ], 4 ) &&
69         lclAddHexDigit( cChar, rpcStr[ 5 ], 0 ) )
70     {
71         rpcStr += XSTRING_ENCCHAR_LEN;
72         return cChar;
73     }
74     return *rpcStr++;
75 }
76 
77 } // namespace
78 
79 // ----------------------------------------------------------------------------
80 
81 sal_Int32 AttributeConversion::decodeToken( const OUString& rValue )
82 {
83     return StaticTokenMap::get().getTokenFromUnicode( rValue );
84 }
85 
86 OUString AttributeConversion::decodeXString( const OUString& rValue )
87 {
88     // string shorter than one encoded character - no need to decode
89     if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
90         return rValue;
91     OUStringBuffer aBuffer;
92     const sal_Unicode* pcStr = rValue.getStr();
93     const sal_Unicode* pcEnd = pcStr + rValue.getLength();
94     while( pcStr < pcEnd )
95         aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
96     return aBuffer.makeStringAndClear();
97 }
98 
99 double AttributeConversion::decodeDouble( const OUString& rValue )
100 {
101     return rValue.toDouble();
102 }
103 
104 sal_Int32 AttributeConversion::decodeInteger( const OUString& rValue )
105 {
106     return rValue.toInt32();
107 }
108 
109 sal_uInt32 AttributeConversion::decodeUnsigned( const OUString& rValue )
110 {
111     return getLimitedValue< sal_uInt32, sal_Int64 >( rValue.toInt64(), 0, SAL_MAX_UINT32 );
112 }
113 
114 sal_Int64 AttributeConversion::decodeHyper( const OUString& rValue )
115 {
116     return rValue.toInt64();
117 }
118 
119 sal_Int32 AttributeConversion::decodeIntegerHex( const OUString& rValue )
120 {
121     return rValue.toInt32( 16 );
122 }
123 
124 sal_uInt32 AttributeConversion::decodeUnsignedHex( const OUString& rValue )
125 {
126     return getLimitedValue< sal_uInt32, sal_Int64 >( rValue.toInt64( 16 ), 0, SAL_MAX_UINT32 );
127 }
128 
129 sal_Int64 AttributeConversion::decodeHyperHex( const OUString& rValue )
130 {
131     return rValue.toInt64( 16 );
132 }
133 
134 // ============================================================================
135 
136 AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
137     mxAttribs( rxAttribs )
138 {
139     OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
140 }
141 
142 bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
143 {
144     return mxAttribs->hasAttribute( nAttrToken );
145 }
146 
147 // optional return values -----------------------------------------------------
148 
149 OptValue< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
150 {
151     sal_Int32 nToken = mxAttribs->getOptionalValueToken( nAttrToken, XML_TOKEN_INVALID );
152     return OptValue< sal_Int32 >( nToken != XML_TOKEN_INVALID, nToken );
153 }
154 
155 OptValue< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
156 {
157     // check if the attribute exists (empty string may be different to missing attribute)
158     if( mxAttribs->hasAttribute( nAttrToken ) )
159         return OptValue< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
160     return OptValue< OUString >();
161 }
162 
163 OptValue< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
164 {
165     // check if the attribute exists (empty string may be different to missing attribute)
166     if( mxAttribs->hasAttribute( nAttrToken ) )
167         return OptValue< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
168     return OptValue< OUString >();
169 }
170 
171 OptValue< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
172 {
173     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
174     bool bValid = aValue.getLength() > 0;
175     return OptValue< double >( bValid, bValid ? AttributeConversion::decodeDouble( aValue ) : 0.0 );
176 }
177 
178 OptValue< sal_Int32 > AttributeList::getInteger( sal_Int32 nAttrToken ) const
179 {
180     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
181     bool bValid = aValue.getLength() > 0;
182     return OptValue< sal_Int32 >( bValid, bValid ? AttributeConversion::decodeInteger( aValue ) : 0 );
183 }
184 
185 OptValue< sal_uInt32 > AttributeList::getUnsigned( sal_Int32 nAttrToken ) const
186 {
187     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
188     bool bValid = aValue.getLength() > 0;
189     return OptValue< sal_uInt32 >( bValid, AttributeConversion::decodeUnsigned( aValue ) );
190 }
191 
192 OptValue< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
193 {
194     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
195     bool bValid = aValue.getLength() > 0;
196     return OptValue< sal_Int64 >( bValid, bValid ? AttributeConversion::decodeHyper( aValue ) : 0 );
197 }
198 
199 OptValue< sal_Int32 > AttributeList::getIntegerHex( sal_Int32 nAttrToken ) const
200 {
201     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
202     bool bValid = aValue.getLength() > 0;
203     return OptValue< sal_Int32 >( bValid, bValid ? AttributeConversion::decodeIntegerHex( aValue ) : 0 );
204 }
205 
206 OptValue< sal_uInt32 > AttributeList::getUnsignedHex( sal_Int32 nAttrToken ) const
207 {
208     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
209     bool bValid = aValue.getLength() > 0;
210     return OptValue< sal_uInt32 >( bValid, bValid ? AttributeConversion::decodeUnsignedHex( aValue ) : 0 );
211 }
212 
213 OptValue< sal_Int64 > AttributeList::getHyperHex( sal_Int32 nAttrToken ) const
214 {
215     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
216     bool bValid = aValue.getLength() > 0;
217     return OptValue< sal_Int64 >( bValid, bValid ? AttributeConversion::decodeHyperHex( aValue ) : 0 );
218 }
219 
220 OptValue< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
221 {
222     // boolean attributes may be "t", "f", "true", "false", "on", "off", "1", or "0"
223     switch( getToken( nAttrToken, XML_TOKEN_INVALID ) )
224     {
225         case XML_t:     return OptValue< bool >( true );  // used in VML
226         case XML_true:  return OptValue< bool >( true );
227         case XML_on:    return OptValue< bool >( true );
228         case XML_f:     return OptValue< bool >( false ); // used in VML
229         case XML_false: return OptValue< bool >( false );
230         case XML_off:   return OptValue< bool >( false );
231     }
232     OptValue< sal_Int32 > onValue = getInteger( nAttrToken );
233     return OptValue< bool >( onValue.has(), onValue.get() != 0 );
234 }
235 
236 OptValue< DateTime > AttributeList::getDateTime( sal_Int32 nAttrToken ) const
237 {
238     OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
239     DateTime aDateTime;
240     bool bValid = (aValue.getLength() == 19) && (aValue[ 4 ] == '-') && (aValue[ 7 ] == '-') &&
241         (aValue[ 10 ] == 'T') && (aValue[ 13 ] == ':') && (aValue[ 16 ] == ':');
242     if( bValid )
243     {
244         aDateTime.Year    = static_cast< sal_uInt16 >( aValue.copy( 0, 4 ).toInt32() );
245         aDateTime.Month   = static_cast< sal_uInt16 >( aValue.copy( 5, 2 ).toInt32() );
246         aDateTime.Day     = static_cast< sal_uInt16 >( aValue.copy( 8, 2 ).toInt32() );
247         aDateTime.Hours   = static_cast< sal_uInt16 >( aValue.copy( 11, 2 ).toInt32() );
248         aDateTime.Minutes = static_cast< sal_uInt16 >( aValue.copy( 14, 2 ).toInt32() );
249         aDateTime.Seconds = static_cast< sal_uInt16 >( aValue.copy( 17, 2 ).toInt32() );
250     }
251     return OptValue< DateTime >( bValid, aDateTime );
252 }
253 
254 // defaulted return values ----------------------------------------------------
255 
256 sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
257 {
258     return mxAttribs->getOptionalValueToken( nAttrToken, nDefault );
259 }
260 
261 OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
262 {
263     try
264     {
265         return mxAttribs->getValue( nAttrToken );
266     }
267     catch( Exception& )
268     {
269     }
270     return rDefault;
271 }
272 
273 OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefault ) const
274 {
275     return getXString( nAttrToken ).get( rDefault );
276 }
277 
278 double AttributeList::getDouble( sal_Int32 nAttrToken, double fDefault ) const
279 {
280     return getDouble( nAttrToken ).get( fDefault );
281 }
282 
283 sal_Int32 AttributeList::getInteger( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
284 {
285     return getInteger( nAttrToken ).get( nDefault );
286 }
287 
288 sal_uInt32 AttributeList::getUnsigned( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
289 {
290     return getUnsigned( nAttrToken ).get( nDefault );
291 }
292 
293 sal_Int64 AttributeList::getHyper( sal_Int32 nAttrToken, sal_Int64 nDefault ) const
294 {
295     return getHyper( nAttrToken ).get( nDefault );
296 }
297 
298 sal_Int32 AttributeList::getIntegerHex( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
299 {
300     return getIntegerHex( nAttrToken ).get( nDefault );
301 }
302 
303 sal_uInt32 AttributeList::getUnsignedHex( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
304 {
305     return getUnsignedHex( nAttrToken ).get( nDefault );
306 }
307 
308 sal_Int64 AttributeList::getHyperHex( sal_Int32 nAttrToken, sal_Int64 nDefault ) const
309 {
310     return getHyperHex( nAttrToken ).get( nDefault );
311 }
312 
313 bool AttributeList::getBool( sal_Int32 nAttrToken, bool bDefault ) const
314 {
315     return getBool( nAttrToken ).get( bDefault );
316 }
317 
318 DateTime AttributeList::getDateTime( sal_Int32 nAttrToken, const DateTime& rDefault ) const
319 {
320     return getDateTime( nAttrToken ).get( rDefault );
321 }
322 
323 // ============================================================================
324 
325 } // namespace oox
326