Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "oox/helper/attributelist.hxx"
21 :
22 : #include <cassert>
23 : #include <osl/diagnose.h>
24 : #include <rtl/ustrbuf.hxx>
25 : #include <sax/fastattribs.hxx>
26 : #include "oox/token/tokenmap.hxx"
27 :
28 : namespace oox {
29 :
30 :
31 :
32 : using namespace ::com::sun::star;
33 : using namespace ::com::sun::star::uno;
34 : using namespace ::com::sun::star::xml::sax;
35 :
36 :
37 :
38 : namespace {
39 :
40 : const sal_Int32 XSTRING_ENCCHAR_LEN = 7;
41 :
42 3409 : bool lclAddHexDigit( sal_Unicode& orcChar, sal_Unicode cDigit, int nBitShift )
43 : {
44 3409 : if( ('0' <= cDigit) && (cDigit <= '9') ) { orcChar |= ((cDigit - '0') << nBitShift); return true; }
45 1 : if( ('a' <= cDigit) && (cDigit <= 'f') ) { orcChar |= ((cDigit - 'a' + 10) << nBitShift); return true; }
46 1 : if( ('A' <= cDigit) && (cDigit <= 'F') ) { orcChar |= ((cDigit - 'A' + 10) << nBitShift); return true; }
47 1 : return false;
48 : }
49 :
50 13463 : sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
51 : {
52 13463 : sal_Unicode cChar = 0;
53 32936 : if( (pcEnd - rpcStr >= XSTRING_ENCCHAR_LEN) &&
54 6867 : (rpcStr[ 0 ] == '_') &&
55 1711 : (rpcStr[ 1 ] == 'x') &&
56 1707 : (rpcStr[ 6 ] == '_') &&
57 1705 : lclAddHexDigit( cChar, rpcStr[ 2 ], 12 ) &&
58 1704 : lclAddHexDigit( cChar, rpcStr[ 3 ], 8 ) &&
59 15167 : lclAddHexDigit( cChar, rpcStr[ 4 ], 4 ) &&
60 852 : lclAddHexDigit( cChar, rpcStr[ 5 ], 0 ) )
61 : {
62 852 : rpcStr += XSTRING_ENCCHAR_LEN;
63 852 : return cChar;
64 : }
65 12611 : return *rpcStr++;
66 : }
67 :
68 : } // namespace
69 :
70 :
71 :
72 27537 : sal_Int32 AttributeConversion::decodeToken( const OUString& rValue )
73 : {
74 27537 : return StaticTokenMap::get().getTokenFromUnicode( rValue );
75 : }
76 :
77 1827 : OUString AttributeConversion::decodeXString( const OUString& rValue )
78 : {
79 : // string shorter than one encoded character - no need to decode
80 1827 : if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
81 363 : return rValue;
82 1464 : OUStringBuffer aBuffer;
83 1464 : const sal_Unicode* pcStr = rValue.getStr();
84 1464 : const sal_Unicode* pcEnd = pcStr + rValue.getLength();
85 16391 : while( pcStr < pcEnd )
86 13463 : aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
87 1464 : return aBuffer.makeStringAndClear();
88 : }
89 :
90 0 : sal_Int32 AttributeConversion::decodeInteger( const OUString& rValue )
91 : {
92 0 : return rValue.toInt32();
93 : }
94 :
95 47 : sal_uInt32 AttributeConversion::decodeUnsigned( const OUString& rValue )
96 : {
97 47 : return getLimitedValue< sal_uInt32, sal_Int64 >( rValue.toInt64(), 0, SAL_MAX_UINT32 );
98 : }
99 :
100 0 : sal_Int64 AttributeConversion::decodeHyper( const OUString& rValue )
101 : {
102 0 : return rValue.toInt64();
103 : }
104 :
105 15057 : sal_Int32 AttributeConversion::decodeIntegerHex( const OUString& rValue )
106 : {
107 : // It looks like all Office Open XML attributes containing hexadecimal
108 : // values are based on xsd:hexBinary and so use an unsigned representation:
109 15057 : return static_cast< sal_Int32 >(rValue.toUInt32( 16 ));
110 : //TODO: Change this function to return sal_uInt32 and get rid of the
111 : // cast, but that will have a ripple effect
112 : }
113 :
114 :
115 :
116 475535 : AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
117 : mxAttribs( rxAttribs ),
118 475535 : mpAttribList( NULL )
119 : {
120 : OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
121 475535 : }
122 :
123 155467 : sax_fastparser::FastAttributeList *AttributeList::getAttribList() const
124 : {
125 155467 : if( mpAttribList == NULL )
126 : {
127 : assert( dynamic_cast< sax_fastparser::FastAttributeList *>( mxAttribs.get() ) != NULL );
128 80850 : mpAttribList = static_cast< sax_fastparser::FastAttributeList *>( mxAttribs.get() );
129 : }
130 155467 : return mpAttribList;
131 : }
132 :
133 57558 : bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
134 : {
135 57558 : return mxAttribs->hasAttribute( nAttrToken );
136 : }
137 :
138 : // optional return values -----------------------------------------------------
139 :
140 20487 : OptValue< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
141 : {
142 20487 : sal_Int32 nToken = mxAttribs->getOptionalValueToken( nAttrToken, XML_TOKEN_INVALID );
143 20487 : return OptValue< sal_Int32 >( nToken != XML_TOKEN_INVALID, nToken );
144 : }
145 :
146 82157 : OptValue< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
147 : {
148 : // check if the attribute exists (empty string may be different to missing attribute)
149 82157 : if( mxAttribs->hasAttribute( nAttrToken ) )
150 67640 : return OptValue< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
151 14517 : return OptValue< OUString >();
152 : }
153 :
154 2181 : OptValue< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
155 : {
156 : // check if the attribute exists (empty string may be different to missing attribute)
157 2181 : if( mxAttribs->hasAttribute( nAttrToken ) )
158 1737 : return OptValue< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
159 444 : return OptValue< OUString >();
160 : }
161 :
162 10831 : OptValue< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
163 : {
164 : double nValue;
165 10831 : bool bValid = getAttribList()->getAsDouble( nAttrToken, nValue );
166 10831 : return OptValue< double >( bValid, nValue );
167 : }
168 :
169 105536 : OptValue< sal_Int32 > AttributeList::getInteger( sal_Int32 nAttrToken ) const
170 : {
171 : sal_Int32 nValue;
172 105536 : bool bValid = getAttribList()->getAsInteger( nAttrToken, nValue );
173 105536 : return OptValue< sal_Int32 >( bValid, nValue );
174 : }
175 :
176 47 : OptValue< sal_uInt32 > AttributeList::getUnsigned( sal_Int32 nAttrToken ) const
177 : {
178 47 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
179 47 : bool bValid = !aValue.isEmpty();
180 47 : return OptValue< sal_uInt32 >( bValid, AttributeConversion::decodeUnsigned( aValue ) );
181 : }
182 :
183 0 : OptValue< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
184 : {
185 0 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
186 0 : bool bValid = !aValue.isEmpty();
187 0 : return OptValue< sal_Int64 >( bValid, bValid ? AttributeConversion::decodeHyper( aValue ) : 0 );
188 : }
189 :
190 15064 : OptValue< sal_Int32 > AttributeList::getIntegerHex( sal_Int32 nAttrToken ) const
191 : {
192 15064 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
193 15064 : bool bValid = !aValue.isEmpty();
194 15064 : return OptValue< sal_Int32 >( bValid, bValid ? AttributeConversion::decodeIntegerHex( aValue ) : 0 );
195 : }
196 :
197 37123 : OptValue< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
198 : {
199 : const char *pAttr;
200 :
201 : // catch the common cases as quickly as possible first
202 37123 : bool bHasAttr = getAttribList()->getAsChar( nAttrToken, pAttr );
203 37123 : if( !bHasAttr )
204 22789 : return OptValue< bool >();
205 14334 : if( !strcmp( pAttr, "false" ) )
206 3642 : return OptValue< bool >( false );
207 10692 : if( !strcmp( pAttr, "true" ) )
208 993 : return OptValue< bool >( true );
209 :
210 : // now for all the crazy stuff
211 :
212 : // boolean attributes may be "t", "f", "true", "false", "on", "off", "1", or "0"
213 9699 : switch( getToken( nAttrToken, XML_TOKEN_INVALID ) )
214 : {
215 0 : case XML_t: return OptValue< bool >( true ); // used in VML
216 0 : case XML_true: return OptValue< bool >( true );
217 0 : case XML_on: return OptValue< bool >( true );
218 0 : case XML_f: return OptValue< bool >( false ); // used in VML
219 0 : case XML_false: return OptValue< bool >( false );
220 0 : case XML_off: return OptValue< bool >( false );
221 : }
222 9699 : OptValue< sal_Int32 > onValue = getInteger( nAttrToken );
223 9699 : return OptValue< bool >( onValue.has(), onValue.get() != 0 );
224 : }
225 :
226 0 : OptValue< util::DateTime > AttributeList::getDateTime( sal_Int32 nAttrToken ) const
227 : {
228 0 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
229 0 : util::DateTime aDateTime;
230 0 : bool bValid = (aValue.getLength() == 19) && (aValue[ 4 ] == '-') && (aValue[ 7 ] == '-') &&
231 0 : (aValue[ 10 ] == 'T') && (aValue[ 13 ] == ':') && (aValue[ 16 ] == ':');
232 0 : if( bValid )
233 : {
234 0 : aDateTime.Year = static_cast< sal_uInt16 >( aValue.copy( 0, 4 ).toInt32() );
235 0 : aDateTime.Month = static_cast< sal_uInt16 >( aValue.copy( 5, 2 ).toInt32() );
236 0 : aDateTime.Day = static_cast< sal_uInt16 >( aValue.copy( 8, 2 ).toInt32() );
237 0 : aDateTime.Hours = static_cast< sal_uInt16 >( aValue.copy( 11, 2 ).toInt32() );
238 0 : aDateTime.Minutes = static_cast< sal_uInt16 >( aValue.copy( 14, 2 ).toInt32() );
239 0 : aDateTime.Seconds = static_cast< sal_uInt16 >( aValue.copy( 17, 2 ).toInt32() );
240 : }
241 0 : return OptValue< util::DateTime >( bValid, aDateTime );
242 : }
243 :
244 : // defaulted return values ----------------------------------------------------
245 :
246 219890 : sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
247 : {
248 219890 : return mxAttribs->getOptionalValueToken( nAttrToken, nDefault );
249 : }
250 :
251 76175 : OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
252 : {
253 : // try to avoid slow exception throw/catch if we can
254 76175 : if (rDefault.isEmpty())
255 76122 : return mxAttribs->getOptionalValue( nAttrToken );
256 :
257 : try
258 : {
259 53 : return mxAttribs->getValue( nAttrToken );
260 : }
261 8 : catch( Exception& )
262 : {
263 : }
264 8 : return rDefault;
265 : }
266 :
267 2179 : OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefault ) const
268 : {
269 2179 : return getXString( nAttrToken ).get( rDefault );
270 : }
271 :
272 1977 : const char* AttributeList::getChar( sal_Int32 nAttrToken ) const
273 : {
274 1977 : const char* p = NULL;
275 1977 : bool bValid = getAttribList()->getAsChar(nAttrToken, p);
276 1977 : if (!bValid)
277 3 : p = NULL;
278 :
279 1977 : return p;
280 : }
281 :
282 10831 : double AttributeList::getDouble( sal_Int32 nAttrToken, double fDefault ) const
283 : {
284 10831 : return getDouble( nAttrToken ).get( fDefault );
285 : }
286 :
287 84792 : sal_Int32 AttributeList::getInteger( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
288 : {
289 84792 : return getInteger( nAttrToken ).get( nDefault );
290 : }
291 :
292 47 : sal_uInt32 AttributeList::getUnsigned( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
293 : {
294 47 : return getUnsigned( nAttrToken ).get( nDefault );
295 : }
296 :
297 0 : sal_Int64 AttributeList::getHyper( sal_Int32 nAttrToken, sal_Int64 nDefault ) const
298 : {
299 0 : return getHyper( nAttrToken ).get( nDefault );
300 : }
301 :
302 14956 : sal_Int32 AttributeList::getIntegerHex( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
303 : {
304 14956 : return getIntegerHex( nAttrToken ).get( nDefault );
305 : }
306 :
307 30812 : bool AttributeList::getBool( sal_Int32 nAttrToken, bool bDefault ) const
308 : {
309 30812 : return getBool( nAttrToken ).get( bDefault );
310 : }
311 :
312 0 : util::DateTime AttributeList::getDateTime( sal_Int32 nAttrToken, const util::DateTime& rDefault ) const
313 : {
314 0 : return getDateTime( nAttrToken ).get( rDefault );
315 : }
316 :
317 :
318 :
319 : } // namespace oox
320 :
321 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|