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