bump product version to 6.3.0.0.beta1
[LibreOffice.git] / configmgr / source / valueparser.cxx
blob4dda54c410e4f8b5be3c68e6acf36e3f1407c1cc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <cassert>
23 #include <set>
25 #include <com/sun/star/uno/Any.hxx>
26 #include <com/sun/star/uno/Reference.hxx>
27 #include <com/sun/star/uno/RuntimeException.hpp>
28 #include <com/sun/star/uno/Sequence.hxx>
29 #include <com/sun/star/uno/XInterface.hpp>
30 #include <comphelper/sequence.hxx>
31 #include <rtl/string.h>
32 #include <rtl/string.hxx>
33 #include <rtl/ustring.hxx>
34 #include <sal/types.h>
35 #include <xmlreader/span.hxx>
36 #include <xmlreader/xmlreader.hxx>
38 #include "localizedvaluenode.hxx"
39 #include "node.hxx"
40 #include "nodemap.hxx"
41 #include "parsemanager.hxx"
42 #include "propertynode.hxx"
43 #include "type.hxx"
44 #include "valueparser.hxx"
45 #include "xmldata.hxx"
47 namespace configmgr {
49 namespace {
51 bool parseHexDigit(char c, int * value) {
52 assert(value != nullptr);
53 if (c >= '0' && c <= '9') {
54 *value = c - '0';
55 return true;
57 if (c >= 'A' && c <= 'F') {
58 *value = c - 'A' + 10;
59 return true;
61 if (c >= 'a' && c <= 'f') {
62 *value = c - 'a' + 10;
63 return true;
65 return false;
68 bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
69 assert(text.is() && value != nullptr);
70 if (text.equals("true") || text.equals("1")) {
71 *value = true;
72 return true;
74 if (text.equals("false") || text.equals("0")) {
75 *value = false;
76 return true;
78 return false;
81 bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
82 assert(text.is() && value != nullptr);
83 // For backwards compatibility, support hexadecimal values:
84 sal_Int32 n =
85 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
86 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
87 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
88 static_cast< sal_Int32 >(
89 OString(
90 text.begin + RTL_CONSTASCII_LENGTH("0X"),
91 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
92 OString(text.begin, text.length).toInt32();
93 //TODO: check valid lexical representation
94 if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
95 *value = static_cast< sal_Int16 >(n);
96 return true;
98 return false;
101 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
102 assert(text.is() && value != nullptr);
103 // For backwards compatibility, support hexadecimal values:
104 *value =
105 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
106 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
107 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
108 static_cast< sal_Int32 >(
109 OString(
110 text.begin + RTL_CONSTASCII_LENGTH("0X"),
111 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
112 OString(text.begin, text.length).toInt32();
113 //TODO: check valid lexical representation
114 return true;
117 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
118 assert(text.is() && value != nullptr);
119 // For backwards compatibility, support hexadecimal values:
120 *value =
121 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
122 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
123 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
124 static_cast< sal_Int64 >(
125 OString(
126 text.begin + RTL_CONSTASCII_LENGTH("0X"),
127 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
128 OString(text.begin, text.length).toInt64();
129 //TODO: check valid lexical representation
130 return true;
133 bool parseValue(xmlreader::Span const & text, double * value) {
134 assert(text.is() && value != nullptr);
135 *value = OString(text.begin, text.length).toDouble();
136 //TODO: check valid lexical representation
137 return true;
140 bool parseValue(xmlreader::Span const & text, OUString * value) {
141 assert(text.is() && value != nullptr);
142 *value = text.convertFromUtf8();
143 return true;
146 bool parseValue(
147 xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
149 assert(text.is() && value != nullptr);
150 if ((text.length & 1) != 0) {
151 return false;
153 std::vector< sal_Int8 > seq;
154 for (sal_Int32 i = 0; i != text.length;) {
155 int n1;
156 int n2;
157 if (!parseHexDigit(text.begin[i++], &n1) ||
158 !parseHexDigit(text.begin[i++], &n2))
160 return false;
162 seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
164 *value = comphelper::containerToSequence(seq);
165 return true;
168 template< typename T > css::uno::Any parseSingleValue(
169 xmlreader::Span const & text)
171 T val;
172 if (!parseValue(text, &val)) {
173 throw css::uno::RuntimeException("invalid value");
175 return css::uno::Any(val);
178 template< typename T > css::uno::Any parseListValue(
179 OString const & separator, xmlreader::Span const & text)
181 std::vector< T > seq;
182 xmlreader::Span sep;
183 if (separator.isEmpty()) {
184 sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
185 } else {
186 sep = xmlreader::Span(separator.getStr(), separator.getLength());
188 if (text.length != 0) {
189 for (xmlreader::Span t(text);;) {
190 sal_Int32 i = rtl_str_indexOfStr_WithLength(
191 t.begin, t.length, sep.begin, sep.length);
192 T val;
193 if (!parseValue(
194 xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
196 throw css::uno::RuntimeException("invalid value");
198 seq.push_back(val);
199 if (i < 0) {
200 break;
202 t.begin += i + sep.length;
203 t.length -= i + sep.length;
206 return css::uno::Any(comphelper::containerToSequence(seq));
209 css::uno::Any parseValue(
210 OString const & separator, xmlreader::Span const & text, Type type)
212 switch (type) {
213 case TYPE_ANY:
214 throw css::uno::RuntimeException("invalid value of type any");
215 case TYPE_BOOLEAN:
216 return parseSingleValue< sal_Bool >(text);
217 case TYPE_SHORT:
218 return parseSingleValue< sal_Int16 >(text);
219 case TYPE_INT:
220 return parseSingleValue< sal_Int32 >(text);
221 case TYPE_LONG:
222 return parseSingleValue< sal_Int64 >(text);
223 case TYPE_DOUBLE:
224 return parseSingleValue< double >(text);
225 case TYPE_STRING:
226 return parseSingleValue< OUString >(text);
227 case TYPE_HEXBINARY:
228 return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
229 case TYPE_BOOLEAN_LIST:
230 return parseListValue< sal_Bool >(separator, text);
231 case TYPE_SHORT_LIST:
232 return parseListValue< sal_Int16 >(separator, text);
233 case TYPE_INT_LIST:
234 return parseListValue< sal_Int32 >(separator, text);
235 case TYPE_LONG_LIST:
236 return parseListValue< sal_Int64 >(separator, text);
237 case TYPE_DOUBLE_LIST:
238 return parseListValue< double >(separator, text);
239 case TYPE_STRING_LIST:
240 return parseListValue< OUString >(separator, text);
241 case TYPE_HEXBINARY_LIST:
242 return parseListValue< css::uno::Sequence< sal_Int8 > >(
243 separator, text);
244 default:
245 assert(false);
246 throw css::uno::RuntimeException("this cannot happen");
252 ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
254 ValueParser::~ValueParser() {}
256 xmlreader::XmlReader::Text ValueParser::getTextMode() const {
257 if (node_.is()) {
258 switch (state_) {
259 case State::Text:
260 if (!items_.empty()) {
261 break;
263 [[fallthrough]];
264 case State::IT:
265 return
266 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
267 !separator_.isEmpty())
268 ? xmlreader::XmlReader::Text::Raw
269 : xmlreader::XmlReader::Text::Normalized;
270 default:
271 break;
274 return xmlreader::XmlReader::Text::NONE;
277 bool ValueParser::startElement(
278 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
280 if (!node_.is()) {
281 return false;
283 switch (state_) {
284 case State::Text:
285 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("it") &&
286 isListType(type_) && separator_.isEmpty())
288 pad_.clear();
289 // before first <it>, characters are not ignored; assume they
290 // are only whitespace
291 state_ = State::IT;
292 return true;
294 [[fallthrough]];
295 case State::IT:
296 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
297 name.equals("unicode") &&
298 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
300 sal_Int32 scalar = -1;
301 for (;;) {
302 int attrNsId;
303 xmlreader::Span attrLn;
304 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
305 break;
307 if (attrNsId == ParseManager::NAMESPACE_OOR &&
308 attrLn.equals("scalar"))
310 if (!parseValue(reader.getAttributeValue(true), &scalar)) {
311 scalar = -1;
313 break;
316 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
317 scalar != 0x0A && scalar != 0x0D)
319 char c = static_cast< char >(scalar);
320 pad_.add(&c, 1);
321 } else if (scalar == 0xFFFE) {
322 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
323 } else if (scalar == 0xFFFF) {
324 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
325 } else {
326 throw css::uno::RuntimeException(
327 "bad unicode scalar attribute in " + reader.getUrl());
329 state_ = state_ == State::Text ? State::TextUnicode : State::ITUnicode;
330 return true;
332 break;
333 default:
334 break;
336 throw css::uno::RuntimeException(
337 "bad member <" + name.convertFromUtf8() + "> in " + reader.getUrl());
340 bool ValueParser::endElement() {
341 if (!node_.is()) {
342 return false;
344 switch (state_) {
345 case State::Text:
347 css::uno::Any *pValue = nullptr;
349 switch (node_->kind()) {
350 case Node::KIND_PROPERTY:
351 pValue = static_cast< PropertyNode * >(node_.get())->getValuePtr(layer_);
352 break;
353 case Node::KIND_LOCALIZED_PROPERTY:
355 NodeMap & members = node_->getMembers();
356 NodeMap::iterator i(members.find(localizedName_));
357 LocalizedValueNode *pLVNode;
358 if (i == members.end()) {
359 pLVNode = new LocalizedValueNode(layer_);
360 members.insert(
361 NodeMap::value_type(localizedName_, pLVNode ));
362 } else {
363 pLVNode = static_cast< LocalizedValueNode * >(i->second.get());
365 pValue = pLVNode->getValuePtr(layer_);
367 break;
368 default:
369 assert(false); // this cannot happen
370 return false;
373 if (items_.empty()) {
374 *pValue = parseValue(separator_, pad_.get(), type_);
375 pad_.clear();
376 } else {
377 switch (type_) {
378 case TYPE_BOOLEAN_LIST:
379 *pValue = convertItems< sal_Bool >();
380 break;
381 case TYPE_SHORT_LIST:
382 *pValue = convertItems< sal_Int16 >();
383 break;
384 case TYPE_INT_LIST:
385 *pValue = convertItems< sal_Int32 >();
386 break;
387 case TYPE_LONG_LIST:
388 *pValue = convertItems< sal_Int64 >();
389 break;
390 case TYPE_DOUBLE_LIST:
391 *pValue = convertItems< double >();
392 break;
393 case TYPE_STRING_LIST:
394 *pValue = convertItems< OUString >();
395 break;
396 case TYPE_HEXBINARY_LIST:
397 *pValue = convertItems< css::uno::Sequence< sal_Int8 > >();
398 break;
399 default:
400 assert(false); // this cannot happen
401 break;
403 items_.clear();
405 separator_.clear();
406 node_.clear();
408 break;
409 case State::TextUnicode:
410 state_ = State::Text;
411 break;
412 case State::ITUnicode:
413 state_ = State::IT;
414 break;
415 case State::IT:
416 items_.push_back(
417 parseValue(OString(), pad_.get(), elementType(type_)));
418 pad_.clear();
419 state_ = State::Text;
420 break;
422 return true;
425 void ValueParser::characters(xmlreader::Span const & text) {
426 if (node_.is()) {
427 assert(state_ == State::Text || state_ == State::IT);
428 pad_.add(text.begin, text.length);
432 void ValueParser::start(
433 rtl::Reference< Node > const & node, OUString const & localizedName)
435 assert(node.is() && !node_.is());
436 node_ = node;
437 localizedName_ = localizedName;
438 state_ = State::Text;
442 template< typename T > css::uno::Any ValueParser::convertItems() {
443 css::uno::Sequence< T > seq(items_.size());
444 for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
445 bool ok = (items_[i] >>= seq[i]);
446 assert(ok);
447 (void) ok; // avoid warnings
449 return css::uno::Any(seq);
454 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */