1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "precompiled_configmgr.hxx"
25 #include "sal/config.h"
26
27 #include "com/sun/star/uno/Any.hxx"
28 #include "com/sun/star/uno/Reference.hxx"
29 #include "com/sun/star/uno/RuntimeException.hpp"
30 #include "com/sun/star/uno/Sequence.hxx"
31 #include "com/sun/star/uno/XInterface.hpp"
32 #include "comphelper/sequenceasvector.hxx"
33 #include "osl/diagnose.h"
34 #include "rtl/string.h"
35 #include "rtl/string.hxx"
36 #include "rtl/ustring.h"
37 #include "rtl/ustring.hxx"
38 #include "sal/types.h"
39 #include "xmlreader/span.hxx"
40 #include "xmlreader/xmlreader.hxx"
41
42 #include "localizedvaluenode.hxx"
43 #include "node.hxx"
44 #include "nodemap.hxx"
45 #include "parsemanager.hxx"
46 #include "propertynode.hxx"
47 #include "type.hxx"
48 #include "valueparser.hxx"
49 #include "xmldata.hxx"
50
51 namespace configmgr {
52
53 namespace {
54
55 namespace css = com::sun::star;
56
parseHexDigit(char c,int * value)57 bool parseHexDigit(char c, int * value) {
58 OSL_ASSERT(value != 0);
59 if (c >= '0' && c <= '9') {
60 *value = c - '0';
61 return true;
62 }
63 if (c >= 'A' && c <= 'F') {
64 *value = c - 'A' + 10;
65 return true;
66 }
67 if (c >= 'a' && c <= 'f') {
68 *value = c - 'a' + 10;
69 return true;
70 }
71 return false;
72 }
73
parseValue(xmlreader::Span const & text,sal_Bool * value)74 bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
75 OSL_ASSERT(text.is() && value != 0);
76 if (text.equals(RTL_CONSTASCII_STRINGPARAM("true")) ||
77 text.equals(RTL_CONSTASCII_STRINGPARAM("1")))
78 {
79 *value = true;
80 return true;
81 }
82 if (text.equals(RTL_CONSTASCII_STRINGPARAM("false")) ||
83 text.equals(RTL_CONSTASCII_STRINGPARAM("0")))
84 {
85 *value = false;
86 return true;
87 }
88 return false;
89 }
90
parseValue(xmlreader::Span const & text,sal_Int16 * value)91 bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
92 OSL_ASSERT(text.is() && value != 0);
93 // For backwards compatibility, support hexadecimal values:
94 sal_Int32 n =
95 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
96 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
97 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
98 rtl::OString(
99 text.begin + RTL_CONSTASCII_LENGTH("0X"),
100 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
101 rtl::OString(text.begin, text.length).toInt32();
102 //TODO: check valid lexical representation
103 if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
104 *value = static_cast< sal_Int16 >(n);
105 return true;
106 }
107 return false;
108 }
109
parseValue(xmlreader::Span const & text,sal_Int32 * value)110 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
111 OSL_ASSERT(text.is() && value != 0);
112 // For backwards compatibility, support hexadecimal values:
113 *value =
114 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
115 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
116 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
117 rtl::OString(
118 text.begin + RTL_CONSTASCII_LENGTH("0X"),
119 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
120 rtl::OString(text.begin, text.length).toInt32();
121 //TODO: check valid lexical representation
122 return true;
123 }
124
parseValue(xmlreader::Span const & text,sal_Int64 * value)125 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
126 OSL_ASSERT(text.is() && value != 0);
127 // For backwards compatibility, support hexadecimal values:
128 *value =
129 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
130 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
131 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
132 rtl::OString(
133 text.begin + RTL_CONSTASCII_LENGTH("0X"),
134 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt64(16) :
135 rtl::OString(text.begin, text.length).toInt64();
136 //TODO: check valid lexical representation
137 return true;
138 }
139
parseValue(xmlreader::Span const & text,double * value)140 bool parseValue(xmlreader::Span const & text, double * value) {
141 OSL_ASSERT(text.is() && value != 0);
142 *value = rtl::OString(text.begin, text.length).toDouble();
143 //TODO: check valid lexical representation
144 return true;
145 }
146
parseValue(xmlreader::Span const & text,rtl::OUString * value)147 bool parseValue(xmlreader::Span const & text, rtl::OUString * value) {
148 OSL_ASSERT(text.is() && value != 0);
149 *value = text.convertFromUtf8();
150 return true;
151 }
152
parseValue(xmlreader::Span const & text,css::uno::Sequence<sal_Int8> * value)153 bool parseValue(
154 xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
155 {
156 OSL_ASSERT(text.is() && value != 0);
157 if ((text.length & 1) != 0) {
158 return false;
159 }
160 comphelper::SequenceAsVector< sal_Int8 > seq;
161 for (sal_Int32 i = 0; i != text.length;) {
162 int n1;
163 int n2;
164 if (!parseHexDigit(text.begin[i++], &n1) ||
165 !parseHexDigit(text.begin[i++], &n2))
166 {
167 return false;
168 }
169 seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
170 }
171 *value = seq.getAsConstList();
172 return true;
173 }
174
parseSingleValue(xmlreader::Span const & text)175 template< typename T > css::uno::Any parseSingleValue(
176 xmlreader::Span const & text)
177 {
178 T val;
179 if (!parseValue(text, &val)) {
180 throw css::uno::RuntimeException(
181 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
182 css::uno::Reference< css::uno::XInterface >());
183 }
184 return css::uno::makeAny(val);
185 }
186
parseListValue(rtl::OString const & separator,xmlreader::Span const & text)187 template< typename T > css::uno::Any parseListValue(
188 rtl::OString const & separator, xmlreader::Span const & text)
189 {
190 comphelper::SequenceAsVector< T > seq;
191 xmlreader::Span sep;
192 if (separator.getLength() == 0) {
193 sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
194 } else {
195 sep = xmlreader::Span(separator.getStr(), separator.getLength());
196 }
197 if (text.length != 0) {
198 for (xmlreader::Span t(text);;) {
199 sal_Int32 i = rtl_str_indexOfStr_WithLength(
200 t.begin, t.length, sep.begin, sep.length);
201 T val;
202 if (!parseValue(
203 xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
204 {
205 throw css::uno::RuntimeException(
206 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
207 css::uno::Reference< css::uno::XInterface >());
208 }
209 seq.push_back(val);
210 if (i < 0) {
211 break;
212 }
213 t.begin += i + sep.length;
214 t.length -= i + sep.length;
215 }
216 }
217 return css::uno::makeAny(seq.getAsConstList());
218 }
219
parseValue(rtl::OString const & separator,xmlreader::Span const & text,Type type)220 css::uno::Any parseValue(
221 rtl::OString const & separator, xmlreader::Span const & text, Type type)
222 {
223 switch (type) {
224 case TYPE_ANY:
225 throw css::uno::RuntimeException(
226 rtl::OUString(
227 RTL_CONSTASCII_USTRINGPARAM("invalid value of type any")),
228 css::uno::Reference< css::uno::XInterface >());
229 case TYPE_BOOLEAN:
230 return parseSingleValue< sal_Bool >(text);
231 case TYPE_SHORT:
232 return parseSingleValue< sal_Int16 >(text);
233 case TYPE_INT:
234 return parseSingleValue< sal_Int32 >(text);
235 case TYPE_LONG:
236 return parseSingleValue< sal_Int64 >(text);
237 case TYPE_DOUBLE:
238 return parseSingleValue< double >(text);
239 case TYPE_STRING:
240 return parseSingleValue< rtl::OUString >(text);
241 case TYPE_HEXBINARY:
242 return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
243 case TYPE_BOOLEAN_LIST:
244 return parseListValue< sal_Bool >(separator, text);
245 case TYPE_SHORT_LIST:
246 return parseListValue< sal_Int16 >(separator, text);
247 case TYPE_INT_LIST:
248 return parseListValue< sal_Int32 >(separator, text);
249 case TYPE_LONG_LIST:
250 return parseListValue< sal_Int64 >(separator, text);
251 case TYPE_DOUBLE_LIST:
252 return parseListValue< double >(separator, text);
253 case TYPE_STRING_LIST:
254 return parseListValue< rtl::OUString >(separator, text);
255 case TYPE_HEXBINARY_LIST:
256 return parseListValue< css::uno::Sequence< sal_Int8 > >(
257 separator, text);
258 default:
259 OSL_ASSERT(false);
260 throw css::uno::RuntimeException(
261 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
262 css::uno::Reference< css::uno::XInterface >());
263 }
264 }
265
266 }
267
ValueParser(int layer)268 ValueParser::ValueParser(int layer): layer_(layer) {}
269
~ValueParser()270 ValueParser::~ValueParser() {}
271
getTextMode() const272 xmlreader::XmlReader::Text ValueParser::getTextMode() const {
273 if (node_.is()) {
274 switch (state_) {
275 case STATE_TEXT:
276 if (!items_.empty()) {
277 break;
278 }
279 // fall through
280 case STATE_IT:
281 return
282 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
283 separator_.getLength() != 0)
284 ? xmlreader::XmlReader::TEXT_RAW
285 : xmlreader::XmlReader::TEXT_NORMALIZED;
286 default:
287 break;
288 }
289 }
290 return xmlreader::XmlReader::TEXT_NONE;
291 }
292
startElement(xmlreader::XmlReader & reader,int nsId,xmlreader::Span const & name)293 bool ValueParser::startElement(
294 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
295 {
296 if (!node_.is()) {
297 return false;
298 }
299 switch (state_) {
300 case STATE_TEXT:
301 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
302 name.equals(RTL_CONSTASCII_STRINGPARAM("it")) &&
303 isListType(type_) && separator_.getLength() == 0)
304 {
305 pad_.clear();
306 // before first <it>, characters are not ignored; assume they
307 // are only whitespace
308 state_ = STATE_IT;
309 return true;
310 }
311 // fall through
312 case STATE_IT:
313 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
314 name.equals(RTL_CONSTASCII_STRINGPARAM("unicode")) &&
315 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
316 {
317 sal_Int32 scalar = -1;
318 for (;;) {
319 int attrNsId;
320 xmlreader::Span attrLn;
321 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
322 break;
323 }
324 if (attrNsId == ParseManager::NAMESPACE_OOR &&
325 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("scalar")))
326 {
327 if (!parseValue(reader.getAttributeValue(true), &scalar)) {
328 scalar = -1;
329 }
330 break;
331 }
332 }
333 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
334 scalar != 0x0A && scalar != 0x0D)
335 {
336 char c = static_cast< char >(scalar);
337 pad_.add(&c, 1);
338 } else if (scalar == 0xFFFE) {
339 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
340 } else if (scalar == 0xFFFF) {
341 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
342 } else {
343 throw css::uno::RuntimeException(
344 (rtl::OUString(
345 RTL_CONSTASCII_USTRINGPARAM(
346 "bad unicode scalar attribute in ")) +
347 reader.getUrl()),
348 css::uno::Reference< css::uno::XInterface >());
349 }
350 state_ = State(state_ + 1);
351 return true;
352 }
353 break;
354 default:
355 break;
356 }
357 throw css::uno::RuntimeException(
358 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
359 name.convertFromUtf8() +
360 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()),
361 css::uno::Reference< css::uno::XInterface >());
362 }
363
endElement()364 bool ValueParser::endElement() {
365 if (!node_.is()) {
366 return false;
367 }
368 switch (state_) {
369 case STATE_TEXT:
370 {
371 css::uno::Any value;
372 if (items_.empty()) {
373 value = parseValue(separator_, pad_.get(), type_);
374 pad_.clear();
375 } else {
376 switch (type_) {
377 case TYPE_BOOLEAN_LIST:
378 value = convertItems< sal_Bool >();
379 break;
380 case TYPE_SHORT_LIST:
381 value = convertItems< sal_Int16 >();
382 break;
383 case TYPE_INT_LIST:
384 value = convertItems< sal_Int32 >();
385 break;
386 case TYPE_LONG_LIST:
387 value = convertItems< sal_Int64 >();
388 break;
389 case TYPE_DOUBLE_LIST:
390 value = convertItems< double >();
391 break;
392 case TYPE_STRING_LIST:
393 value = convertItems< rtl::OUString >();
394 break;
395 case TYPE_HEXBINARY_LIST:
396 value = convertItems< css::uno::Sequence< sal_Int8 > >();
397 break;
398 default:
399 OSL_ASSERT(false); // this cannot happen
400 break;
401 }
402 items_.clear();
403 }
404 switch (node_->kind()) {
405 case Node::KIND_PROPERTY:
406 dynamic_cast< PropertyNode * >(node_.get())->setValue(
407 layer_, value);
408 break;
409 case Node::KIND_LOCALIZED_PROPERTY:
410 {
411 NodeMap::iterator i(
412 node_->getMembers().find(localizedName_));
413 if (i == node_->getMembers().end()) {
414 node_->getMembers().insert(
415 NodeMap::value_type(
416 localizedName_,
417 new LocalizedValueNode(layer_, value)));
418 } else {
419 dynamic_cast< LocalizedValueNode * >(i->second.get())->
420 setValue(layer_, value);
421 }
422 }
423 break;
424 default:
425 OSL_ASSERT(false); // this cannot happen
426 break;
427 }
428 separator_ = rtl::OString();
429 node_.clear();
430 }
431 break;
432 case STATE_TEXT_UNICODE:
433 case STATE_IT_UNICODE:
434 state_ = State(state_ - 1);
435 break;
436 case STATE_IT:
437 items_.push_back(
438 parseValue(rtl::OString(), pad_.get(), elementType(type_)));
439 pad_.clear();
440 state_ = STATE_TEXT;
441 break;
442 }
443 return true;
444 }
445
characters(xmlreader::Span const & text)446 void ValueParser::characters(xmlreader::Span const & text) {
447 if (node_.is()) {
448 OSL_ASSERT(state_ == STATE_TEXT || state_ == STATE_IT);
449 pad_.add(text.begin, text.length);
450 }
451 }
452
start(rtl::Reference<Node> const & node,rtl::OUString const & localizedName)453 void ValueParser::start(
454 rtl::Reference< Node > const & node, rtl::OUString const & localizedName)
455 {
456 OSL_ASSERT(node.is() && !node_.is());
457 node_ = node;
458 localizedName_ = localizedName;
459 state_ = STATE_TEXT;
460 }
461
getLayer() const462 int ValueParser::getLayer() const {
463 return layer_;
464 }
465
convertItems()466 template< typename T > css::uno::Any ValueParser::convertItems() {
467 css::uno::Sequence< T > seq(items_.size());
468 for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
469 OSL_VERIFY(items_[i] >>= seq[i]);
470 }
471 return css::uno::makeAny(seq);
472 }
473
474 }
475