LibreOffice Module oox (master)  1
attributelist.cxx
Go to the documentation of this file.
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 
21 
22 #include <osl/diagnose.h>
23 #include <rtl/ustrbuf.hxx>
24 #include <sax/fastattribs.hxx>
25 #include <oox/token/tokenmap.hxx>
26 
27 namespace oox {
28 
29 using namespace ::com::sun::star;
30 using namespace ::com::sun::star::uno;
31 using namespace ::com::sun::star::xml::sax;
32 
33 namespace {
34 
35 const sal_Int32 XSTRING_ENCCHAR_LEN = 7;
36 
37 bool lclAddHexDigit( sal_Unicode& orcChar, sal_Unicode cDigit, int nBitShift )
38 {
39  if( ('0' <= cDigit) && (cDigit <= '9') ) { orcChar |= ((cDigit - '0') << nBitShift); return true; }
40  if( ('a' <= cDigit) && (cDigit <= 'f') ) { orcChar |= ((cDigit - 'a' + 10) << nBitShift); return true; }
41  if( ('A' <= cDigit) && (cDigit <= 'F') ) { orcChar |= ((cDigit - 'A' + 10) << nBitShift); return true; }
42  return false;
43 }
44 
45 sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
46 {
47  sal_Unicode cChar = 0;
48  if( (pcEnd - rpcStr >= XSTRING_ENCCHAR_LEN) &&
49  (rpcStr[ 0 ] == '_') &&
50  (rpcStr[ 1 ] == 'x') &&
51  (rpcStr[ 6 ] == '_') &&
52  lclAddHexDigit( cChar, rpcStr[ 2 ], 12 ) &&
53  lclAddHexDigit( cChar, rpcStr[ 3 ], 8 ) &&
54  lclAddHexDigit( cChar, rpcStr[ 4 ], 4 ) &&
55  lclAddHexDigit( cChar, rpcStr[ 5 ], 0 ) )
56  {
57  rpcStr += XSTRING_ENCCHAR_LEN;
58  return cChar;
59  }
60  return *rpcStr++;
61 }
62 
63 } // namespace
64 
65 #define STRING_TO_TOKEN(color) if (sColorName == u"" #color) return XML_##color
66 sal_Int32 getHighlightColorTokenFromString(std::u16string_view sColorName)
67 {
68  STRING_TO_TOKEN(black);
69  STRING_TO_TOKEN(blue);
70  STRING_TO_TOKEN(cyan);
71  STRING_TO_TOKEN(darkBlue);
72  STRING_TO_TOKEN(darkCyan);
73  STRING_TO_TOKEN(darkGreen);
74  STRING_TO_TOKEN(darkMagenta);
75  STRING_TO_TOKEN(darkRed);
76  STRING_TO_TOKEN(darkYellow);
77  STRING_TO_TOKEN(darkGray);
78  STRING_TO_TOKEN(green);
79  STRING_TO_TOKEN(lightGray);
80  STRING_TO_TOKEN(magenta);
81  STRING_TO_TOKEN(red);
82  STRING_TO_TOKEN(white);
83  STRING_TO_TOKEN(yellow);
85 
86  return XML_TOKEN_INVALID;
87 }
88 
89 sal_Int32 AttributeConversion::decodeToken( std::u16string_view rValue )
90 {
91  return TokenMap::getTokenFromUnicode( rValue );
92 }
93 
94 OUString AttributeConversion::decodeXString( const OUString& rValue )
95 {
96  // string shorter than one encoded character - no need to decode
97  if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
98  return rValue;
99  OUStringBuffer aBuffer;
100  const sal_Unicode* pcStr = rValue.getStr();
101  const sal_Unicode* pcEnd = pcStr + rValue.getLength();
102  while( pcStr < pcEnd )
103  aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
104  return aBuffer.makeStringAndClear();
105 }
106 
107 sal_Int32 AttributeConversion::decodeInteger( const OUString& rValue )
108 {
109  return rValue.toInt32();
110 }
111 
112 sal_uInt32 AttributeConversion::decodeUnsigned( const OUString& rValue )
113 {
114  return getLimitedValue< sal_uInt32, sal_Int64 >( rValue.toInt64(), 0, SAL_MAX_UINT32 );
115 }
116 
117 sal_Int64 AttributeConversion::decodeHyper( const OUString& rValue )
118 {
119  return rValue.toInt64();
120 }
121 
122 sal_Int32 AttributeConversion::decodeIntegerHex( const OUString& rValue )
123 {
124  // It looks like all Office Open XML attributes containing hexadecimal
125  // values are based on xsd:hexBinary and so use an unsigned representation:
126  return static_cast< sal_Int32 >(rValue.toUInt32( 16 ));
127  //TODO: Change this function to return sal_uInt32 and get rid of the
128  // cast, but that will have a ripple effect
129 }
130 
131 AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
132  mxAttribs( rxAttribs ),
133  mpAttribList( nullptr )
134 {
135  OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
136 }
137 
139 {
140  if( mpAttribList == nullptr )
141  {
143  }
144  return mpAttribList;
145 }
146 
147 bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
148 {
149  return mxAttribs->hasAttribute( nAttrToken );
150 }
151 
153 {
154  OUString sColorVal = mxAttribs->getValue(nAttrToken);
155  oox::drawingml::Color aColor;
157  return aColor;
158 }
159 
160 // optional return values -----------------------------------------------------
161 
162 OptValue< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
163 {
164  sal_Int32 nToken = mxAttribs->getOptionalValueToken( nAttrToken, XML_TOKEN_INVALID );
165  return OptValue< sal_Int32 >( nToken != XML_TOKEN_INVALID, nToken );
166 }
167 
168 OptValue< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
169 {
170  // check if the attribute exists (empty string may be different to missing attribute)
171  if( mxAttribs->hasAttribute( nAttrToken ) )
172  return OptValue< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
173  return OptValue< OUString >();
174 }
175 
176 OptValue< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
177 {
178  // check if the attribute exists (empty string may be different to missing attribute)
179  if( mxAttribs->hasAttribute( nAttrToken ) )
180  return OptValue< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
181  return OptValue< OUString >();
182 }
183 
184 OptValue< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
185 {
186  double nValue;
187  bool bValid = getAttribList()->getAsDouble( nAttrToken, nValue );
188  return OptValue< double >( bValid, nValue );
189 }
190 
192 {
193  sal_Int32 nValue;
194  bool bValid = getAttribList()->getAsInteger( nAttrToken, nValue );
195  return OptValue< sal_Int32 >( bValid, nValue );
196 }
197 
199 {
200  OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
201  bool bValid = !aValue.isEmpty();
203 }
204 
205 OptValue< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
206 {
207  OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
208  bool bValid = !aValue.isEmpty();
209  return OptValue< sal_Int64 >( bValid, bValid ? AttributeConversion::decodeHyper( aValue ) : 0 );
210 }
211 
213 {
214  OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
215  bool bValid = !aValue.isEmpty();
216  return OptValue< sal_Int32 >( bValid, bValid ? AttributeConversion::decodeIntegerHex( aValue ) : 0 );
217 }
218 
219 OptValue< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
220 {
221  const char *pAttr;
222 
223  // catch the common cases as quickly as possible first
224  bool bHasAttr = getAttribList()->getAsChar( nAttrToken, pAttr );
225  if( !bHasAttr )
226  return OptValue< bool >();
227  if( !strcmp( pAttr, "false" ) )
228  return OptValue< bool >( false );
229  if( !strcmp( pAttr, "true" ) )
230  return OptValue< bool >( true );
231 
232  // now for all the crazy stuff
233 
234  // boolean attributes may be "t", "f", "true", "false", "on", "off", "1", or "0"
235  switch( getToken( nAttrToken, XML_TOKEN_INVALID ) )
236  {
237  case XML_t: return OptValue< bool >( true ); // used in VML
238  case XML_true: return OptValue< bool >( true );
239  case XML_on: return OptValue< bool >( true );
240  case XML_f: return OptValue< bool >( false ); // used in VML
241  case XML_false: return OptValue< bool >( false );
242  case XML_off: return OptValue< bool >( false );
243  }
244  OptValue< sal_Int32 > onValue = getInteger( nAttrToken );
245  return OptValue< bool >( onValue.has(), onValue.get() != 0 );
246 }
247 
249 {
250  OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
251  util::DateTime aDateTime;
252  bool bValid = (aValue.getLength() == 19) && (aValue[ 4 ] == '-') && (aValue[ 7 ] == '-') &&
253  (aValue[ 10 ] == 'T') && (aValue[ 13 ] == ':') && (aValue[ 16 ] == ':');
254  if( bValid )
255  {
256  aDateTime.Year = static_cast< sal_uInt16 >( aValue.copy( 0, 4 ).toInt32() );
257  aDateTime.Month = static_cast< sal_uInt16 >( aValue.copy( 5, 2 ).toInt32() );
258  aDateTime.Day = static_cast< sal_uInt16 >( aValue.copy( 8, 2 ).toInt32() );
259  aDateTime.Hours = static_cast< sal_uInt16 >( aValue.copy( 11, 2 ).toInt32() );
260  aDateTime.Minutes = static_cast< sal_uInt16 >( aValue.copy( 14, 2 ).toInt32() );
261  aDateTime.Seconds = static_cast< sal_uInt16 >( aValue.copy( 17, 2 ).toInt32() );
262  }
263  return OptValue< util::DateTime >( bValid, aDateTime );
264 }
265 
266 // defaulted return values ----------------------------------------------------
267 
268 sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
269 {
270  return mxAttribs->getOptionalValueToken( nAttrToken, nDefault );
271 }
272 
273 OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
274 {
275  // try to avoid slow exception throw/catch if we can
276  if (rDefault.isEmpty())
277  return mxAttribs->getOptionalValue( nAttrToken );
278 
279  try
280  {
281  return mxAttribs->getValue( nAttrToken );
282  }
283  catch( Exception& )
284  {
285  }
286  return rDefault;
287 }
288 
289 OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefault ) const
290 {
291  return getXString( nAttrToken ).get( rDefault );
292 }
293 
294 const char* AttributeList::getChar( sal_Int32 nAttrToken ) const
295 {
296  const char* p = nullptr;
297  bool bValid = getAttribList()->getAsChar(nAttrToken, p);
298  if (!bValid)
299  p = nullptr;
300 
301  return p;
302 }
303 
304 double AttributeList::getDouble( sal_Int32 nAttrToken, double fDefault ) const
305 {
306  return getDouble( nAttrToken ).get( fDefault );
307 }
308 
309 sal_Int32 AttributeList::getInteger( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
310 {
311  return getInteger( nAttrToken ).get( nDefault );
312 }
313 
314 sal_uInt32 AttributeList::getUnsigned( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
315 {
316  return getUnsigned( nAttrToken ).get( nDefault );
317 }
318 
319 sal_Int64 AttributeList::getHyper( sal_Int32 nAttrToken, sal_Int64 nDefault ) const
320 {
321  return getHyper( nAttrToken ).get( nDefault );
322 }
323 
324 sal_Int32 AttributeList::getIntegerHex( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
325 {
326  return getIntegerHex( nAttrToken ).get( nDefault );
327 }
328 
329 sal_uInt32 AttributeList::getUnsignedHex( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
330 {
331  return getIntegerHex( nAttrToken ).get( nDefault );
332 }
333 
334 bool AttributeList::getBool( sal_Int32 nAttrToken, bool bDefault ) const
335 {
336  return getBool( nAttrToken ).get( bDefault );
337 }
338 
339 util::DateTime AttributeList::getDateTime( sal_Int32 nAttrToken, const util::DateTime& rDefault ) const
340 {
341  return getDateTime( nAttrToken ).get( rDefault );
342 }
343 
344 std::vector<sal_Int32> AttributeList::getTokenList(sal_Int32 nAttrToken) const
345 {
346  std::vector<sal_Int32> aValues;
347  OUString sValue = getString(nAttrToken, "");
348  sal_Int32 nIndex = 0;
349  do
350  {
351  aValues.push_back(AttributeConversion::decodeToken(sValue.getToken(0, ' ', nIndex)));
352  } while (nIndex >= 0);
353 
354  return aValues;
355 }
356 
357 } // namespace oox
358 
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 nIndex
OptValue< bool > getBool(sal_Int32 nAttrToken) const
Returns the boolean value of the specified attribute.
void setHighlight(sal_Int32 nToken)
Sets a predefined color from the w:highlight element.
Definition: color.cxx:297
OptValue< OUString > getXString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
static OUString decodeXString(const OUString &rValue)
Returns the decoded string value.
OptValue< sal_Int32 > getInteger(sal_Int32 nAttrToken) const
Returns the 32-bit signed integer value of the specified attribute (decimal).
css::uno::Reference< css::xml::sax::XFastAttributeList > mxAttribs
AttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &rxAttribs)
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
OptValue< double > getDouble(sal_Int32 nAttrToken) const
Returns the double value of the specified attribute.
OptValue< OUString > getString(sal_Int32 nAttrToken) const
Returns the string value of the specified attribute.
#define SAL_MAX_UINT32
oox::drawingml::Color getHighlightColor(sal_Int32 nAttrToken) const
Returns the Color object of highlight of the text.
sal_uInt16 sal_Unicode
sal_uInt32 getUnsignedHex(sal_Int32 nAttrToken, sal_uInt32 nDefault) const
bool hasAttribute(sal_Int32 nAttrToken) const
Returns true, if the specified attribute is present.
const Type & get() const
Definition: helper.hxx:185
OptValue< css::util::DateTime > getDateTime(sal_Int32 nAttrToken) const
Returns the date/time value of the specified attribute.
sal_Int32 getHighlightColorTokenFromString(std::u16string_view sColorName)
OptValue< sal_uInt32 > getUnsigned(sal_Int32 nAttrToken) const
Returns the 32-bit unsigned integer value of the specified attribute (decimal).
#define STRING_TO_TOKEN(color)
static sal_Int32 getTokenFromUnicode(std::u16string_view rUnicodeName)
Returns the token identifier for the passed Unicode token name.
Definition: tokenmap.cxx:77
OptValue< sal_Int64 > getHyper(sal_Int32 nAttrToken) const
Returns the 64-bit signed integer value of the specified attribute (decimal).
sax_fastparser::FastAttributeList * mpAttribList
none
static sal_Int32 decodeToken(std::u16string_view rValue)
Returns the XML token identifier from the passed string.
XML_TOKEN_INVALID
const char * getChar(sal_Int32 nAttrToken) const
bool getAsInteger(sal_Int32 nToken, sal_Int32 &rInt) const
DefTokenId nToken
std::unique_ptr< char[]> aBuffer
OptValue< sal_Int32 > getIntegerHex(sal_Int32 nAttrToken) const
Returns the 32-bit signed integer value of the specified attribute (hexadecimal). ...
bool getAsDouble(sal_Int32 nToken, double &rDouble) const
static sal_Int32 decodeInteger(const OUString &rValue)
Returns the 32-bit signed integer value from the passed string (decimal).
sax_fastparser::FastAttributeList * getAttribList() const
void * p
std::vector< sal_Int32 > getTokenList(sal_Int32 nAttrToken) const
bool getAsChar(sal_Int32 nToken, const char *&rPos) const
static sal_Int64 decodeHyper(const OUString &rValue)
Returns the 64-bit signed integer value from the passed string (decimal).
bool has() const
Definition: helper.hxx:181
static sal_uInt32 decodeUnsigned(const OUString &rValue)
Returns the 32-bit unsigned integer value from the passed string (decimal).
static sal_Int32 decodeIntegerHex(const OUString &rValue)
Returns the 32-bit signed integer value from the passed string (hexadecimal).
OptValue< sal_Int32 > getToken(sal_Int32 nAttrToken) const
Returns the token identifier of the value of the specified attribute.
sal_Int16 nValue