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