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