1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
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"
39 #include "localizedvaluenode.hxx"
41 #include "nodemap.hxx"
42 #include "parsemanager.hxx"
43 #include "propertynode.hxx"
45 #include "valueparser.hxx"
46 #include "xmldata.hxx"
52 bool parseHexDigit(char c
, int * value
) {
54 if (c
>= '0' && c
<= '9') {
58 if (c
>= 'A' && c
<= 'F') {
59 *value
= c
- 'A' + 10;
62 if (c
>= 'a' && c
<= 'f') {
63 *value
= c
- 'a' + 10;
69 bool parseValue(xmlreader::Span
const & text
, sal_Bool
* value
) {
70 assert(text
.is() && value
!= 0);
71 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("true")) ||
72 text
.equals(RTL_CONSTASCII_STRINGPARAM("1")))
77 if (text
.equals(RTL_CONSTASCII_STRINGPARAM("false")) ||
78 text
.equals(RTL_CONSTASCII_STRINGPARAM("0")))
86 bool parseValue(xmlreader::Span
const & text
, sal_Int16
* value
) {
87 assert(text
.is() && value
!= 0);
88 // For backwards compatibility, support hexadecimal values:
90 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
91 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
92 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
94 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
95 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
96 rtl::OString(text
.begin
, text
.length
).toInt32();
97 //TODO: check valid lexical representation
98 if (n
>= SAL_MIN_INT16
&& n
<= SAL_MAX_INT16
) {
99 *value
= static_cast< sal_Int16
>(n
);
105 bool parseValue(xmlreader::Span
const & text
, sal_Int32
* value
) {
106 assert(text
.is() && value
!= 0);
107 // For backwards compatibility, support hexadecimal values:
109 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
110 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
111 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
113 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
114 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
115 rtl::OString(text
.begin
, text
.length
).toInt32();
116 //TODO: check valid lexical representation
120 bool parseValue(xmlreader::Span
const & text
, sal_Int64
* value
) {
121 assert(text
.is() && value
!= 0);
122 // For backwards compatibility, support hexadecimal values:
124 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
125 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
126 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
128 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
129 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toInt64(16) :
130 rtl::OString(text
.begin
, text
.length
).toInt64();
131 //TODO: check valid lexical representation
135 bool parseValue(xmlreader::Span
const & text
, double * value
) {
136 assert(text
.is() && value
!= 0);
137 *value
= rtl::OString(text
.begin
, text
.length
).toDouble();
138 //TODO: check valid lexical representation
142 bool parseValue(xmlreader::Span
const & text
, rtl::OUString
* value
) {
143 assert(text
.is() && value
!= 0);
144 *value
= text
.convertFromUtf8();
149 xmlreader::Span
const & text
, css::uno::Sequence
< sal_Int8
> * value
)
151 assert(text
.is() && value
!= 0);
152 if ((text
.length
& 1) != 0) {
155 comphelper::SequenceAsVector
< sal_Int8
> seq
;
156 for (sal_Int32 i
= 0; i
!= text
.length
;) {
159 if (!parseHexDigit(text
.begin
[i
++], &n1
) ||
160 !parseHexDigit(text
.begin
[i
++], &n2
))
164 seq
.push_back(static_cast< sal_Int8
>((n1
<< 4) | n2
));
166 *value
= seq
.getAsConstList();
170 template< typename T
> css::uno::Any
parseSingleValue(
171 xmlreader::Span
const & text
)
174 if (!parseValue(text
, &val
)) {
175 throw css::uno::RuntimeException(
176 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
177 css::uno::Reference
< css::uno::XInterface
>());
179 return css::uno::makeAny(val
);
182 template< typename T
> css::uno::Any
parseListValue(
183 rtl::OString
const & separator
, xmlreader::Span
const & text
)
185 comphelper::SequenceAsVector
< T
> seq
;
187 if (separator
.isEmpty()) {
188 sep
= xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
190 sep
= xmlreader::Span(separator
.getStr(), separator
.getLength());
192 if (text
.length
!= 0) {
193 for (xmlreader::Span
t(text
);;) {
194 sal_Int32 i
= rtl_str_indexOfStr_WithLength(
195 t
.begin
, t
.length
, sep
.begin
, sep
.length
);
198 xmlreader::Span(t
.begin
, i
== -1 ? t
.length
: i
), &val
))
200 throw css::uno::RuntimeException(
201 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")),
202 css::uno::Reference
< css::uno::XInterface
>());
208 t
.begin
+= i
+ sep
.length
;
209 t
.length
-= i
+ sep
.length
;
212 return css::uno::makeAny(seq
.getAsConstList());
215 css::uno::Any
parseValue(
216 rtl::OString
const & separator
, xmlreader::Span
const & text
, Type type
)
220 throw css::uno::RuntimeException(
222 RTL_CONSTASCII_USTRINGPARAM("invalid value of type any")),
223 css::uno::Reference
< css::uno::XInterface
>());
225 return parseSingleValue
< sal_Bool
>(text
);
227 return parseSingleValue
< sal_Int16
>(text
);
229 return parseSingleValue
< sal_Int32
>(text
);
231 return parseSingleValue
< sal_Int64
>(text
);
233 return parseSingleValue
< double >(text
);
235 return parseSingleValue
< rtl::OUString
>(text
);
237 return parseSingleValue
< css::uno::Sequence
< sal_Int8
> >(text
);
238 case TYPE_BOOLEAN_LIST
:
239 return parseListValue
< sal_Bool
>(separator
, text
);
240 case TYPE_SHORT_LIST
:
241 return parseListValue
< sal_Int16
>(separator
, text
);
243 return parseListValue
< sal_Int32
>(separator
, text
);
245 return parseListValue
< sal_Int64
>(separator
, text
);
246 case TYPE_DOUBLE_LIST
:
247 return parseListValue
< double >(separator
, text
);
248 case TYPE_STRING_LIST
:
249 return parseListValue
< rtl::OUString
>(separator
, text
);
250 case TYPE_HEXBINARY_LIST
:
251 return parseListValue
< css::uno::Sequence
< sal_Int8
> >(
255 throw css::uno::RuntimeException(
256 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
257 css::uno::Reference
< css::uno::XInterface
>());
263 ValueParser::ValueParser(int layer
): layer_(layer
) {}
265 ValueParser::~ValueParser() {}
267 xmlreader::XmlReader::Text
ValueParser::getTextMode() const {
271 if (!items_
.empty()) {
277 (type_
== TYPE_STRING
|| type_
== TYPE_STRING_LIST
||
278 !separator_
.isEmpty())
279 ? xmlreader::XmlReader::TEXT_RAW
280 : xmlreader::XmlReader::TEXT_NORMALIZED
;
285 return xmlreader::XmlReader::TEXT_NONE
;
288 bool ValueParser::startElement(
289 xmlreader::XmlReader
& reader
, int nsId
, xmlreader::Span
const & name
,
290 std::set
< rtl::OUString
> const *)
297 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
298 name
.equals(RTL_CONSTASCII_STRINGPARAM("it")) &&
299 isListType(type_
) && separator_
.isEmpty())
302 // before first <it>, characters are not ignored; assume they
303 // are only whitespace
309 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
310 name
.equals(RTL_CONSTASCII_STRINGPARAM("unicode")) &&
311 (type_
== TYPE_STRING
|| type_
== TYPE_STRING_LIST
))
313 sal_Int32 scalar
= -1;
316 xmlreader::Span attrLn
;
317 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
320 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
321 attrLn
.equals(RTL_CONSTASCII_STRINGPARAM("scalar")))
323 if (!parseValue(reader
.getAttributeValue(true), &scalar
)) {
329 if (scalar
>= 0 && scalar
< 0x20 && scalar
!= 0x09 &&
330 scalar
!= 0x0A && scalar
!= 0x0D)
332 char c
= static_cast< char >(scalar
);
334 } else if (scalar
== 0xFFFE) {
335 pad_
.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
336 } else if (scalar
== 0xFFFF) {
337 pad_
.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
339 throw css::uno::RuntimeException(
341 RTL_CONSTASCII_USTRINGPARAM(
342 "bad unicode scalar attribute in ")) +
344 css::uno::Reference
< css::uno::XInterface
>());
346 state_
= State(state_
+ 1);
353 throw css::uno::RuntimeException(
354 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
355 name
.convertFromUtf8() +
356 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader
.getUrl()),
357 css::uno::Reference
< css::uno::XInterface
>());
360 bool ValueParser::endElement() {
368 if (items_
.empty()) {
369 value
= parseValue(separator_
, pad_
.get(), type_
);
373 case TYPE_BOOLEAN_LIST
:
374 value
= convertItems
< sal_Bool
>();
376 case TYPE_SHORT_LIST
:
377 value
= convertItems
< sal_Int16
>();
380 value
= convertItems
< sal_Int32
>();
383 value
= convertItems
< sal_Int64
>();
385 case TYPE_DOUBLE_LIST
:
386 value
= convertItems
< double >();
388 case TYPE_STRING_LIST
:
389 value
= convertItems
< rtl::OUString
>();
391 case TYPE_HEXBINARY_LIST
:
392 value
= convertItems
< css::uno::Sequence
< sal_Int8
> >();
395 assert(false); // this cannot happen
400 switch (node_
->kind()) {
401 case Node::KIND_PROPERTY
:
402 dynamic_cast< PropertyNode
* >(node_
.get())->setValue(
405 case Node::KIND_LOCALIZED_PROPERTY
:
407 NodeMap
& members
= node_
->getMembers();
408 NodeMap::iterator
i(members
.find(localizedName_
));
409 if (i
== members
.end()) {
413 new LocalizedValueNode(layer_
, value
)));
415 dynamic_cast< LocalizedValueNode
* >(i
->second
.get())->
416 setValue(layer_
, value
);
421 assert(false); // this cannot happen
424 separator_
= rtl::OString();
428 case STATE_TEXT_UNICODE
:
429 case STATE_IT_UNICODE
:
430 state_
= State(state_
- 1);
434 parseValue(rtl::OString(), pad_
.get(), elementType(type_
)));
442 void ValueParser::characters(xmlreader::Span
const & text
) {
444 assert(state_
== STATE_TEXT
|| state_
== STATE_IT
);
445 pad_
.add(text
.begin
, text
.length
);
449 void ValueParser::start(
450 rtl::Reference
< Node
> const & node
, rtl::OUString
const & localizedName
)
452 assert(node
.is() && !node_
.is());
454 localizedName_
= localizedName
;
458 int ValueParser::getLayer() const {
462 template< typename T
> css::uno::Any
ValueParser::convertItems() {
463 css::uno::Sequence
< T
> seq(items_
.size());
464 for (sal_Int32 i
= 0; i
< seq
.getLength(); ++i
) {
465 bool ok
= (items_
[i
] >>= seq
[i
]);
467 (void) ok
; // avoid warnings
469 return css::uno::makeAny(seq
);
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */