bump product version to 4.1.6.2
[LibreOffice.git] / configmgr / source / valueparser.cxx
bloba8dad1922df9ae37e10d52ae35e12d04bf7573dd
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/sequenceasvector.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 != 0);
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 != 0);
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 != 0);
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 OString(
89 text.begin + RTL_CONSTASCII_LENGTH("0X"),
90 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
91 OString(text.begin, text.length).toInt32();
92 //TODO: check valid lexical representation
93 if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
94 *value = static_cast< sal_Int16 >(n);
95 return true;
97 return false;
100 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
101 assert(text.is() && value != 0);
102 // For backwards compatibility, support hexadecimal values:
103 *value =
104 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
105 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
106 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
107 OString(
108 text.begin + RTL_CONSTASCII_LENGTH("0X"),
109 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
110 OString(text.begin, text.length).toInt32();
111 //TODO: check valid lexical representation
112 return true;
115 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
116 assert(text.is() && value != 0);
117 // For backwards compatibility, support hexadecimal values:
118 *value =
119 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
120 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
121 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
122 OString(
123 text.begin + RTL_CONSTASCII_LENGTH("0X"),
124 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt64(16) :
125 OString(text.begin, text.length).toInt64();
126 //TODO: check valid lexical representation
127 return true;
130 bool parseValue(xmlreader::Span const & text, double * value) {
131 assert(text.is() && value != 0);
132 *value = OString(text.begin, text.length).toDouble();
133 //TODO: check valid lexical representation
134 return true;
137 bool parseValue(xmlreader::Span const & text, OUString * value) {
138 assert(text.is() && value != 0);
139 *value = text.convertFromUtf8();
140 return true;
143 bool parseValue(
144 xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
146 assert(text.is() && value != 0);
147 if ((text.length & 1) != 0) {
148 return false;
150 comphelper::SequenceAsVector< sal_Int8 > seq;
151 for (sal_Int32 i = 0; i != text.length;) {
152 int n1;
153 int n2;
154 if (!parseHexDigit(text.begin[i++], &n1) ||
155 !parseHexDigit(text.begin[i++], &n2))
157 return false;
159 seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
161 *value = seq.getAsConstList();
162 return true;
165 template< typename T > css::uno::Any parseSingleValue(
166 xmlreader::Span const & text)
168 T val;
169 if (!parseValue(text, &val)) {
170 throw css::uno::RuntimeException(
171 OUString("invalid value"),
172 css::uno::Reference< css::uno::XInterface >());
174 return css::uno::makeAny(val);
177 template< typename T > css::uno::Any parseListValue(
178 OString const & separator, xmlreader::Span const & text)
180 comphelper::SequenceAsVector< T > seq;
181 xmlreader::Span sep;
182 if (separator.isEmpty()) {
183 sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
184 } else {
185 sep = xmlreader::Span(separator.getStr(), separator.getLength());
187 if (text.length != 0) {
188 for (xmlreader::Span t(text);;) {
189 sal_Int32 i = rtl_str_indexOfStr_WithLength(
190 t.begin, t.length, sep.begin, sep.length);
191 T val;
192 if (!parseValue(
193 xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
195 throw css::uno::RuntimeException(
196 OUString("invalid value"),
197 css::uno::Reference< css::uno::XInterface >());
199 seq.push_back(val);
200 if (i < 0) {
201 break;
203 t.begin += i + sep.length;
204 t.length -= i + sep.length;
207 return css::uno::makeAny(seq.getAsConstList());
210 css::uno::Any parseValue(
211 OString const & separator, xmlreader::Span const & text, Type type)
213 switch (type) {
214 case TYPE_ANY:
215 throw css::uno::RuntimeException(
216 OUString("invalid value of type any"),
217 css::uno::Reference< css::uno::XInterface >());
218 case TYPE_BOOLEAN:
219 return parseSingleValue< sal_Bool >(text);
220 case TYPE_SHORT:
221 return parseSingleValue< sal_Int16 >(text);
222 case TYPE_INT:
223 return parseSingleValue< sal_Int32 >(text);
224 case TYPE_LONG:
225 return parseSingleValue< sal_Int64 >(text);
226 case TYPE_DOUBLE:
227 return parseSingleValue< double >(text);
228 case TYPE_STRING:
229 return parseSingleValue< OUString >(text);
230 case TYPE_HEXBINARY:
231 return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
232 case TYPE_BOOLEAN_LIST:
233 return parseListValue< sal_Bool >(separator, text);
234 case TYPE_SHORT_LIST:
235 return parseListValue< sal_Int16 >(separator, text);
236 case TYPE_INT_LIST:
237 return parseListValue< sal_Int32 >(separator, text);
238 case TYPE_LONG_LIST:
239 return parseListValue< sal_Int64 >(separator, text);
240 case TYPE_DOUBLE_LIST:
241 return parseListValue< double >(separator, text);
242 case TYPE_STRING_LIST:
243 return parseListValue< OUString >(separator, text);
244 case TYPE_HEXBINARY_LIST:
245 return parseListValue< css::uno::Sequence< sal_Int8 > >(
246 separator, text);
247 default:
248 assert(false);
249 throw css::uno::RuntimeException(
250 OUString("this cannot happen"),
251 css::uno::Reference< css::uno::XInterface >());
257 ValueParser::ValueParser(int layer): layer_(layer) {}
259 ValueParser::~ValueParser() {}
261 xmlreader::XmlReader::Text ValueParser::getTextMode() const {
262 if (node_.is()) {
263 switch (state_) {
264 case STATE_TEXT:
265 if (!items_.empty()) {
266 break;
268 // fall through
269 case STATE_IT:
270 return
271 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
272 !separator_.isEmpty())
273 ? xmlreader::XmlReader::TEXT_RAW
274 : xmlreader::XmlReader::TEXT_NORMALIZED;
275 default:
276 break;
279 return xmlreader::XmlReader::TEXT_NONE;
282 bool ValueParser::startElement(
283 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
284 std::set< OUString > const *)
286 if (!node_.is()) {
287 return false;
289 switch (state_) {
290 case STATE_TEXT:
291 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("it") &&
292 isListType(type_) && separator_.isEmpty())
294 pad_.clear();
295 // before first <it>, characters are not ignored; assume they
296 // are only whitespace
297 state_ = STATE_IT;
298 return true;
300 // fall through
301 case STATE_IT:
302 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
303 name.equals("unicode") &&
304 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
306 sal_Int32 scalar = -1;
307 for (;;) {
308 int attrNsId;
309 xmlreader::Span attrLn;
310 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
311 break;
313 if (attrNsId == ParseManager::NAMESPACE_OOR &&
314 attrLn.equals("scalar"))
316 if (!parseValue(reader.getAttributeValue(true), &scalar)) {
317 scalar = -1;
319 break;
322 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
323 scalar != 0x0A && scalar != 0x0D)
325 char c = static_cast< char >(scalar);
326 pad_.add(&c, 1);
327 } else if (scalar == 0xFFFE) {
328 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
329 } else if (scalar == 0xFFFF) {
330 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
331 } else {
332 throw css::uno::RuntimeException(
333 (OUString("bad unicode scalar attribute in ") +
334 reader.getUrl()),
335 css::uno::Reference< css::uno::XInterface >());
337 state_ = State(state_ + 1);
338 return true;
340 break;
341 default:
342 break;
344 throw css::uno::RuntimeException(
345 (OUString("bad member <") +
346 name.convertFromUtf8() +
347 OUString("> in ") + reader.getUrl()),
348 css::uno::Reference< css::uno::XInterface >());
351 bool ValueParser::endElement() {
352 if (!node_.is()) {
353 return false;
355 switch (state_) {
356 case STATE_TEXT:
358 css::uno::Any value;
359 if (items_.empty()) {
360 value = parseValue(separator_, pad_.get(), type_);
361 pad_.clear();
362 } else {
363 switch (type_) {
364 case TYPE_BOOLEAN_LIST:
365 value = convertItems< sal_Bool >();
366 break;
367 case TYPE_SHORT_LIST:
368 value = convertItems< sal_Int16 >();
369 break;
370 case TYPE_INT_LIST:
371 value = convertItems< sal_Int32 >();
372 break;
373 case TYPE_LONG_LIST:
374 value = convertItems< sal_Int64 >();
375 break;
376 case TYPE_DOUBLE_LIST:
377 value = convertItems< double >();
378 break;
379 case TYPE_STRING_LIST:
380 value = convertItems< OUString >();
381 break;
382 case TYPE_HEXBINARY_LIST:
383 value = convertItems< css::uno::Sequence< sal_Int8 > >();
384 break;
385 default:
386 assert(false); // this cannot happen
387 break;
389 items_.clear();
391 switch (node_->kind()) {
392 case Node::KIND_PROPERTY:
393 dynamic_cast< PropertyNode * >(node_.get())->setValue(
394 layer_, value);
395 break;
396 case Node::KIND_LOCALIZED_PROPERTY:
398 NodeMap & members = node_->getMembers();
399 NodeMap::iterator i(members.find(localizedName_));
400 if (i == members.end()) {
401 members.insert(
402 NodeMap::value_type(
403 localizedName_,
404 new LocalizedValueNode(layer_, value)));
405 } else {
406 dynamic_cast< LocalizedValueNode * >(i->second.get())->
407 setValue(layer_, value);
410 break;
411 default:
412 assert(false); // this cannot happen
413 break;
415 separator_ = OString();
416 node_.clear();
418 break;
419 case STATE_TEXT_UNICODE:
420 case STATE_IT_UNICODE:
421 state_ = State(state_ - 1);
422 break;
423 case STATE_IT:
424 items_.push_back(
425 parseValue(OString(), pad_.get(), elementType(type_)));
426 pad_.clear();
427 state_ = STATE_TEXT;
428 break;
430 return true;
433 void ValueParser::characters(xmlreader::Span const & text) {
434 if (node_.is()) {
435 assert(state_ == STATE_TEXT || state_ == STATE_IT);
436 pad_.add(text.begin, text.length);
440 void ValueParser::start(
441 rtl::Reference< Node > const & node, OUString const & localizedName)
443 assert(node.is() && !node_.is());
444 node_ = node;
445 localizedName_ = localizedName;
446 state_ = STATE_TEXT;
449 int ValueParser::getLayer() const {
450 return layer_;
453 template< typename T > css::uno::Any ValueParser::convertItems() {
454 css::uno::Sequence< T > seq(items_.size());
455 for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
456 bool ok = (items_[i] >>= seq[i]);
457 assert(ok);
458 (void) ok; // avoid warnings
460 return css::uno::makeAny(seq);
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */