LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/configmgr/source - valueparser.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 150 217 69.1 %
Date: 2013-07-09 Functions: 28 38 73.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      22             : #include <cassert>
      23             : #include <set>
      24             : 
      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.hxx"
      34             : #include "sal/types.h"
      35             : #include "xmlreader/span.hxx"
      36             : #include "xmlreader/xmlreader.hxx"
      37             : 
      38             : #include "localizedvaluenode.hxx"
      39             : #include "node.hxx"
      40             : #include "nodemap.hxx"
      41             : #include "parsemanager.hxx"
      42             : #include "propertynode.hxx"
      43             : #include "type.hxx"
      44             : #include "valueparser.hxx"
      45             : #include "xmldata.hxx"
      46             : 
      47             : namespace configmgr {
      48             : 
      49             : namespace {
      50             : 
      51       30600 : bool parseHexDigit(char c, int * value) {
      52             :     assert(value != 0);
      53       30600 :     if (c >= '0' && c <= '9') {
      54        8874 :         *value = c - '0';
      55        8874 :         return true;
      56             :     }
      57       21726 :     if (c >= 'A' && c <= 'F') {
      58       16065 :         *value = c - 'A' + 10;
      59       16065 :         return true;
      60             :     }
      61        5661 :     if (c >= 'a' && c <= 'f') {
      62        5661 :         *value = c - 'a' + 10;
      63        5661 :         return true;
      64             :     }
      65           0 :     return false;
      66             : }
      67             : 
      68      343371 : bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
      69             :     assert(text.is() && value != 0);
      70      343371 :     if (text.equals("true") || text.equals("1")) {
      71      198976 :         *value = true;
      72      198976 :         return true;
      73             :     }
      74      144395 :     if (text.equals("false") || text.equals("0")) {
      75      144395 :         *value = false;
      76      144395 :         return true;
      77             :     }
      78           0 :     return false;
      79             : }
      80             : 
      81       14185 : bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
      82             :     assert(text.is() && value != 0);
      83             :     // For backwards compatibility, support hexadecimal values:
      84             :     sal_Int32 n =
      85             :         rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
      86             :             text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
      87       14185 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
      88             :         static_cast< sal_Int32 >(
      89             :             OString(
      90           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
      91       14185 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
      92       28370 :         OString(text.begin, text.length).toInt32();
      93             :         //TODO: check valid lexical representation
      94       14185 :     if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
      95       14185 :         *value = static_cast< sal_Int16 >(n);
      96       14185 :         return true;
      97             :     }
      98           0 :     return false;
      99             : }
     100             : 
     101      539371 : bool parseValue(xmlreader::Span const & text, sal_Int32 * value) {
     102             :     assert(text.is() && value != 0);
     103             :     // For backwards compatibility, support hexadecimal values:
     104             :     *value =
     105             :         rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
     106             :             text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
     107      539371 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
     108             :         static_cast< sal_Int32 >(
     109             :             OString(
     110           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
     111      539371 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
     112     1078742 :         OString(text.begin, text.length).toInt32();
     113             :         //TODO: check valid lexical representation
     114      539371 :     return true;
     115             : }
     116             : 
     117        6640 : bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
     118             :     assert(text.is() && value != 0);
     119             :     // For backwards compatibility, support hexadecimal values:
     120             :     *value =
     121             :         rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
     122             :             text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
     123        6640 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
     124             :         static_cast< sal_Int64 >(
     125             :             OString(
     126           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
     127        6640 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
     128       13280 :         OString(text.begin, text.length).toInt64();
     129             :         //TODO: check valid lexical representation
     130        6640 :     return true;
     131             : }
     132             : 
     133       11781 : bool parseValue(xmlreader::Span const & text, double * value) {
     134             :     assert(text.is() && value != 0);
     135       11781 :     *value = OString(text.begin, text.length).toDouble();
     136             :         //TODO: check valid lexical representation
     137       11781 :     return true;
     138             : }
     139             : 
     140     2076188 : bool parseValue(xmlreader::Span const & text, OUString * value) {
     141             :     assert(text.is() && value != 0);
     142     2076188 :     *value = text.convertFromUtf8();
     143     2076188 :     return true;
     144             : }
     145             : 
     146        5049 : bool parseValue(
     147             :     xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
     148             : {
     149             :     assert(text.is() && value != 0);
     150        5049 :     if ((text.length & 1) != 0) {
     151           0 :         return false;
     152             :     }
     153        5049 :     comphelper::SequenceAsVector< sal_Int8 > seq;
     154       25398 :     for (sal_Int32 i = 0; i != text.length;) {
     155             :         int n1;
     156             :         int n2;
     157       30600 :         if (!parseHexDigit(text.begin[i++], &n1) ||
     158       15300 :             !parseHexDigit(text.begin[i++], &n2))
     159             :         {
     160           0 :             return false;
     161             :         }
     162       15300 :         seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
     163             :     }
     164        5049 :     *value = seq.getAsConstList();
     165        5049 :     return true;
     166             : }
     167             : 
     168     2692285 : template< typename T > css::uno::Any parseSingleValue(
     169             :     xmlreader::Span const & text)
     170             : {
     171     1787103 :     T val;
     172     2692285 :     if (!parseValue(text, &val)) {
     173           0 :         throw css::uno::RuntimeException(
     174             :             OUString("invalid value"),
     175           0 :             css::uno::Reference< css::uno::XInterface >());
     176             :     }
     177     2692285 :     return css::uno::makeAny(val);
     178             : }
     179             : 
     180      114915 : template< typename T > css::uno::Any parseListValue(
     181             :     OString const & separator, xmlreader::Span const & text)
     182             : {
     183      114915 :     comphelper::SequenceAsVector< T > seq;
     184      114915 :     xmlreader::Span sep;
     185      114915 :     if (separator.isEmpty()) {
     186       97946 :         sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
     187             :     } else {
     188       16969 :         sep = xmlreader::Span(separator.getStr(), separator.getLength());
     189             :     }
     190      114915 :     if (text.length != 0) {
     191      304300 :         for (xmlreader::Span t(text);;) {
     192             :             sal_Int32 i = rtl_str_indexOfStr_WithLength(
     193      304300 :                 t.begin, t.length, sep.begin, sep.length);
     194      294134 :             T val;
     195      608600 :             if (!parseValue(
     196      608600 :                     xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
     197             :             {
     198           0 :                 throw css::uno::RuntimeException(
     199             :                     OUString("invalid value"),
     200           0 :                     css::uno::Reference< css::uno::XInterface >());
     201             :             }
     202      304300 :             seq.push_back(val);
     203      304300 :             if (i < 0) {
     204       97257 :                 break;
     205             :             }
     206      207043 :             t.begin += i + sep.length;
     207      207043 :             t.length -= i + sep.length;
     208             :         }
     209             :     }
     210      114915 :     return css::uno::makeAny(seq.getAsConstList());
     211             : }
     212             : 
     213     2807200 : css::uno::Any parseValue(
     214             :     OString const & separator, xmlreader::Span const & text, Type type)
     215             : {
     216     2807200 :     switch (type) {
     217             :     case TYPE_ANY:
     218             :         throw css::uno::RuntimeException(
     219             :             OUString("invalid value of type any"),
     220           0 :             css::uno::Reference< css::uno::XInterface >());
     221             :     case TYPE_BOOLEAN:
     222      343371 :         return parseSingleValue< sal_Bool >(text);
     223             :     case TYPE_SHORT:
     224       14185 :         return parseSingleValue< sal_Int16 >(text);
     225             :     case TYPE_INT:
     226      531041 :         return parseSingleValue< sal_Int32 >(text);
     227             :     case TYPE_LONG:
     228        4804 :         return parseSingleValue< sal_Int64 >(text);
     229             :     case TYPE_DOUBLE:
     230       11781 :         return parseSingleValue< double >(text);
     231             :     case TYPE_STRING:
     232     1782054 :         return parseSingleValue< OUString >(text);
     233             :     case TYPE_HEXBINARY:
     234        5049 :         return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
     235             :     case TYPE_BOOLEAN_LIST:
     236           0 :         return parseListValue< sal_Bool >(separator, text);
     237             :     case TYPE_SHORT_LIST:
     238           0 :         return parseListValue< sal_Int16 >(separator, text);
     239             :     case TYPE_INT_LIST:
     240         459 :         return parseListValue< sal_Int32 >(separator, text);
     241             :     case TYPE_LONG_LIST:
     242         153 :         return parseListValue< sal_Int64 >(separator, text);
     243             :     case TYPE_DOUBLE_LIST:
     244           0 :         return parseListValue< double >(separator, text);
     245             :     case TYPE_STRING_LIST:
     246      114303 :         return parseListValue< OUString >(separator, text);
     247             :     case TYPE_HEXBINARY_LIST:
     248             :         return parseListValue< css::uno::Sequence< sal_Int8 > >(
     249           0 :             separator, text);
     250             :     default:
     251             :         assert(false);
     252             :         throw css::uno::RuntimeException(
     253             :             OUString("this cannot happen"),
     254           0 :             css::uno::Reference< css::uno::XInterface >());
     255             :     }
     256             : }
     257             : 
     258             : }
     259             : 
     260       40848 : ValueParser::ValueParser(int layer): layer_(layer), state_() {}
     261             : 
     262       40848 : ValueParser::~ValueParser() {}
     263             : 
     264    18600345 : xmlreader::XmlReader::Text ValueParser::getTextMode() const {
     265    18600345 :     if (node_.is()) {
     266     5479843 :         switch (state_) {
     267             :         case STATE_TEXT:
     268     5432941 :             if (!items_.empty()) {
     269       23451 :                 break;
     270             :             }
     271             :             // fall through
     272             :         case STATE_IT:
     273             :             return
     274     9372417 :                 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
     275     1821533 :                  !separator_.isEmpty())
     276             :                 ? xmlreader::XmlReader::TEXT_RAW
     277     9091251 :                 : xmlreader::XmlReader::TEXT_NORMALIZED;
     278             :         default:
     279           0 :             break;
     280             :         }
     281             :     }
     282    13143953 :     return xmlreader::XmlReader::TEXT_NONE;
     283             : }
     284             : 
     285     7980723 : bool ValueParser::startElement(
     286             :     xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
     287             :     std::set< OUString > const *)
     288             : {
     289     7980723 :     if (!node_.is()) {
     290     7957272 :         return false;
     291             :     }
     292       23451 :     switch (state_) {
     293             :     case STATE_TEXT:
     294       70353 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("it") &&
     295       70353 :             isListType(type_) && separator_.isEmpty())
     296             :         {
     297       23451 :             pad_.clear();
     298             :                 // before first <it>, characters are not ignored; assume they
     299             :                 // are only whitespace
     300       23451 :             state_ = STATE_IT;
     301       23451 :             return true;
     302             :         }
     303             :         // fall through
     304             :     case STATE_IT:
     305           0 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     306           0 :             name.equals("unicode") &&
     307           0 :             (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
     308             :         {
     309           0 :             sal_Int32 scalar = -1;
     310             :             for (;;) {
     311             :                 int attrNsId;
     312           0 :                 xmlreader::Span attrLn;
     313           0 :                 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     314           0 :                     break;
     315             :                 }
     316           0 :                 if (attrNsId == ParseManager::NAMESPACE_OOR &&
     317           0 :                     attrLn.equals("scalar"))
     318             :                 {
     319           0 :                     if (!parseValue(reader.getAttributeValue(true), &scalar)) {
     320           0 :                         scalar = -1;
     321             :                     }
     322           0 :                     break;
     323             :                 }
     324           0 :             }
     325           0 :             if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
     326           0 :                 scalar != 0x0A && scalar != 0x0D)
     327             :             {
     328           0 :                 char c = static_cast< char >(scalar);
     329           0 :                 pad_.add(&c, 1);
     330           0 :             } else if (scalar == 0xFFFE) {
     331           0 :                 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
     332           0 :             } else if (scalar == 0xFFFF) {
     333           0 :                 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
     334             :             } else {
     335             :                 throw css::uno::RuntimeException(
     336           0 :                     (OUString("bad unicode scalar attribute in ") +
     337           0 :                      reader.getUrl()),
     338           0 :                     css::uno::Reference< css::uno::XInterface >());
     339             :             }
     340           0 :             state_ = State(state_ + 1);
     341           0 :             return true;
     342             :         }
     343           0 :         break;
     344             :     default:
     345           0 :         break;
     346             :     }
     347             :     throw css::uno::RuntimeException(
     348           0 :         (OUString("bad member <") +
     349           0 :          name.convertFromUtf8() +
     350           0 :          OUString("> in ") + reader.getUrl()),
     351           0 :         css::uno::Reference< css::uno::XInterface >());
     352             : }
     353             : 
     354     7980723 : bool ValueParser::endElement() {
     355     7980723 :     if (!node_.is()) {
     356     5168601 :         return false;
     357             :     }
     358     2812122 :     switch (state_) {
     359             :     case STATE_TEXT:
     360             :         {
     361     2788671 :             css::uno::Any value;
     362     2788671 :             if (items_.empty()) {
     363     2783749 :                 value = parseValue(separator_, pad_.get(), type_);
     364     2783749 :                 pad_.clear();
     365             :             } else {
     366        4922 :                 switch (type_) {
     367             :                 case TYPE_BOOLEAN_LIST:
     368           0 :                     value = convertItems< sal_Bool >();
     369           0 :                     break;
     370             :                 case TYPE_SHORT_LIST:
     371           0 :                     value = convertItems< sal_Int16 >();
     372           0 :                     break;
     373             :                 case TYPE_INT_LIST:
     374           0 :                     value = convertItems< sal_Int32 >();
     375           0 :                     break;
     376             :                 case TYPE_LONG_LIST:
     377           0 :                     value = convertItems< sal_Int64 >();
     378           0 :                     break;
     379             :                 case TYPE_DOUBLE_LIST:
     380           0 :                     value = convertItems< double >();
     381           0 :                     break;
     382             :                 case TYPE_STRING_LIST:
     383        4922 :                     value = convertItems< OUString >();
     384        4922 :                     break;
     385             :                 case TYPE_HEXBINARY_LIST:
     386           0 :                     value = convertItems< css::uno::Sequence< sal_Int8 > >();
     387           0 :                     break;
     388             :                 default:
     389             :                     assert(false); // this cannot happen
     390           0 :                     break;
     391             :                 }
     392        4922 :                 items_.clear();
     393             :             }
     394     2788671 :             switch (node_->kind()) {
     395             :             case Node::KIND_PROPERTY:
     396     1879216 :                 dynamic_cast< PropertyNode * >(node_.get())->setValue(
     397     3758432 :                     layer_, value);
     398     1879216 :                 break;
     399             :             case Node::KIND_LOCALIZED_PROPERTY:
     400             :                 {
     401      909455 :                     NodeMap & members = node_->getMembers();
     402      909455 :                     NodeMap::iterator i(members.find(localizedName_));
     403      909455 :                     if (i == members.end()) {
     404             :                         members.insert(
     405             :                             NodeMap::value_type(
     406             :                                 localizedName_,
     407      909245 :                                 new LocalizedValueNode(layer_, value)));
     408             :                     } else {
     409         210 :                         dynamic_cast< LocalizedValueNode * >(i->second.get())->
     410         420 :                             setValue(layer_, value);
     411             :                     }
     412             :                 }
     413      909455 :                 break;
     414             :             default:
     415             :                 assert(false); // this cannot happen
     416           0 :                 break;
     417             :             }
     418     2788671 :             separator_ = OString();
     419     2788671 :             node_.clear();
     420             :         }
     421     2788671 :         break;
     422             :     case STATE_TEXT_UNICODE:
     423             :     case STATE_IT_UNICODE:
     424           0 :         state_ = State(state_ - 1);
     425           0 :         break;
     426             :     case STATE_IT:
     427             :         items_.push_back(
     428       23451 :             parseValue(OString(), pad_.get(), elementType(type_)));
     429       23451 :         pad_.clear();
     430       23451 :         state_ = STATE_TEXT;
     431       23451 :         break;
     432             :     }
     433     2812122 :     return true;
     434             : }
     435             : 
     436     2644270 : void ValueParser::characters(xmlreader::Span const & text) {
     437     2644270 :     if (node_.is()) {
     438             :         assert(state_ == STATE_TEXT || state_ == STATE_IT);
     439     2644270 :         pad_.add(text.begin, text.length);
     440             :     }
     441     2644270 : }
     442             : 
     443     2788671 : void ValueParser::start(
     444             :     rtl::Reference< Node > const & node, OUString const & localizedName)
     445             : {
     446             :     assert(node.is() && !node_.is());
     447     2788671 :     node_ = node;
     448     2788671 :     localizedName_ = localizedName;
     449     2788671 :     state_ = STATE_TEXT;
     450     2788671 : }
     451             : 
     452     9204434 : int ValueParser::getLayer() const {
     453     9204434 :     return layer_;
     454             : }
     455             : 
     456        4922 : template< typename T > css::uno::Any ValueParser::convertItems() {
     457        4922 :     css::uno::Sequence< T > seq(items_.size());
     458       28373 :     for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
     459       23451 :         bool ok = (items_[i] >>= seq[i]);
     460             :         assert(ok);
     461             :         (void) ok; // avoid warnings
     462             :     }
     463        4922 :     return css::uno::makeAny(seq);
     464             : }
     465             : 
     466             : }
     467             : 
     468             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10