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