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 76200 : bool parseHexDigit(char c, int * value) {
52 : assert(value != 0);
53 76200 : if (c >= '0' && c <= '9') {
54 22098 : *value = c - '0';
55 22098 : return true;
56 : }
57 54102 : if (c >= 'A' && c <= 'F') {
58 40005 : *value = c - 'A' + 10;
59 40005 : return true;
60 : }
61 14097 : if (c >= 'a' && c <= 'f') {
62 14097 : *value = c - 'a' + 10;
63 14097 : return true;
64 : }
65 0 : return false;
66 : }
67 :
68 895547 : bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
69 : assert(text.is() && value != 0);
70 895547 : if (text.equals("true") || text.equals("1")) {
71 521334 : *value = true;
72 521334 : return true;
73 : }
74 374213 : if (text.equals("false") || text.equals("0")) {
75 374213 : *value = false;
76 374213 : return true;
77 : }
78 0 : return false;
79 : }
80 :
81 34867 : 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 34867 : RTL_CONSTASCII_LENGTH("0X")) == 0 ?
88 : static_cast< sal_Int32 >(
89 : OString(
90 : text.begin + RTL_CONSTASCII_LENGTH("0X"),
91 34867 : text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
92 69734 : OString(text.begin, text.length).toInt32();
93 : //TODO: check valid lexical representation
94 34867 : if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
95 34867 : *value = static_cast< sal_Int16 >(n);
96 34867 : return true;
97 : }
98 0 : return false;
99 : }
100 :
101 1386789 : 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 1386789 : RTL_CONSTASCII_LENGTH("0X")) == 0 ?
108 : static_cast< sal_Int32 >(
109 : OString(
110 : text.begin + RTL_CONSTASCII_LENGTH("0X"),
111 1386789 : text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
112 2773578 : OString(text.begin, text.length).toInt32();
113 : //TODO: check valid lexical representation
114 1386789 : return true;
115 : }
116 :
117 16383 : 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 16383 : RTL_CONSTASCII_LENGTH("0X")) == 0 ?
124 : static_cast< sal_Int64 >(
125 : OString(
126 : text.begin + RTL_CONSTASCII_LENGTH("0X"),
127 16383 : text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
128 32766 : OString(text.begin, text.length).toInt64();
129 : //TODO: check valid lexical representation
130 16383 : return true;
131 : }
132 :
133 30480 : bool parseValue(xmlreader::Span const & text, double * value) {
134 : assert(text.is() && value != 0);
135 30480 : *value = OString(text.begin, text.length).toDouble();
136 : //TODO: check valid lexical representation
137 30480 : return true;
138 : }
139 :
140 5644435 : bool parseValue(xmlreader::Span const & text, OUString * value) {
141 : assert(text.is() && value != 0);
142 5644435 : *value = text.convertFromUtf8();
143 5644435 : return true;
144 : }
145 :
146 12573 : bool parseValue(
147 : xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
148 : {
149 : assert(text.is() && value != 0);
150 12573 : if ((text.length & 1) != 0) {
151 0 : return false;
152 : }
153 12573 : comphelper::SequenceAsVector< sal_Int8 > seq;
154 63246 : for (sal_Int32 i = 0; i != text.length;) {
155 : int n1;
156 : int n2;
157 76200 : if (!parseHexDigit(text.begin[i++], &n1) ||
158 38100 : !parseHexDigit(text.begin[i++], &n2))
159 : {
160 0 : return false;
161 : }
162 38100 : seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
163 : }
164 12573 : *value = seq.getAsConstList();
165 12573 : return true;
166 : }
167 :
168 7072384 : template< typename T > css::uno::Any parseSingleValue(
169 : xmlreader::Span const & text)
170 : {
171 4733464 : T val;
172 7072384 : if (!parseValue(text, &val)) {
173 0 : throw css::uno::RuntimeException("invalid value");
174 : }
175 7072384 : return css::uno::makeAny(val);
176 : }
177 :
178 364236 : template< typename T > css::uno::Any parseListValue(
179 : OString const & separator, xmlreader::Span const & text)
180 : {
181 364236 : comphelper::SequenceAsVector< T > seq;
182 364236 : xmlreader::Span sep;
183 364236 : if (separator.isEmpty()) {
184 319659 : sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
185 : } else {
186 44577 : sep = xmlreader::Span(separator.getStr(), separator.getLength());
187 : }
188 364236 : if (text.length != 0) {
189 948690 : for (xmlreader::Span t(text);;) {
190 : sal_Int32 i = rtl_str_indexOfStr_WithLength(
191 948690 : t.begin, t.length, sep.begin, sep.length);
192 923544 : T val;
193 1897380 : if (!parseValue(
194 1897380 : xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
195 : {
196 0 : throw css::uno::RuntimeException("invalid value");
197 : }
198 948690 : seq.push_back(val);
199 948690 : if (i < 0) {
200 306705 : break;
201 : }
202 641985 : t.begin += i + sep.length;
203 641985 : t.length -= i + sep.length;
204 : }
205 : }
206 364236 : return css::uno::makeAny(seq.getAsConstList());
207 : }
208 :
209 7436620 : css::uno::Any parseValue(
210 : OString const & separator, xmlreader::Span const & text, Type type)
211 : {
212 7436620 : switch (type) {
213 : case TYPE_ANY:
214 0 : throw css::uno::RuntimeException("invalid value of type any");
215 : case TYPE_BOOLEAN:
216 895547 : return parseSingleValue< sal_Bool >(text);
217 : case TYPE_SHORT:
218 34867 : return parseSingleValue< sal_Int16 >(text);
219 : case TYPE_INT:
220 1366215 : return parseSingleValue< sal_Int32 >(text);
221 : case TYPE_LONG:
222 11811 : return parseSingleValue< sal_Int64 >(text);
223 : case TYPE_DOUBLE:
224 30480 : return parseSingleValue< double >(text);
225 : case TYPE_STRING:
226 4720891 : return parseSingleValue< OUString >(text);
227 : case TYPE_HEXBINARY:
228 12573 : 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 1143 : return parseListValue< sal_Int32 >(separator, text);
235 : case TYPE_LONG_LIST:
236 381 : return parseListValue< sal_Int64 >(separator, text);
237 : case TYPE_DOUBLE_LIST:
238 0 : return parseListValue< double >(separator, text);
239 : case TYPE_STRING_LIST:
240 362712 : 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 116940 : ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
253 :
254 116940 : ValueParser::~ValueParser() {}
255 :
256 45056071 : xmlreader::XmlReader::Text ValueParser::getTextMode() const {
257 45056071 : if (node_.is()) {
258 14502702 : switch (state_) {
259 : case STATE_TEXT:
260 14380660 : if (!items_.empty()) {
261 61021 : break;
262 : }
263 : // fall through
264 : case STATE_IT:
265 : return
266 24668182 : (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
267 4705653 : !separator_.isEmpty())
268 : ? xmlreader::XmlReader::TEXT_RAW
269 24177709 : : xmlreader::XmlReader::TEXT_NORMALIZED;
270 : default:
271 0 : break;
272 : }
273 : }
274 30614390 : return xmlreader::XmlReader::TEXT_NONE;
275 : }
276 :
277 19090158 : bool ValueParser::startElement(
278 : xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
279 : std::set< OUString > const *)
280 : {
281 19090158 : if (!node_.is()) {
282 19029137 : return false;
283 : }
284 61021 : switch (state_) {
285 : case STATE_TEXT:
286 183063 : if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("it") &&
287 183063 : isListType(type_) && separator_.isEmpty())
288 : {
289 61021 : pad_.clear();
290 : // before first <it>, characters are not ignored; assume they
291 : // are only whitespace
292 61021 : state_ = STATE_IT;
293 61021 : 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 19090158 : bool ValueParser::endElement() {
342 19090158 : if (!node_.is()) {
343 11640908 : return false;
344 : }
345 7449250 : switch (state_) {
346 : case STATE_TEXT:
347 : {
348 7388229 : css::uno::Any *pValue = NULL;
349 :
350 7388229 : switch (node_->kind()) {
351 : case Node::KIND_PROPERTY:
352 5026883 : pValue = static_cast< PropertyNode * >(node_.get())->getValuePtr(layer_);
353 5026883 : break;
354 : case Node::KIND_LOCALIZED_PROPERTY:
355 : {
356 2361346 : NodeMap & members = node_->getMembers();
357 2361346 : NodeMap::iterator i(members.find(localizedName_));
358 : LocalizedValueNode *pLVNode;
359 2361346 : if (i == members.end()) {
360 2360134 : pLVNode = new LocalizedValueNode(layer_);
361 : members.insert(
362 2360134 : NodeMap::value_type(localizedName_, pLVNode ));
363 : } else {
364 1212 : pLVNode = static_cast< LocalizedValueNode * >(i->second.get());
365 : }
366 2361346 : pValue = pLVNode->getValuePtr(layer_);
367 : }
368 2361346 : break;
369 : default:
370 : assert(false); // this cannot happen
371 0 : return false;
372 : }
373 :
374 7388229 : if (items_.empty()) {
375 7375599 : *pValue = parseValue(separator_, pad_.get(), type_);
376 7375599 : pad_.clear();
377 : } else {
378 12630 : 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 12630 : *pValue = convertItems< OUString >();
396 12630 : 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 12630 : items_.clear();
405 : }
406 7388229 : separator_ = OString();
407 7388229 : node_.clear();
408 : }
409 7388229 : 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 61021 : parseValue(OString(), pad_.get(), elementType(type_)));
417 61021 : pad_.clear();
418 61021 : state_ = STATE_TEXT;
419 61021 : break;
420 : }
421 7449250 : return true;
422 : }
423 :
424 6992431 : void ValueParser::characters(xmlreader::Span const & text) {
425 6992431 : if (node_.is()) {
426 : assert(state_ == STATE_TEXT || state_ == STATE_IT);
427 6992431 : pad_.add(text.begin, text.length);
428 : }
429 6992431 : }
430 :
431 7388229 : void ValueParser::start(
432 : rtl::Reference< Node > const & node, OUString const & localizedName)
433 : {
434 : assert(node.is() && !node_.is());
435 7388229 : node_ = node;
436 7388229 : localizedName_ = localizedName;
437 7388229 : state_ = STATE_TEXT;
438 7388229 : }
439 :
440 :
441 12630 : template< typename T > css::uno::Any ValueParser::convertItems() {
442 12630 : css::uno::Sequence< T > seq(items_.size());
443 73651 : for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
444 61021 : bool ok = (items_[i] >>= seq[i]);
445 : assert(ok);
446 : (void) ok; // avoid warnings
447 : }
448 12630 : return css::uno::makeAny(seq);
449 : }
450 :
451 : }
452 :
453 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|