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