LibreOffice Module configmgr (master)  1
valueparser.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 
20 #include <sal/config.h>
21 
22 #include <cassert>
23 
24 #include <com/sun/star/uno/Any.hxx>
25 #include <com/sun/star/uno/RuntimeException.hpp>
26 #include <com/sun/star/uno/Sequence.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <rtl/math.h>
29 #include <rtl/string.h>
30 #include <rtl/string.hxx>
31 #include <rtl/ustring.hxx>
32 #include <sal/types.h>
33 #include <xmlreader/span.hxx>
34 #include <xmlreader/xmlreader.hxx>
35 
36 #include "localizedvaluenode.hxx"
37 #include "node.hxx"
38 #include "nodemap.hxx"
39 #include "parsemanager.hxx"
40 #include "propertynode.hxx"
41 #include "type.hxx"
42 #include "valueparser.hxx"
43 
44 namespace configmgr {
45 
46 namespace {
47 
48 bool parseHexDigit(char c, int * value) {
49  assert(value != nullptr);
50  if (c >= '0' && c <= '9') {
51  *value = c - '0';
52  return true;
53  }
54  if (c >= 'A' && c <= 'F') {
55  *value = c - 'A' + 10;
56  return true;
57  }
58  if (c >= 'a' && c <= 'f') {
59  *value = c - 'a' + 10;
60  return true;
61  }
62  return false;
63 }
64 
65 bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
66  assert(text.is() && value != nullptr);
67  if (text == "true" || text == "1") {
68  *value = true;
69  return true;
70  }
71  if (text == "false" || text == "0") {
72  *value = false;
73  return true;
74  }
75  return false;
76 }
77 
78 bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
79  assert(text.is() && value != nullptr);
80  // For backwards compatibility, support hexadecimal values:
81  sal_Int32 n =
82  rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
83  text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
84  RTL_CONSTASCII_LENGTH("0X")) == 0 ?
85  static_cast< sal_Int32 >(
86  OString(
87  text.begin + RTL_CONSTASCII_LENGTH("0X"),
88  text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
89  OString(text.begin, text.length).toInt32();
90  //TODO: check valid lexical representation
91  if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
92  *value = static_cast< sal_Int16 >(n);
93  return true;
94  }
95  return false;
96 }
97 
98 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
99  assert(text.is() && value != nullptr);
100  // For backwards compatibility, support hexadecimal values:
101  *value =
102  rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
103  text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
104  RTL_CONSTASCII_LENGTH("0X")) == 0 ?
105  static_cast< sal_Int32 >(
106  OString(
107  text.begin + RTL_CONSTASCII_LENGTH("0X"),
108  text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
109  OString(text.begin, text.length).toInt32();
110  //TODO: check valid lexical representation
111  return true;
112 }
113 
114 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
115  assert(text.is() && value != nullptr);
116  // For backwards compatibility, support hexadecimal values:
117  *value =
118  rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
119  text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
120  RTL_CONSTASCII_LENGTH("0X")) == 0 ?
121  static_cast< sal_Int64 >(
122  OString(
123  text.begin + RTL_CONSTASCII_LENGTH("0X"),
124  text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
125  OString(text.begin, text.length).toInt64();
126  //TODO: check valid lexical representation
127  return true;
128 }
129 
130 bool parseValue(xmlreader::Span const & text, double * value) {
131  assert(text.is() && value != nullptr);
132  *value = rtl_math_stringToDouble(
133  text.begin, text.begin + text.length, '.', 0, nullptr, nullptr);
134  //TODO: check valid lexical representation
135  return true;
136 }
137 
138 bool parseValue(xmlreader::Span const & text, OUString * value) {
139  assert(text.is() && value != nullptr);
140  *value = text.convertFromUtf8();
141  return true;
142 }
143 
144 bool parseValue(
145  xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
146 {
147  assert(text.is() && value != nullptr);
148  if ((text.length & 1) != 0) {
149  return false;
150  }
151  std::vector< sal_Int8 > seq;
152  for (sal_Int32 i = 0; i != text.length;) {
153  int n1;
154  int n2;
155  if (!parseHexDigit(text.begin[i++], &n1) ||
156  !parseHexDigit(text.begin[i++], &n2))
157  {
158  return false;
159  }
160  seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
161  }
162  *value = comphelper::containerToSequence(seq);
163  return true;
164 }
165 
166 template< typename T > css::uno::Any parseSingleValue(
167  xmlreader::Span const & text)
168 {
169  T val;
170  if (!parseValue(text, &val)) {
171  throw css::uno::RuntimeException("invalid value");
172  }
173  return css::uno::Any(val);
174 }
175 
176 template< typename T > css::uno::Any parseListValue(
177  OString const & separator, xmlreader::Span const & text)
178 {
179  std::vector< T > seq;
180  xmlreader::Span sep;
181  if (separator.isEmpty()) {
182  sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
183  } else {
184  sep = xmlreader::Span(separator.getStr(), separator.getLength());
185  }
186  if (text.length != 0) {
187  for (xmlreader::Span t(text);;) {
188  sal_Int32 i = rtl_str_indexOfStr_WithLength(
189  t.begin, t.length, sep.begin, sep.length);
190  T val;
191  if (!parseValue(
192  xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
193  {
194  throw css::uno::RuntimeException("invalid value");
195  }
196  seq.push_back(val);
197  if (i < 0) {
198  break;
199  }
200  t.begin += i + sep.length;
201  t.length -= i + sep.length;
202  }
203  }
204  return css::uno::Any(comphelper::containerToSequence(seq));
205 }
206 
207 css::uno::Any parseValue(
208  OString const & separator, xmlreader::Span const & text, Type type)
209 {
210  switch (type) {
211  case TYPE_ANY:
212  throw css::uno::RuntimeException("invalid value of type any");
213  case TYPE_BOOLEAN:
214  return parseSingleValue< sal_Bool >(text);
215  case TYPE_SHORT:
216  return parseSingleValue< sal_Int16 >(text);
217  case TYPE_INT:
218  return parseSingleValue< sal_Int32 >(text);
219  case TYPE_LONG:
220  return parseSingleValue< sal_Int64 >(text);
221  case TYPE_DOUBLE:
222  return parseSingleValue< double >(text);
223  case TYPE_STRING:
224  return parseSingleValue< OUString >(text);
225  case TYPE_HEXBINARY:
226  return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
227  case TYPE_BOOLEAN_LIST:
228  return parseListValue< sal_Bool >(separator, text);
229  case TYPE_SHORT_LIST:
230  return parseListValue< sal_Int16 >(separator, text);
231  case TYPE_INT_LIST:
232  return parseListValue< sal_Int32 >(separator, text);
233  case TYPE_LONG_LIST:
234  return parseListValue< sal_Int64 >(separator, text);
235  case TYPE_DOUBLE_LIST:
236  return parseListValue< double >(separator, text);
237  case TYPE_STRING_LIST:
238  return parseListValue< OUString >(separator, text);
239  case TYPE_HEXBINARY_LIST:
240  return parseListValue< css::uno::Sequence< sal_Int8 > >(
241  separator, text);
242  default:
243  assert(false);
244  throw css::uno::RuntimeException("this cannot happen");
245  }
246 }
247 
248 }
249 
250 ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
251 
253 
255  if (node_.is()) {
256  switch (state_) {
257  case State::Text:
258  if (!items_.empty()) {
259  break;
260  }
261  [[fallthrough]];
262  case State::IT:
263  return
265  !separator_.isEmpty())
268  default:
269  break;
270  }
271  }
273 }
274 
276  xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
277 {
278  if (!node_.is()) {
279  return false;
280  }
281  switch (state_) {
282  case State::Text:
283  if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name == "it" &&
284  isListType(type_) && separator_.isEmpty())
285  {
286  pad_.clear();
287  // before first <it>, characters are not ignored; assume they
288  // are only whitespace
289  state_ = State::IT;
290  return true;
291  }
292  [[fallthrough]];
293  case State::IT:
295  name == "unicode" &&
297  {
298  sal_Int32 scalar = -1;
299  for (;;) {
300  int attrNsId;
301  xmlreader::Span attrLn;
302  if (!reader.nextAttribute(&attrNsId, &attrLn)) {
303  break;
304  }
305  if (attrNsId == ParseManager::NAMESPACE_OOR &&
306  attrLn == "scalar")
307  {
308  if (!parseValue(reader.getAttributeValue(true), &scalar)) {
309  scalar = -1;
310  }
311  break;
312  }
313  }
314  if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
315  scalar != 0x0A && scalar != 0x0D)
316  {
317  char c = static_cast< char >(scalar);
318  pad_.add(&c, 1);
319  } else if (scalar == 0xFFFE) {
320  pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
321  } else if (scalar == 0xFFFF) {
322  pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
323  } else {
324  throw css::uno::RuntimeException(
325  "bad unicode scalar attribute in " + reader.getUrl());
326  }
328  return true;
329  }
330  break;
331  default:
332  break;
333  }
334  throw css::uno::RuntimeException(
335  "bad member <" + name.convertFromUtf8() + "> in " + reader.getUrl());
336 }
337 
339  if (!node_.is()) {
340  return false;
341  }
342  switch (state_) {
343  case State::Text:
344  {
345  css::uno::Any *pValue = nullptr;
346 
347  switch (node_->kind()) {
348  case Node::KIND_PROPERTY:
349  pValue = static_cast< PropertyNode * >(node_.get())->getValuePtr(layer_);
350  break;
352  {
353  NodeMap & members = node_->getMembers();
355  LocalizedValueNode *pLVNode;
356  if (i == members.end()) {
357  pLVNode = new LocalizedValueNode(layer_);
358  members.insert(
360  } else {
361  pLVNode = static_cast< LocalizedValueNode * >(i->second.get());
362  }
363  pValue = pLVNode->getValuePtr(layer_);
364  }
365  break;
366  default:
367  assert(false); // this cannot happen
368  return false;
369  }
370 
371  if (items_.empty()) {
372  *pValue = parseValue(separator_, pad_.get(), type_);
373  pad_.clear();
374  } else {
375  switch (type_) {
376  case TYPE_BOOLEAN_LIST:
377  *pValue = convertItems< sal_Bool >();
378  break;
379  case TYPE_SHORT_LIST:
380  *pValue = convertItems< sal_Int16 >();
381  break;
382  case TYPE_INT_LIST:
383  *pValue = convertItems< sal_Int32 >();
384  break;
385  case TYPE_LONG_LIST:
386  *pValue = convertItems< sal_Int64 >();
387  break;
388  case TYPE_DOUBLE_LIST:
389  *pValue = convertItems< double >();
390  break;
391  case TYPE_STRING_LIST:
392  *pValue = convertItems< OUString >();
393  break;
394  case TYPE_HEXBINARY_LIST:
395  *pValue = convertItems< css::uno::Sequence< sal_Int8 > >();
396  break;
397  default:
398  assert(false); // this cannot happen
399  break;
400  }
401  items_.clear();
402  }
403  separator_.clear();
404  node_.clear();
405  }
406  break;
407  case State::TextUnicode:
409  break;
410  case State::ITUnicode:
411  state_ = State::IT;
412  break;
413  case State::IT:
414  items_.push_back(
415  parseValue(OString(), pad_.get(), elementType(type_)));
416  pad_.clear();
418  break;
419  }
420  return true;
421 }
422 
424  if (node_.is()) {
425  assert(state_ == State::Text || state_ == State::IT);
426  pad_.add(text.begin, text.length);
427  }
428 }
429 
431  rtl::Reference< Node > const & node, OUString const & localizedName)
432 {
433  assert(node.is() && !node_.is());
434  node_ = node;
435  localizedName_ = localizedName;
437 }
438 
439 
440 template< typename T > css::uno::Any ValueParser::convertItems() {
441  css::uno::Sequence< T > seq(items_.size());
442  for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
443  bool ok = (items_[i] >>= seq[i]);
444  assert(ok);
445  (void) ok; // avoid warnings
446  }
447  return css::uno::Any(seq);
448 }
449 
450 }
451 
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void add(char const *begin, sal_Int32 length)
xmlreader::XmlReader::Text getTextMode() const
GVariantType * type_
Definition: dconf.cxx:184
iterator find(const OUString &aStr)
Definition: nodemap.hxx:43
bool startElement(xmlreader::XmlReader &reader, int nsId, xmlreader::Span const &name)
rtl::Reference< Node > node_
Definition: valueparser.hxx:76
int n1
sal_Int64 n
std::pair< iterator, bool > insert(const value_type &vt)
Definition: nodemap.hxx:53
PyObject_HEAD PyUNO_callable_Internals * members
char const * begin
bool is() const
Span get() const
int n2
int i
NodeMapImpl::value_type value_type
Definition: nodemap.hxx:39
std::vector< css::uno::Any > items_
Definition: valueparser.hxx:80
void characters(xmlreader::Span const &text)
unsigned char sal_Bool
Type elementType(Type type)
Definition: type.cxx:40
css::uno::Any * getValuePtr(int layer)
XPropertyListType t
void start(rtl::Reference< Node > const &property, OUString const &localizedName=OUString())
NodeMapImpl::iterator iterator
Definition: nodemap.hxx:37
sal_Int32 length
Span getAttributeValue(bool fullyNormalize)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
rtl::OUString convertFromUtf8() const
const OUString & getUrl() const
xmlreader::Pad pad_
Definition: valueparser.hxx:79
bool isListType(Type type)
Definition: type.cxx:36
bool nextAttribute(int *nsId, Span *localName)
css::uno::Any convertItems()
OUString name
Definition: components.cxx:83
iterator end()
Definition: nodemap.hxx:49
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo