Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / configmgr / source / valueparser.cxx
blob65190e41b6f172087295fdd3bc938d6c54e2431b
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.h"
34 #include "rtl/ustring.hxx"
35 #include "sal/types.h"
36 #include "xmlreader/span.hxx"
37 #include "xmlreader/xmlreader.hxx"
39 #include "localizedvaluenode.hxx"
40 #include "node.hxx"
41 #include "nodemap.hxx"
42 #include "parsemanager.hxx"
43 #include "propertynode.hxx"
44 #include "type.hxx"
45 #include "valueparser.hxx"
46 #include "xmldata.hxx"
48 namespace configmgr {
50 namespace {
52 bool parseHexDigit(char c, int * value) {
53 assert(value != 0);
54 if (c >= '0' && c <= '9') {
55 *value = c - '0';
56 return true;
58 if (c >= 'A' && c <= 'F') {
59 *value = c - 'A' + 10;
60 return true;
62 if (c >= 'a' && c <= 'f') {
63 *value = c - 'a' + 10;
64 return true;
66 return false;
69 bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
70 assert(text.is() && value != 0);
71 if (text.equals(RTL_CONSTASCII_STRINGPARAM("true")) ||
72 text.equals(RTL_CONSTASCII_STRINGPARAM("1")))
74 *value = true;
75 return true;
77 if (text.equals(RTL_CONSTASCII_STRINGPARAM("false")) ||
78 text.equals(RTL_CONSTASCII_STRINGPARAM("0")))
80 *value = false;
81 return true;
83 return false;
86 bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
87 assert(text.is() && value != 0);
88 // For backwards compatibility, support hexadecimal values:
89 sal_Int32 n =
90 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
91 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
92 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
93 rtl::OString(
94 text.begin + RTL_CONSTASCII_LENGTH("0X"),
95 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
96 rtl::OString(text.begin, text.length).toInt32();
97 //TODO: check valid lexical representation
98 if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
99 *value = static_cast< sal_Int16 >(n);
100 return true;
102 return false;
105 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
106 assert(text.is() && value != 0);
107 // For backwards compatibility, support hexadecimal values:
108 *value =
109 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
110 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
111 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
112 rtl::OString(
113 text.begin + RTL_CONSTASCII_LENGTH("0X"),
114 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
115 rtl::OString(text.begin, text.length).toInt32();
116 //TODO: check valid lexical representation
117 return true;
120 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
121 assert(text.is() && value != 0);
122 // For backwards compatibility, support hexadecimal values:
123 *value =
124 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
125 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
126 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
127 rtl::OString(
128 text.begin + RTL_CONSTASCII_LENGTH("0X"),
129 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt64(16) :
130 rtl::OString(text.begin, text.length).toInt64();
131 //TODO: check valid lexical representation
132 return true;
135 bool parseValue(xmlreader::Span const & text, double * value) {
136 assert(text.is() && value != 0);
137 *value = rtl::OString(text.begin, text.length).toDouble();
138 //TODO: check valid lexical representation
139 return true;
142 bool parseValue(xmlreader::Span const & text, rtl::OUString * value) {
143 assert(text.is() && value != 0);
144 *value = text.convertFromUtf8();
145 return true;
148 bool parseValue(
149 xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
151 assert(text.is() && value != 0);
152 if ((text.length & 1) != 0) {
153 return false;
155 comphelper::SequenceAsVector< sal_Int8 > seq;
156 for (sal_Int32 i = 0; i != text.length;) {
157 int n1;
158 int n2;
159 if (!parseHexDigit(text.begin[i++], &n1) ||
160 !parseHexDigit(text.begin[i++], &n2))
162 return false;
164 seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
166 *value = seq.getAsConstList();
167 return true;
170 template< typename T > css::uno::Any parseSingleValue(
171 xmlreader::Span const & text)
173 T val;
174 if (!parseValue(text, &val)) {
175 throw css::uno::RuntimeException(
176 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
177 css::uno::Reference< css::uno::XInterface >());
179 return css::uno::makeAny(val);
182 template< typename T > css::uno::Any parseListValue(
183 rtl::OString const & separator, xmlreader::Span const & text)
185 comphelper::SequenceAsVector< T > seq;
186 xmlreader::Span sep;
187 if (separator.isEmpty()) {
188 sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
189 } else {
190 sep = xmlreader::Span(separator.getStr(), separator.getLength());
192 if (text.length != 0) {
193 for (xmlreader::Span t(text);;) {
194 sal_Int32 i = rtl_str_indexOfStr_WithLength(
195 t.begin, t.length, sep.begin, sep.length);
196 T val;
197 if (!parseValue(
198 xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
200 throw css::uno::RuntimeException(
201 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
202 css::uno::Reference< css::uno::XInterface >());
204 seq.push_back(val);
205 if (i < 0) {
206 break;
208 t.begin += i + sep.length;
209 t.length -= i + sep.length;
212 return css::uno::makeAny(seq.getAsConstList());
215 css::uno::Any parseValue(
216 rtl::OString const & separator, xmlreader::Span const & text, Type type)
218 switch (type) {
219 case TYPE_ANY:
220 throw css::uno::RuntimeException(
221 rtl::OUString(
222 RTL_CONSTASCII_USTRINGPARAM("invalid value of type any")),
223 css::uno::Reference< css::uno::XInterface >());
224 case TYPE_BOOLEAN:
225 return parseSingleValue< sal_Bool >(text);
226 case TYPE_SHORT:
227 return parseSingleValue< sal_Int16 >(text);
228 case TYPE_INT:
229 return parseSingleValue< sal_Int32 >(text);
230 case TYPE_LONG:
231 return parseSingleValue< sal_Int64 >(text);
232 case TYPE_DOUBLE:
233 return parseSingleValue< double >(text);
234 case TYPE_STRING:
235 return parseSingleValue< rtl::OUString >(text);
236 case TYPE_HEXBINARY:
237 return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
238 case TYPE_BOOLEAN_LIST:
239 return parseListValue< sal_Bool >(separator, text);
240 case TYPE_SHORT_LIST:
241 return parseListValue< sal_Int16 >(separator, text);
242 case TYPE_INT_LIST:
243 return parseListValue< sal_Int32 >(separator, text);
244 case TYPE_LONG_LIST:
245 return parseListValue< sal_Int64 >(separator, text);
246 case TYPE_DOUBLE_LIST:
247 return parseListValue< double >(separator, text);
248 case TYPE_STRING_LIST:
249 return parseListValue< rtl::OUString >(separator, text);
250 case TYPE_HEXBINARY_LIST:
251 return parseListValue< css::uno::Sequence< sal_Int8 > >(
252 separator, text);
253 default:
254 assert(false);
255 throw css::uno::RuntimeException(
256 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
257 css::uno::Reference< css::uno::XInterface >());
263 ValueParser::ValueParser(int layer): layer_(layer) {}
265 ValueParser::~ValueParser() {}
267 xmlreader::XmlReader::Text ValueParser::getTextMode() const {
268 if (node_.is()) {
269 switch (state_) {
270 case STATE_TEXT:
271 if (!items_.empty()) {
272 break;
274 // fall through
275 case STATE_IT:
276 return
277 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
278 !separator_.isEmpty())
279 ? xmlreader::XmlReader::TEXT_RAW
280 : xmlreader::XmlReader::TEXT_NORMALIZED;
281 default:
282 break;
285 return xmlreader::XmlReader::TEXT_NONE;
288 bool ValueParser::startElement(
289 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
290 std::set< rtl::OUString > const *)
292 if (!node_.is()) {
293 return false;
295 switch (state_) {
296 case STATE_TEXT:
297 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
298 name.equals(RTL_CONSTASCII_STRINGPARAM("it")) &&
299 isListType(type_) && separator_.isEmpty())
301 pad_.clear();
302 // before first <it>, characters are not ignored; assume they
303 // are only whitespace
304 state_ = STATE_IT;
305 return true;
307 // fall through
308 case STATE_IT:
309 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
310 name.equals(RTL_CONSTASCII_STRINGPARAM("unicode")) &&
311 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
313 sal_Int32 scalar = -1;
314 for (;;) {
315 int attrNsId;
316 xmlreader::Span attrLn;
317 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
318 break;
320 if (attrNsId == ParseManager::NAMESPACE_OOR &&
321 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("scalar")))
323 if (!parseValue(reader.getAttributeValue(true), &scalar)) {
324 scalar = -1;
326 break;
329 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
330 scalar != 0x0A && scalar != 0x0D)
332 char c = static_cast< char >(scalar);
333 pad_.add(&c, 1);
334 } else if (scalar == 0xFFFE) {
335 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
336 } else if (scalar == 0xFFFF) {
337 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
338 } else {
339 throw css::uno::RuntimeException(
340 (rtl::OUString(
341 RTL_CONSTASCII_USTRINGPARAM(
342 "bad unicode scalar attribute in ")) +
343 reader.getUrl()),
344 css::uno::Reference< css::uno::XInterface >());
346 state_ = State(state_ + 1);
347 return true;
349 break;
350 default:
351 break;
353 throw css::uno::RuntimeException(
354 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
355 name.convertFromUtf8() +
356 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()),
357 css::uno::Reference< css::uno::XInterface >());
360 bool ValueParser::endElement() {
361 if (!node_.is()) {
362 return false;
364 switch (state_) {
365 case STATE_TEXT:
367 css::uno::Any value;
368 if (items_.empty()) {
369 value = parseValue(separator_, pad_.get(), type_);
370 pad_.clear();
371 } else {
372 switch (type_) {
373 case TYPE_BOOLEAN_LIST:
374 value = convertItems< sal_Bool >();
375 break;
376 case TYPE_SHORT_LIST:
377 value = convertItems< sal_Int16 >();
378 break;
379 case TYPE_INT_LIST:
380 value = convertItems< sal_Int32 >();
381 break;
382 case TYPE_LONG_LIST:
383 value = convertItems< sal_Int64 >();
384 break;
385 case TYPE_DOUBLE_LIST:
386 value = convertItems< double >();
387 break;
388 case TYPE_STRING_LIST:
389 value = convertItems< rtl::OUString >();
390 break;
391 case TYPE_HEXBINARY_LIST:
392 value = convertItems< css::uno::Sequence< sal_Int8 > >();
393 break;
394 default:
395 assert(false); // this cannot happen
396 break;
398 items_.clear();
400 switch (node_->kind()) {
401 case Node::KIND_PROPERTY:
402 dynamic_cast< PropertyNode * >(node_.get())->setValue(
403 layer_, value);
404 break;
405 case Node::KIND_LOCALIZED_PROPERTY:
407 NodeMap & members = node_->getMembers();
408 NodeMap::iterator i(members.find(localizedName_));
409 if (i == members.end()) {
410 members.insert(
411 NodeMap::value_type(
412 localizedName_,
413 new LocalizedValueNode(layer_, value)));
414 } else {
415 dynamic_cast< LocalizedValueNode * >(i->second.get())->
416 setValue(layer_, value);
419 break;
420 default:
421 assert(false); // this cannot happen
422 break;
424 separator_ = rtl::OString();
425 node_.clear();
427 break;
428 case STATE_TEXT_UNICODE:
429 case STATE_IT_UNICODE:
430 state_ = State(state_ - 1);
431 break;
432 case STATE_IT:
433 items_.push_back(
434 parseValue(rtl::OString(), pad_.get(), elementType(type_)));
435 pad_.clear();
436 state_ = STATE_TEXT;
437 break;
439 return true;
442 void ValueParser::characters(xmlreader::Span const & text) {
443 if (node_.is()) {
444 assert(state_ == STATE_TEXT || state_ == STATE_IT);
445 pad_.add(text.begin, text.length);
449 void ValueParser::start(
450 rtl::Reference< Node > const & node, rtl::OUString const & localizedName)
452 assert(node.is() && !node_.is());
453 node_ = node;
454 localizedName_ = localizedName;
455 state_ = STATE_TEXT;
458 int ValueParser::getLayer() const {
459 return layer_;
462 template< typename T > css::uno::Any ValueParser::convertItems() {
463 css::uno::Sequence< T > seq(items_.size());
464 for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
465 bool ok = (items_[i] >>= seq[i]);
466 assert(ok);
467 (void) ok; // avoid warnings
469 return css::uno::makeAny(seq);
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */