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>
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>
35
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
44namespace configmgr {
45
46namespace {
47
48bool 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
65bool 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
78bool 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
98bool 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
114bool 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
130bool 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
138bool parseValue(xmlreader::Span const & text, OUString * value) {
139 assert(text.is() && value != nullptr);
140 *value = text.convertFromUtf8();
141 return true;
142}
143
144bool 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 }
163 return true;
164}
165
166template< 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
176template< 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
207css::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);
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);
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
250ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
251
253
255 if (!node_)
256 return xmlreader::XmlReader::Text::NONE;
257
258 switch (state_) {
259 case State::Text:
260 if (!items_.empty()) {
261 break;
262 }
263 [[fallthrough]];
264 case State::IT:
265 return
267 !separator_.isEmpty())
268 ? xmlreader::XmlReader::Text::Raw
269 : xmlreader::XmlReader::Text::Normalized;
270 default:
271 break;
272 }
273 return xmlreader::XmlReader::Text::NONE;
274}
275
277 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
278{
279 if (!node_.is()) {
280 return false;
281 }
282 switch (state_) {
283 case State::Text:
284 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name == "it" &&
285 isListType(type_) && separator_.isEmpty())
286 {
287 pad_.clear();
288 // before first <it>, characters are not ignored; assume they
289 // are only whitespace
291 return true;
292 }
293 [[fallthrough]];
294 case State::IT:
296 name == "unicode" &&
298 {
299 sal_Int32 scalar = -1;
300 for (;;) {
301 int attrNsId;
302 xmlreader::Span attrLn;
303 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
304 break;
305 }
306 if (attrNsId == ParseManager::NAMESPACE_OOR &&
307 attrLn == "scalar")
308 {
309 if (!parseValue(reader.getAttributeValue(true), &scalar)) {
310 scalar = -1;
311 }
312 break;
313 }
314 }
315 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
316 scalar != 0x0A && scalar != 0x0D)
317 {
318 char c = static_cast< char >(scalar);
319 pad_.add(&c, 1);
320 } else if (scalar == 0xFFFE) {
321 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
322 } else if (scalar == 0xFFFF) {
323 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
324 } else {
325 throw css::uno::RuntimeException(
326 "bad unicode scalar attribute in " + reader.getUrl());
327 }
329 return true;
330 }
331 break;
332 default:
333 break;
334 }
335 throw css::uno::RuntimeException(
336 "bad member <" + name.convertFromUtf8() + "> in " + reader.getUrl());
337}
338
340 if (!node_.is()) {
341 return false;
342 }
343 switch (state_) {
344 case State::Text:
345 {
346 css::uno::Any *pValue = nullptr;
347
348 switch (node_->kind()) {
350 pValue = static_cast< PropertyNode * >(node_.get())->getValuePtr(layer_);
351 break;
353 {
354 NodeMap & members = node_->getMembers();
356 LocalizedValueNode *pLVNode;
357 if (i == members.end()) {
358 pLVNode = new LocalizedValueNode(layer_);
359 members.insert(
361 } else {
362 pLVNode = static_cast< LocalizedValueNode * >(i->second.get());
363 }
364 pValue = pLVNode->getValuePtr(layer_);
365 }
366 break;
367 default:
368 assert(false); // this cannot happen
369 return false;
370 }
371
372 if (items_.empty()) {
373 *pValue = parseValue(separator_, pad_.get(), type_);
374 pad_.clear();
375 } else {
376 switch (type_) {
378 *pValue = convertItems< sal_Bool >();
379 break;
380 case TYPE_SHORT_LIST:
381 *pValue = convertItems< sal_Int16 >();
382 break;
383 case TYPE_INT_LIST:
384 *pValue = convertItems< sal_Int32 >();
385 break;
386 case TYPE_LONG_LIST:
387 *pValue = convertItems< sal_Int64 >();
388 break;
389 case TYPE_DOUBLE_LIST:
390 *pValue = convertItems< double >();
391 break;
392 case TYPE_STRING_LIST:
393 *pValue = convertItems< OUString >();
394 break;
396 *pValue = convertItems< css::uno::Sequence< sal_Int8 > >();
397 break;
398 default:
399 assert(false); // this cannot happen
400 break;
401 }
402 items_.clear();
403 }
404 separator_.clear();
405 node_.clear();
406 }
407 break;
410 break;
411 case State::ITUnicode:
413 break;
414 case State::IT:
415 items_.push_back(
416 parseValue(OString(), pad_.get(), elementType(type_)));
417 pad_.clear();
419 break;
420 }
421 return true;
422}
423
425 if (node_.is()) {
426 assert(state_ == State::Text || state_ == State::IT);
427 pad_.add(text.begin, text.length);
428 }
429}
430
432 rtl::Reference< Node > const & node, OUString const & localizedName)
433{
434 assert(node.is() && !node_.is());
435 node_ = node;
436 localizedName_ = localizedName;
438}
439
440
441template< typename T > css::uno::Any ValueParser::convertItems() {
442 css::uno::Sequence< T > seq(items_.size());
443 auto seqRange = asNonConstRange(seq);
444 for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
445 bool ok = (items_[i] >>= seqRange[i]);
446 assert(ok);
447 (void) ok; // avoid warnings
448 }
449 return css::uno::Any(seq);
450}
451
452}
453
454/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
css::uno::Any * getValuePtr(int layer)
NodeMapImpl::iterator iterator
Definition: nodemap.hxx:37
NodeMapImpl::value_type value_type
Definition: nodemap.hxx:39
@ KIND_LOCALIZED_PROPERTY
Definition: node.hxx:35
xmlreader::Pad pad_
Definition: valueparser.hxx:79
css::uno::Any convertItems()
void characters(xmlreader::Span const &text)
rtl::Reference< Node > node_
Definition: valueparser.hxx:76
bool startElement(xmlreader::XmlReader &reader, int nsId, xmlreader::Span const &name)
xmlreader::XmlReader::Text getTextMode() const
void start(rtl::Reference< Node > const &property, OUString const &localizedName=OUString())
std::vector< css::uno::Any > items_
Definition: valueparser.hxx:80
Span get() const
void add(char const *begin, sal_Int32 length)
const OUString & getUrl() const
bool nextAttribute(int *nsId, Span *localName)
Span getAttributeValue(bool fullyNormalize)
Any value
OUString name
Definition: components.cxx:85
GVariantType * type_
Definition: dconf.cxx:184
sal_Int64 n
int n2
int n1
def text(shape, orig_st)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
@ TYPE_HEXBINARY_LIST
Definition: type.hxx:36
@ TYPE_HEXBINARY
Definition: type.hxx:34
@ TYPE_BOOLEAN
Definition: type.hxx:33
@ TYPE_STRING_LIST
Definition: type.hxx:36
@ TYPE_INT_LIST
Definition: type.hxx:35
@ TYPE_ANY
Definition: type.hxx:33
@ TYPE_DOUBLE
Definition: type.hxx:34
@ TYPE_LONG
Definition: type.hxx:34
@ TYPE_BOOLEAN_LIST
Definition: type.hxx:34
@ TYPE_SHORT
Definition: type.hxx:33
@ TYPE_INT
Definition: type.hxx:33
@ TYPE_DOUBLE_LIST
Definition: type.hxx:35
@ TYPE_STRING
Definition: type.hxx:34
@ TYPE_ERROR
Definition: type.hxx:33
@ TYPE_LONG_LIST
Definition: type.hxx:35
@ TYPE_SHORT_LIST
Definition: type.hxx:35
bool isListType(Type type)
Definition: type.cxx:36
Type elementType(Type type)
Definition: type.cxx:40
int i
PyObject_HEAD PyUNO_callable_Internals * members
char const * begin
sal_Int32 length
unsigned char sal_Bool
signed char sal_Int8