LCOV - code coverage report
Current view: top level - configmgr/source - valueparser.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 150 214 70.1 %
Date: 2014-04-11 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       33600 : bool parseHexDigit(char c, int * value) {
      52             :     assert(value != 0);
      53       33600 :     if (c >= '0' && c <= '9') {
      54        9744 :         *value = c - '0';
      55        9744 :         return true;
      56             :     }
      57       23856 :     if (c >= 'A' && c <= 'F') {
      58       17640 :         *value = c - 'A' + 10;
      59       17640 :         return true;
      60             :     }
      61        6216 :     if (c >= 'a' && c <= 'f') {
      62        6216 :         *value = c - 'a' + 10;
      63        6216 :         return true;
      64             :     }
      65           0 :     return false;
      66             : }
      67             : 
      68      392353 : bool parseValue(xmlreader::Span const & text, sal_Bool * value) {
      69             :     assert(text.is() && value != 0);
      70      392353 :     if (text.equals("true") || text.equals("1")) {
      71      226111 :         *value = true;
      72      226111 :         return true;
      73             :     }
      74      166242 :     if (text.equals("false") || text.equals("0")) {
      75      166242 :         *value = false;
      76      166242 :         return true;
      77             :     }
      78           0 :     return false;
      79             : }
      80             : 
      81       15386 : 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       15386 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
      88             :         static_cast< sal_Int32 >(
      89             :             OString(
      90           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
      91       15386 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
      92       30772 :         OString(text.begin, text.length).toInt32();
      93             :         //TODO: check valid lexical representation
      94       15386 :     if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) {
      95       15386 :         *value = static_cast< sal_Int16 >(n);
      96       15386 :         return true;
      97             :     }
      98           0 :     return false;
      99             : }
     100             : 
     101      605933 : 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      605933 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
     108             :         static_cast< sal_Int32 >(
     109             :             OString(
     110           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
     111      605933 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
     112     1211866 :         OString(text.begin, text.length).toInt32();
     113             :         //TODO: check valid lexical representation
     114      605933 :     return true;
     115             : }
     116             : 
     117        7224 : 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        7224 :             RTL_CONSTASCII_LENGTH("0X")) == 0 ?
     124             :         static_cast< sal_Int64 >(
     125             :             OString(
     126           0 :                 text.begin + RTL_CONSTASCII_LENGTH("0X"),
     127        7224 :                 text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
     128       14448 :         OString(text.begin, text.length).toInt64();
     129             :         //TODO: check valid lexical representation
     130        7224 :     return true;
     131             : }
     132             : 
     133       13272 : bool parseValue(xmlreader::Span const & text, double * value) {
     134             :     assert(text.is() && value != 0);
     135       13272 :     *value = OString(text.begin, text.length).toDouble();
     136             :         //TODO: check valid lexical representation
     137       13272 :     return true;
     138             : }
     139             : 
     140     2436046 : bool parseValue(xmlreader::Span const & text, OUString * value) {
     141             :     assert(text.is() && value != 0);
     142     2436046 :     *value = text.convertFromUtf8();
     143     2436046 :     return true;
     144             : }
     145             : 
     146        5544 : bool parseValue(
     147             :     xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
     148             : {
     149             :     assert(text.is() && value != 0);
     150        5544 :     if ((text.length & 1) != 0) {
     151           0 :         return false;
     152             :     }
     153        5544 :     comphelper::SequenceAsVector< sal_Int8 > seq;
     154       27888 :     for (sal_Int32 i = 0; i != text.length;) {
     155             :         int n1;
     156             :         int n2;
     157       33600 :         if (!parseHexDigit(text.begin[i++], &n1) ||
     158       16800 :             !parseHexDigit(text.begin[i++], &n2))
     159             :         {
     160           0 :             return false;
     161             :         }
     162       16800 :         seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2));
     163             :     }
     164        5544 :     *value = seq.getAsConstList();
     165        5544 :     return true;
     166             : }
     167             : 
     168     3079110 : template< typename T > css::uno::Any parseSingleValue(
     169             :     xmlreader::Span const & text)
     170             : {
     171     2056030 :     T val;
     172     3079110 :     if (!parseValue(text, &val)) {
     173           0 :         throw css::uno::RuntimeException(
     174           0 :             "invalid value", css::uno::Reference< css::uno::XInterface >());
     175             :     }
     176     3079110 :     return css::uno::makeAny(val);
     177             : }
     178             : 
     179      151536 : template< typename T > css::uno::Any parseListValue(
     180             :     OString const & separator, xmlreader::Span const & text)
     181             : {
     182      151536 :     comphelper::SequenceAsVector< T > seq;
     183      151536 :     xmlreader::Span sep;
     184      151536 :     if (separator.isEmpty()) {
     185      131880 :         sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
     186             :     } else {
     187       19656 :         sep = xmlreader::Span(separator.getStr(), separator.getLength());
     188             :     }
     189      151536 :     if (text.length != 0) {
     190      396648 :         for (xmlreader::Span t(text);;) {
     191             :             sal_Int32 i = rtl_str_indexOfStr_WithLength(
     192      396648 :                 t.begin, t.length, sep.begin, sep.length);
     193      385560 :             T val;
     194      793296 :             if (!parseValue(
     195      793296 :                     xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
     196             :             {
     197           0 :                 throw css::uno::RuntimeException(
     198             :                     "invalid value",
     199           0 :                     css::uno::Reference< css::uno::XInterface >());
     200             :             }
     201      396648 :             seq.push_back(val);
     202      396648 :             if (i < 0) {
     203      128352 :                 break;
     204             :             }
     205      268296 :             t.begin += i + sep.length;
     206      268296 :             t.length -= i + sep.length;
     207             :         }
     208             :     }
     209      151536 :     return css::uno::makeAny(seq.getAsConstList());
     210             : }
     211             : 
     212     3230646 : css::uno::Any parseValue(
     213             :     OString const & separator, xmlreader::Span const & text, Type type)
     214             : {
     215     3230646 :     switch (type) {
     216             :     case TYPE_ANY:
     217             :         throw css::uno::RuntimeException(
     218             :             "invalid value of type any",
     219           0 :             css::uno::Reference< css::uno::XInterface >());
     220             :     case TYPE_BOOLEAN:
     221      392353 :         return parseSingleValue< sal_Bool >(text);
     222             :     case TYPE_SHORT:
     223       15386 :         return parseSingleValue< sal_Int16 >(text);
     224             :     case TYPE_INT:
     225      596861 :         return parseSingleValue< sal_Int32 >(text);
     226             :     case TYPE_LONG:
     227        5208 :         return parseSingleValue< sal_Int64 >(text);
     228             :     case TYPE_DOUBLE:
     229       13272 :         return parseSingleValue< double >(text);
     230             :     case TYPE_STRING:
     231     2050486 :         return parseSingleValue< OUString >(text);
     232             :     case TYPE_HEXBINARY:
     233        5544 :         return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text);
     234             :     case TYPE_BOOLEAN_LIST:
     235           0 :         return parseListValue< sal_Bool >(separator, text);
     236             :     case TYPE_SHORT_LIST:
     237           0 :         return parseListValue< sal_Int16 >(separator, text);
     238             :     case TYPE_INT_LIST:
     239         504 :         return parseListValue< sal_Int32 >(separator, text);
     240             :     case TYPE_LONG_LIST:
     241         168 :         return parseListValue< sal_Int64 >(separator, text);
     242             :     case TYPE_DOUBLE_LIST:
     243           0 :         return parseListValue< double >(separator, text);
     244             :     case TYPE_STRING_LIST:
     245      150864 :         return parseListValue< OUString >(separator, text);
     246             :     case TYPE_HEXBINARY_LIST:
     247             :         return parseListValue< css::uno::Sequence< sal_Int8 > >(
     248           0 :             separator, text);
     249             :     default:
     250             :         assert(false);
     251             :         throw css::uno::RuntimeException(
     252             :             "this cannot happen",
     253           0 :             css::uno::Reference< css::uno::XInterface >());
     254             :     }
     255             : }
     256             : 
     257             : }
     258             : 
     259       51989 : ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
     260             : 
     261       51989 : ValueParser::~ValueParser() {}
     262             : 
     263    19588520 : xmlreader::XmlReader::Text ValueParser::getTextMode() const {
     264    19588520 :     if (node_.is()) {
     265     6300588 :         switch (state_) {
     266             :         case STATE_TEXT:
     267     6247452 :             if (!items_.empty()) {
     268       26568 :                 break;
     269             :             }
     270             :             // fall through
     271             :         case STATE_IT:
     272             :             return
     273    10733012 :                 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
     274     2058424 :                  !separator_.isEmpty())
     275             :                 ? xmlreader::XmlReader::TEXT_RAW
     276    10489616 :                 : xmlreader::XmlReader::TEXT_NORMALIZED;
     277             :         default:
     278           0 :             break;
     279             :         }
     280             :     }
     281    13314500 :     return xmlreader::XmlReader::TEXT_NONE;
     282             : }
     283             : 
     284     8301118 : bool ValueParser::startElement(
     285             :     xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name,
     286             :     std::set< OUString > const *)
     287             : {
     288     8301118 :     if (!node_.is()) {
     289     8274550 :         return false;
     290             :     }
     291       26568 :     switch (state_) {
     292             :     case STATE_TEXT:
     293       79704 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name.equals("it") &&
     294       79704 :             isListType(type_) && separator_.isEmpty())
     295             :         {
     296       26568 :             pad_.clear();
     297             :                 // before first <it>, characters are not ignored; assume they
     298             :                 // are only whitespace
     299       26568 :             state_ = STATE_IT;
     300       26568 :             return true;
     301             :         }
     302             :         // fall through
     303             :     case STATE_IT:
     304           0 :         if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
     305           0 :             name.equals("unicode") &&
     306           0 :             (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
     307             :         {
     308           0 :             sal_Int32 scalar = -1;
     309             :             for (;;) {
     310             :                 int attrNsId;
     311           0 :                 xmlreader::Span attrLn;
     312           0 :                 if (!reader.nextAttribute(&attrNsId, &attrLn)) {
     313           0 :                     break;
     314             :                 }
     315           0 :                 if (attrNsId == ParseManager::NAMESPACE_OOR &&
     316           0 :                     attrLn.equals("scalar"))
     317             :                 {
     318           0 :                     if (!parseValue(reader.getAttributeValue(true), &scalar)) {
     319           0 :                         scalar = -1;
     320             :                     }
     321           0 :                     break;
     322             :                 }
     323           0 :             }
     324           0 :             if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 &&
     325           0 :                 scalar != 0x0A && scalar != 0x0D)
     326             :             {
     327           0 :                 char c = static_cast< char >(scalar);
     328           0 :                 pad_.add(&c, 1);
     329           0 :             } else if (scalar == 0xFFFE) {
     330           0 :                 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE"));
     331           0 :             } else if (scalar == 0xFFFF) {
     332           0 :                 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF"));
     333             :             } else {
     334             :                 throw css::uno::RuntimeException(
     335           0 :                     "bad unicode scalar attribute in " + reader.getUrl(),
     336           0 :                     css::uno::Reference< css::uno::XInterface >());
     337             :             }
     338           0 :             state_ = State(state_ + 1);
     339           0 :             return true;
     340             :         }
     341           0 :         break;
     342             :     default:
     343           0 :         break;
     344             :     }
     345             :     throw css::uno::RuntimeException(
     346           0 :         "bad member <" + name.convertFromUtf8() + "> in " + reader.getUrl(),
     347           0 :         css::uno::Reference< css::uno::XInterface >());
     348             : }
     349             : 
     350     8301118 : bool ValueParser::endElement() {
     351     8301118 :     if (!node_.is()) {
     352     5065240 :         return false;
     353             :     }
     354     3235878 :     switch (state_) {
     355             :     case STATE_TEXT:
     356             :         {
     357     3209310 :             css::uno::Any value;
     358     3209310 :             if (items_.empty()) {
     359     3204078 :                 value = parseValue(separator_, pad_.get(), type_);
     360     3204078 :                 pad_.clear();
     361             :             } else {
     362        5232 :                 switch (type_) {
     363             :                 case TYPE_BOOLEAN_LIST:
     364           0 :                     value = convertItems< sal_Bool >();
     365           0 :                     break;
     366             :                 case TYPE_SHORT_LIST:
     367           0 :                     value = convertItems< sal_Int16 >();
     368           0 :                     break;
     369             :                 case TYPE_INT_LIST:
     370           0 :                     value = convertItems< sal_Int32 >();
     371           0 :                     break;
     372             :                 case TYPE_LONG_LIST:
     373           0 :                     value = convertItems< sal_Int64 >();
     374           0 :                     break;
     375             :                 case TYPE_DOUBLE_LIST:
     376           0 :                     value = convertItems< double >();
     377           0 :                     break;
     378             :                 case TYPE_STRING_LIST:
     379        5232 :                     value = convertItems< OUString >();
     380        5232 :                     break;
     381             :                 case TYPE_HEXBINARY_LIST:
     382           0 :                     value = convertItems< css::uno::Sequence< sal_Int8 > >();
     383           0 :                     break;
     384             :                 default:
     385             :                     assert(false); // this cannot happen
     386           0 :                     break;
     387             :                 }
     388        5232 :                 items_.clear();
     389             :             }
     390     3209310 :             switch (node_->kind()) {
     391             :             case Node::KIND_PROPERTY:
     392     2173438 :                 static_cast< PropertyNode * >(node_.get())->setValue(
     393     4346876 :                     layer_, value);
     394     2173438 :                 break;
     395             :             case Node::KIND_LOCALIZED_PROPERTY:
     396             :                 {
     397     1035872 :                     NodeMap & members = node_->getMembers();
     398     1035872 :                     NodeMap::iterator i(members.find(localizedName_));
     399     1035872 :                     if (i == members.end()) {
     400             :                         members.insert(
     401             :                             NodeMap::value_type(
     402             :                                 localizedName_,
     403     1035264 :                                 new LocalizedValueNode(layer_, value)));
     404             :                     } else {
     405         608 :                         static_cast< LocalizedValueNode * >(i->second.get())->
     406        1216 :                             setValue(layer_, value);
     407             :                     }
     408             :                 }
     409     1035872 :                 break;
     410             :             default:
     411             :                 assert(false); // this cannot happen
     412           0 :                 break;
     413             :             }
     414     3209310 :             separator_ = OString();
     415     3209310 :             node_.clear();
     416             :         }
     417     3209310 :         break;
     418             :     case STATE_TEXT_UNICODE:
     419             :     case STATE_IT_UNICODE:
     420           0 :         state_ = State(state_ - 1);
     421           0 :         break;
     422             :     case STATE_IT:
     423             :         items_.push_back(
     424       26568 :             parseValue(OString(), pad_.get(), elementType(type_)));
     425       26568 :         pad_.clear();
     426       26568 :         state_ = STATE_TEXT;
     427       26568 :         break;
     428             :     }
     429     3235878 :     return true;
     430             : }
     431             : 
     432     3038142 : void ValueParser::characters(xmlreader::Span const & text) {
     433     3038142 :     if (node_.is()) {
     434             :         assert(state_ == STATE_TEXT || state_ == STATE_IT);
     435     3038142 :         pad_.add(text.begin, text.length);
     436             :     }
     437     3038142 : }
     438             : 
     439     3209310 : void ValueParser::start(
     440             :     rtl::Reference< Node > const & node, OUString const & localizedName)
     441             : {
     442             :     assert(node.is() && !node_.is());
     443     3209310 :     node_ = node;
     444     3209310 :     localizedName_ = localizedName;
     445     3209310 :     state_ = STATE_TEXT;
     446     3209310 : }
     447             : 
     448    10577505 : int ValueParser::getLayer() const {
     449    10577505 :     return layer_;
     450             : }
     451             : 
     452        5232 : template< typename T > css::uno::Any ValueParser::convertItems() {
     453        5232 :     css::uno::Sequence< T > seq(items_.size());
     454       31800 :     for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
     455       26568 :         bool ok = (items_[i] >>= seq[i]);
     456             :         assert(ok);
     457             :         (void) ok; // avoid warnings
     458             :     }
     459        5232 :     return css::uno::makeAny(seq);
     460             : }
     461             : 
     462             : }
     463             : 
     464             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10