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/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>
38 #include "localizedvaluenode.hxx"
40 #include "nodemap.hxx"
41 #include "parsemanager.hxx"
42 #include "propertynode.hxx"
44 #include "valueparser.hxx"
45 #include "xmldata.hxx"
51 bool parseHexDigit(char c
, int * value
) {
53 if (c
>= '0' && c
<= '9') {
57 if (c
>= 'A' && c
<= 'F') {
58 *value
= c
- 'A' + 10;
61 if (c
>= 'a' && c
<= 'f') {
62 *value
= c
- 'a' + 10;
68 bool parseValue(xmlreader::Span
const & text
, sal_Bool
* value
) {
69 assert(text
.is() && value
!= 0);
70 if (text
.equals("true") || text
.equals("1")) {
74 if (text
.equals("false") || text
.equals("0")) {
81 bool parseValue(xmlreader::Span
const & text
, sal_Int16
* value
) {
82 assert(text
.is() && value
!= 0);
83 // For backwards compatibility, support hexadecimal values:
85 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
86 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
87 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
88 static_cast< sal_Int32
>(
90 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
91 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
92 OString(text
.begin
, text
.length
).toInt32();
93 //TODO: check valid lexical representation
94 if (n
>= SAL_MIN_INT16
&& n
<= SAL_MAX_INT16
) {
95 *value
= static_cast< sal_Int16
>(n
);
101 bool parseValue(xmlreader::Span
const & text
, sal_Int32
* value
) {
102 assert(text
.is() && value
!= 0);
103 // For backwards compatibility, support hexadecimal values:
105 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
106 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
107 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
108 static_cast< sal_Int32
>(
110 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
111 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
112 OString(text
.begin
, text
.length
).toInt32();
113 //TODO: check valid lexical representation
117 bool parseValue(xmlreader::Span
const & text
, sal_Int64
* value
) {
118 assert(text
.is() && value
!= 0);
119 // For backwards compatibility, support hexadecimal values:
121 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
122 text
.begin
, text
.length
, RTL_CONSTASCII_STRINGPARAM("0X"),
123 RTL_CONSTASCII_LENGTH("0X")) == 0 ?
124 static_cast< sal_Int64
>(
126 text
.begin
+ RTL_CONSTASCII_LENGTH("0X"),
127 text
.length
- RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
128 OString(text
.begin
, text
.length
).toInt64();
129 //TODO: check valid lexical representation
133 bool parseValue(xmlreader::Span
const & text
, double * value
) {
134 assert(text
.is() && value
!= 0);
135 *value
= OString(text
.begin
, text
.length
).toDouble();
136 //TODO: check valid lexical representation
140 bool parseValue(xmlreader::Span
const & text
, OUString
* value
) {
141 assert(text
.is() && value
!= 0);
142 *value
= text
.convertFromUtf8();
147 xmlreader::Span
const & text
, css::uno::Sequence
< sal_Int8
> * value
)
149 assert(text
.is() && value
!= 0);
150 if ((text
.length
& 1) != 0) {
153 std::vector
< sal_Int8
> seq
;
154 for (sal_Int32 i
= 0; i
!= text
.length
;) {
157 if (!parseHexDigit(text
.begin
[i
++], &n1
) ||
158 !parseHexDigit(text
.begin
[i
++], &n2
))
162 seq
.push_back(static_cast< sal_Int8
>((n1
<< 4) | n2
));
164 *value
= comphelper::containerToSequence(seq
);
168 template< typename T
> css::uno::Any
parseSingleValue(
169 xmlreader::Span
const & text
)
172 if (!parseValue(text
, &val
)) {
173 throw css::uno::RuntimeException("invalid value");
175 return css::uno::makeAny(val
);
178 template< typename T
> css::uno::Any
parseListValue(
179 OString
const & separator
, xmlreader::Span
const & text
)
181 std::vector
< T
> seq
;
183 if (separator
.isEmpty()) {
184 sep
= xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
186 sep
= xmlreader::Span(separator
.getStr(), separator
.getLength());
188 if (text
.length
!= 0) {
189 for (xmlreader::Span
t(text
);;) {
190 sal_Int32 i
= rtl_str_indexOfStr_WithLength(
191 t
.begin
, t
.length
, sep
.begin
, sep
.length
);
194 xmlreader::Span(t
.begin
, i
== -1 ? t
.length
: i
), &val
))
196 throw css::uno::RuntimeException("invalid value");
202 t
.begin
+= i
+ sep
.length
;
203 t
.length
-= i
+ sep
.length
;
206 return css::uno::makeAny(comphelper::containerToSequence(seq
));
209 css::uno::Any
parseValue(
210 OString
const & separator
, xmlreader::Span
const & text
, Type type
)
214 throw css::uno::RuntimeException("invalid value of type any");
216 return parseSingleValue
< sal_Bool
>(text
);
218 return parseSingleValue
< sal_Int16
>(text
);
220 return parseSingleValue
< sal_Int32
>(text
);
222 return parseSingleValue
< sal_Int64
>(text
);
224 return parseSingleValue
< double >(text
);
226 return parseSingleValue
< OUString
>(text
);
228 return parseSingleValue
< css::uno::Sequence
< sal_Int8
> >(text
);
229 case TYPE_BOOLEAN_LIST
:
230 return parseListValue
< sal_Bool
>(separator
, text
);
231 case TYPE_SHORT_LIST
:
232 return parseListValue
< sal_Int16
>(separator
, text
);
234 return parseListValue
< sal_Int32
>(separator
, text
);
236 return parseListValue
< sal_Int64
>(separator
, text
);
237 case TYPE_DOUBLE_LIST
:
238 return parseListValue
< double >(separator
, text
);
239 case TYPE_STRING_LIST
:
240 return parseListValue
< OUString
>(separator
, text
);
241 case TYPE_HEXBINARY_LIST
:
242 return parseListValue
< css::uno::Sequence
< sal_Int8
> >(
246 throw css::uno::RuntimeException("this cannot happen");
252 ValueParser::ValueParser(int layer
): type_(TYPE_ERROR
), layer_(layer
), state_() {}
254 ValueParser::~ValueParser() {}
256 xmlreader::XmlReader::Text
ValueParser::getTextMode() const {
260 if (!items_
.empty()) {
266 (type_
== TYPE_STRING
|| type_
== TYPE_STRING_LIST
||
267 !separator_
.isEmpty())
268 ? xmlreader::XmlReader::TEXT_RAW
269 : xmlreader::XmlReader::TEXT_NORMALIZED
;
274 return xmlreader::XmlReader::TEXT_NONE
;
277 bool ValueParser::startElement(
278 xmlreader::XmlReader
& reader
, int nsId
, xmlreader::Span
const & name
,
279 std::set
< OUString
> const *)
286 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&& name
.equals("it") &&
287 isListType(type_
) && separator_
.isEmpty())
290 // before first <it>, characters are not ignored; assume they
291 // are only whitespace
297 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
&&
298 name
.equals("unicode") &&
299 (type_
== TYPE_STRING
|| type_
== TYPE_STRING_LIST
))
301 sal_Int32 scalar
= -1;
304 xmlreader::Span attrLn
;
305 if (!reader
.nextAttribute(&attrNsId
, &attrLn
)) {
308 if (attrNsId
== ParseManager::NAMESPACE_OOR
&&
309 attrLn
.equals("scalar"))
311 if (!parseValue(reader
.getAttributeValue(true), &scalar
)) {
317 if (scalar
>= 0 && scalar
< 0x20 && scalar
!= 0x09 &&
318 scalar
!= 0x0A && scalar
!= 0x0D)
320 char c
= static_cast< char >(scalar
);
322 } else if (scalar
== 0xFFFE) {
323 pad_
.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
324 } else if (scalar
== 0xFFFF) {
325 pad_
.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
327 throw css::uno::RuntimeException(
328 "bad unicode scalar attribute in " + reader
.getUrl());
330 state_
= State(state_
+ 1);
337 throw css::uno::RuntimeException(
338 "bad member <" + name
.convertFromUtf8() + "> in " + reader
.getUrl());
341 bool ValueParser::endElement() {
348 css::uno::Any
*pValue
= NULL
;
350 switch (node_
->kind()) {
351 case Node::KIND_PROPERTY
:
352 pValue
= static_cast< PropertyNode
* >(node_
.get())->getValuePtr(layer_
);
354 case Node::KIND_LOCALIZED_PROPERTY
:
356 NodeMap
& members
= node_
->getMembers();
357 NodeMap::iterator
i(members
.find(localizedName_
));
358 LocalizedValueNode
*pLVNode
;
359 if (i
== members
.end()) {
360 pLVNode
= new LocalizedValueNode(layer_
);
362 NodeMap::value_type(localizedName_
, pLVNode
));
364 pLVNode
= static_cast< LocalizedValueNode
* >(i
->second
.get());
366 pValue
= pLVNode
->getValuePtr(layer_
);
370 assert(false); // this cannot happen
374 if (items_
.empty()) {
375 *pValue
= parseValue(separator_
, pad_
.get(), type_
);
379 case TYPE_BOOLEAN_LIST
:
380 *pValue
= convertItems
< sal_Bool
>();
382 case TYPE_SHORT_LIST
:
383 *pValue
= convertItems
< sal_Int16
>();
386 *pValue
= convertItems
< sal_Int32
>();
389 *pValue
= convertItems
< sal_Int64
>();
391 case TYPE_DOUBLE_LIST
:
392 *pValue
= convertItems
< double >();
394 case TYPE_STRING_LIST
:
395 *pValue
= convertItems
< OUString
>();
397 case TYPE_HEXBINARY_LIST
:
398 *pValue
= convertItems
< css::uno::Sequence
< sal_Int8
> >();
401 assert(false); // this cannot happen
410 case STATE_TEXT_UNICODE
:
411 case STATE_IT_UNICODE
:
412 state_
= State(state_
- 1);
416 parseValue(OString(), pad_
.get(), elementType(type_
)));
424 void ValueParser::characters(xmlreader::Span
const & text
) {
426 assert(state_
== STATE_TEXT
|| state_
== STATE_IT
);
427 pad_
.add(text
.begin
, text
.length
);
431 void ValueParser::start(
432 rtl::Reference
< Node
> const & node
, OUString
const & localizedName
)
434 assert(node
.is() && !node_
.is());
436 localizedName_
= localizedName
;
441 template< typename T
> css::uno::Any
ValueParser::convertItems() {
442 css::uno::Sequence
< T
> seq(items_
.size());
443 for (sal_Int32 i
= 0; i
< seq
.getLength(); ++i
) {
444 bool ok
= (items_
[i
] >>= seq
[i
]);
446 (void) ok
; // avoid warnings
448 return css::uno::makeAny(seq
);
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */