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