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 0 : bool lclAddHexDigit( sal_Unicode& orcChar, sal_Unicode cDigit, int nBitShift )
43 : {
44 0 : if( ('0' <= cDigit) && (cDigit <= '9') ) { orcChar |= ((cDigit - '0') << nBitShift); return true; }
45 0 : if( ('a' <= cDigit) && (cDigit <= 'f') ) { orcChar |= ((cDigit - 'a' + 10) << nBitShift); return true; }
46 0 : if( ('A' <= cDigit) && (cDigit <= 'F') ) { orcChar |= ((cDigit - 'A' + 10) << nBitShift); return true; }
47 0 : return false;
48 : }
49 :
50 0 : sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
51 : {
52 0 : sal_Unicode cChar = 0;
53 0 : if( (pcEnd - rpcStr >= XSTRING_ENCCHAR_LEN) &&
54 0 : (rpcStr[ 0 ] == '_') &&
55 0 : (rpcStr[ 1 ] == 'x') &&
56 0 : (rpcStr[ 6 ] == '_') &&
57 0 : lclAddHexDigit( cChar, rpcStr[ 2 ], 12 ) &&
58 0 : lclAddHexDigit( cChar, rpcStr[ 3 ], 8 ) &&
59 0 : lclAddHexDigit( cChar, rpcStr[ 4 ], 4 ) &&
60 0 : lclAddHexDigit( cChar, rpcStr[ 5 ], 0 ) )
61 : {
62 0 : rpcStr += XSTRING_ENCCHAR_LEN;
63 0 : return cChar;
64 : }
65 0 : return *rpcStr++;
66 : }
67 :
68 : } // namespace
69 :
70 :
71 :
72 0 : sal_Int32 AttributeConversion::decodeToken( const OUString& rValue )
73 : {
74 0 : return StaticTokenMap::get().getTokenFromUnicode( rValue );
75 : }
76 :
77 0 : OUString AttributeConversion::decodeXString( const OUString& rValue )
78 : {
79 : // string shorter than one encoded character - no need to decode
80 0 : if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
81 0 : return rValue;
82 0 : OUStringBuffer aBuffer;
83 0 : const sal_Unicode* pcStr = rValue.getStr();
84 0 : const sal_Unicode* pcEnd = pcStr + rValue.getLength();
85 0 : while( pcStr < pcEnd )
86 0 : aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
87 0 : return aBuffer.makeStringAndClear();
88 : }
89 :
90 0 : sal_Int32 AttributeConversion::decodeInteger( const OUString& rValue )
91 : {
92 0 : return rValue.toInt32();
93 : }
94 :
95 0 : sal_uInt32 AttributeConversion::decodeUnsigned( const OUString& rValue )
96 : {
97 0 : 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 0 : 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 0 : 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 0 : AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
117 : mxAttribs( rxAttribs ),
118 0 : mpAttribList( NULL )
119 : {
120 : OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
121 0 : }
122 :
123 0 : sax_fastparser::FastAttributeList *AttributeList::getAttribList() const
124 : {
125 0 : if( mpAttribList == NULL )
126 : {
127 : assert( dynamic_cast< sax_fastparser::FastAttributeList *>( mxAttribs.get() ) != NULL );
128 0 : mpAttribList = static_cast< sax_fastparser::FastAttributeList *>( mxAttribs.get() );
129 : }
130 0 : return mpAttribList;
131 : }
132 :
133 0 : bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
134 : {
135 0 : return mxAttribs->hasAttribute( nAttrToken );
136 : }
137 :
138 : // optional return values -----------------------------------------------------
139 :
140 0 : OptValue< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
141 : {
142 0 : sal_Int32 nToken = mxAttribs->getOptionalValueToken( nAttrToken, XML_TOKEN_INVALID );
143 0 : return OptValue< sal_Int32 >( nToken != XML_TOKEN_INVALID, nToken );
144 : }
145 :
146 0 : OptValue< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
147 : {
148 : // check if the attribute exists (empty string may be different to missing attribute)
149 0 : if( mxAttribs->hasAttribute( nAttrToken ) )
150 0 : return OptValue< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
151 0 : return OptValue< OUString >();
152 : }
153 :
154 0 : OptValue< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
155 : {
156 : // check if the attribute exists (empty string may be different to missing attribute)
157 0 : if( mxAttribs->hasAttribute( nAttrToken ) )
158 0 : return OptValue< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
159 0 : return OptValue< OUString >();
160 : }
161 :
162 0 : OptValue< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
163 : {
164 : double nValue;
165 0 : bool bValid = getAttribList()->getAsDouble( nAttrToken, nValue );
166 0 : return OptValue< double >( bValid, nValue );
167 : }
168 :
169 0 : OptValue< sal_Int32 > AttributeList::getInteger( sal_Int32 nAttrToken ) const
170 : {
171 : sal_Int32 nValue;
172 0 : bool bValid = getAttribList()->getAsInteger( nAttrToken, nValue );
173 0 : return OptValue< sal_Int32 >( bValid, nValue );
174 : }
175 :
176 0 : OptValue< sal_uInt32 > AttributeList::getUnsigned( sal_Int32 nAttrToken ) const
177 : {
178 0 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
179 0 : bool bValid = !aValue.isEmpty();
180 0 : 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 0 : OptValue< sal_Int32 > AttributeList::getIntegerHex( sal_Int32 nAttrToken ) const
191 : {
192 0 : OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
193 0 : bool bValid = !aValue.isEmpty();
194 0 : return OptValue< sal_Int32 >( bValid, bValid ? AttributeConversion::decodeIntegerHex( aValue ) : 0 );
195 : }
196 :
197 0 : 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 0 : bool bHasAttr = getAttribList()->getAsChar( nAttrToken, pAttr );
203 0 : if( !bHasAttr )
204 0 : return OptValue< bool >();
205 0 : if( !strcmp( pAttr, "false" ) )
206 0 : return OptValue< bool >( false );
207 0 : if( !strcmp( pAttr, "true" ) )
208 0 : 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 0 : 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 0 : OptValue< sal_Int32 > onValue = getInteger( nAttrToken );
223 0 : 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 0 : sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
247 : {
248 0 : return mxAttribs->getOptionalValueToken( nAttrToken, nDefault );
249 : }
250 :
251 0 : OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
252 : {
253 : // try to avoid slow exception throw/catch if we can
254 0 : if (rDefault.isEmpty())
255 0 : return mxAttribs->getOptionalValue( nAttrToken );
256 :
257 : try
258 : {
259 0 : return mxAttribs->getValue( nAttrToken );
260 : }
261 0 : catch( Exception& )
262 : {
263 : }
264 0 : return rDefault;
265 : }
266 :
267 0 : OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefault ) const
268 : {
269 0 : return getXString( nAttrToken ).get( rDefault );
270 : }
271 :
272 0 : const char* AttributeList::getChar( sal_Int32 nAttrToken ) const
273 : {
274 0 : const char* p = NULL;
275 0 : bool bValid = getAttribList()->getAsChar(nAttrToken, p);
276 0 : if (!bValid)
277 0 : p = NULL;
278 :
279 0 : return p;
280 : }
281 :
282 0 : double AttributeList::getDouble( sal_Int32 nAttrToken, double fDefault ) const
283 : {
284 0 : return getDouble( nAttrToken ).get( fDefault );
285 : }
286 :
287 0 : sal_Int32 AttributeList::getInteger( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
288 : {
289 0 : return getInteger( nAttrToken ).get( nDefault );
290 : }
291 :
292 0 : sal_uInt32 AttributeList::getUnsigned( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
293 : {
294 0 : 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 0 : sal_Int32 AttributeList::getIntegerHex( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
303 : {
304 0 : return getIntegerHex( nAttrToken ).get( nDefault );
305 : }
306 :
307 0 : bool AttributeList::getBool( sal_Int32 nAttrToken, bool bDefault ) const
308 : {
309 0 : 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: */
|