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