diff options
Diffstat (limited to 'configmgr/source/valueparser.cxx')
-rw-r--r-- | configmgr/source/valueparser.cxx | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/configmgr/source/valueparser.cxx b/configmgr/source/valueparser.cxx new file mode 100644 index 000000000000..061aeca7a4ac --- /dev/null +++ b/configmgr/source/valueparser.cxx @@ -0,0 +1,451 @@ +/************************************************************************* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2009 by Sun Microsystems, Inc. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* $RCSfile: code,v $ +* +* $Revision: 1.4 $ +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +************************************************************************/ + +#include "precompiled_configmgr.hxx" +#include "sal/config.h" + +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/XInterface.hpp" +#include "comphelper/sequenceasvector.hxx" +#include "osl/diagnose.h" +#include "rtl/string.h" +#include "rtl/string.hxx" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" + +#include "localizedvaluenode.hxx" +#include "node.hxx" +#include "nodemap.hxx" +#include "propertynode.hxx" +#include "span.hxx" +#include "type.hxx" +#include "valueparser.hxx" +#include "xmldata.hxx" +#include "xmlreader.hxx" + +namespace configmgr { + +namespace { + +namespace css = com::sun::star; + +bool parseHexDigit(char c, int * value) { + OSL_ASSERT(value != 0); + if (c >= '0' && c <= '9') { + *value = c - '0'; + return true; + } + if (c >= 'A' && c <= 'F') { + *value = c - 'A' + 10; + return true; + } + if (c >= 'a' && c <= 'f') { + *value = c - 'a' + 10; + return true; + } + return false; +} + +bool parseValue(Span const & text, sal_Bool * value) { + OSL_ASSERT(text.is() && value != 0); + if (text.equals(RTL_CONSTASCII_STRINGPARAM("true")) || + text.equals(RTL_CONSTASCII_STRINGPARAM("1"))) + { + *value = true; + return true; + } + if (text.equals(RTL_CONSTASCII_STRINGPARAM("false")) || + text.equals(RTL_CONSTASCII_STRINGPARAM("0"))) + { + *value = false; + return true; + } + return false; +} + +bool parseValue(Span const & text, sal_Int16 * value) { + OSL_ASSERT(text.is() && value != 0); + sal_Int32 n = rtl::OString(text.begin, text.length).toInt32(); + //TODO: check valid lexical representation + if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) { + *value = static_cast< sal_Int16 >(n); + return true; + } + return false; +} + +bool parseValue(Span const & text, sal_Int32 * value) { + OSL_ASSERT(text.is() && value != 0); + *value = rtl::OString(text.begin, text.length).toInt32(); + //TODO: check valid lexical representation + return true; +} + +bool parseValue(Span const & text, sal_Int64 * value) { + OSL_ASSERT(text.is() && value != 0); + *value = rtl::OString(text.begin, text.length).toInt64(); + //TODO: check valid lexical representation + return true; +} + +bool parseValue(Span const & text, double * value) { + OSL_ASSERT(text.is() && value != 0); + *value = rtl::OString(text.begin, text.length).toDouble(); + //TODO: check valid lexical representation + return true; +} + +bool parseValue(Span const & text, rtl::OUString * value) { + OSL_ASSERT(text.is() && value != 0); + *value = xmldata::convertFromUtf8(text); + return true; +} + +bool parseValue(Span const & text, css::uno::Sequence< sal_Int8 > * value) { + OSL_ASSERT(text.is() && value != 0); + if ((text.length & 1) != 0) { + return false; + } + comphelper::SequenceAsVector< sal_Int8 > seq; + for (sal_Int32 i = 0; i != text.length;) { + int n1; + int n2; + if (!parseHexDigit(text.begin[i++], &n1) || + !parseHexDigit(text.begin[i++], &n2)) + { + return false; + } + seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2)); + } + *value = seq.getAsConstList(); + return true; +} + +template< typename T > css::uno::Any parseSingleValue(Span const & text) { + T val; + if (!parseValue(text, &val)) { + throw css::uno::RuntimeException( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")), + css::uno::Reference< css::uno::XInterface >()); + } + return css::uno::makeAny(val); +} + +template< typename T > css::uno::Any parseListValue( + Span const & separator, Span const & text) +{ + comphelper::SequenceAsVector< T > seq; + Span sep; + if (separator.is()) { + sep = separator; + } else { + sep = Span(RTL_CONSTASCII_STRINGPARAM(" ")); + } + if (text.length != 0) { + for (Span t(text);;) { + sal_Int32 i = rtl_str_indexOfStr_WithLength( + t.begin, t.length, sep.begin, sep.length); + T val; + if (!parseValue(Span(t.begin, i == -1 ? t.length : i), &val)) { + throw css::uno::RuntimeException( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")), + css::uno::Reference< css::uno::XInterface >()); + } + seq.push_back(val); + if (i < 0) { + break; + } + t.begin += i + sep.length; + t.length -= i + sep.length; + } + } + return css::uno::makeAny(seq.getAsConstList()); +} + +css::uno::Any parseValue(Span const & separator, Span const & text, Type type) { + switch (type) { + case TYPE_ANY: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("invalid value of type any")), + css::uno::Reference< css::uno::XInterface >()); + case TYPE_BOOLEAN: + return parseSingleValue< sal_Bool >(text); + case TYPE_SHORT: + return parseSingleValue< sal_Int16 >(text); + case TYPE_INT: + return parseSingleValue< sal_Int32 >(text); + case TYPE_LONG: + return parseSingleValue< sal_Int64 >(text); + case TYPE_DOUBLE: + return parseSingleValue< double >(text); + case TYPE_STRING: + return parseSingleValue< rtl::OUString >(text); + case TYPE_HEXBINARY: + return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text); + case TYPE_BOOLEAN_LIST: + return parseListValue< sal_Bool >(separator, text); + case TYPE_SHORT_LIST: + return parseListValue< sal_Int16 >(separator, text); + case TYPE_INT_LIST: + return parseListValue< sal_Int32 >(separator, text); + case TYPE_LONG_LIST: + return parseListValue< sal_Int64 >(separator, text); + case TYPE_DOUBLE_LIST: + return parseListValue< double >(separator, text); + case TYPE_STRING_LIST: + return parseListValue< rtl::OUString >(separator, text); + case TYPE_HEXBINARY_LIST: + return parseListValue< css::uno::Sequence< sal_Int8 > >( + separator, text); + default: + OSL_ASSERT(false); + throw css::uno::RuntimeException( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")), + css::uno::Reference< css::uno::XInterface >()); + } +} + +} + +ValueParser::ValueParser(int layer): layer_(layer) {} + +ValueParser::~ValueParser() {} + +XmlReader::Text ValueParser::getTextMode() const { + if (node_.is()) { + switch (state_) { + case STATE_TEXT: + case STATE_IT: + return + (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST || + separator_.is()) + ? XmlReader::TEXT_RAW : XmlReader::TEXT_NORMALIZED; + default: + break; + } + } + return XmlReader::TEXT_NONE; +} + +bool ValueParser::startElement( + XmlReader & reader, XmlReader::Namespace ns, Span const & name) +{ + if (!node_.is()) { + return false; + } + switch (state_) { + case STATE_TEXT: + if (ns == XmlReader::NAMESPACE_NONE && + name.equals(RTL_CONSTASCII_STRINGPARAM("it")) && + isListType(type_) && !separator_.is()) + { + checkEmptyPad(reader); + state_ = STATE_IT; + return true; + } + // fall through + case STATE_IT: + if (ns == XmlReader::NAMESPACE_NONE && + name.equals(RTL_CONSTASCII_STRINGPARAM("unicode")) && + (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST)) + { + sal_Int32 scalar = -1; + for (;;) { + XmlReader::Namespace attrNs; + Span attrLn; + if (!reader.nextAttribute(&attrNs, &attrLn)) { + break; + } + if (attrNs == XmlReader::NAMESPACE_OOR && + attrLn.equals(RTL_CONSTASCII_STRINGPARAM("scalar"))) + { + if (!parseValue(reader.getAttributeValue(true), &scalar)) { + scalar = -1; + } + break; + } + } + if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 && + scalar != 0x0A && scalar != 0x0D) + { + char c = static_cast< char >(scalar); + pad_.add(&c, 1); + } else if (scalar == 0xFFFE) { + pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE")); + } else if (scalar == 0xFFFF) { + pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF")); + } else { + throw css::uno::RuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "bad unicode scalar attribute in ")) + + reader.getUrl()), + css::uno::Reference< css::uno::XInterface >()); + } + state_ = State(state_ + 1); + return true; + } + break; + default: + break; + } + throw css::uno::RuntimeException( + (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) + + xmldata::convertFromUtf8(name) + + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()), + css::uno::Reference< css::uno::XInterface >()); +} + +bool ValueParser::endElement(XmlReader const & reader) { + if (!node_.is()) { + return false; + } + switch (state_) { + case STATE_TEXT: + { + css::uno::Any value; + if (items_.empty()) { + value = parseValue(separator_, pad_.get(), type_); + pad_.clear(); + } else { + checkEmptyPad(reader); + switch (type_) { + case TYPE_BOOLEAN_LIST: + value = convertItems< sal_Bool >(); + break; + case TYPE_SHORT_LIST: + value = convertItems< sal_Int16 >(); + break; + case TYPE_INT_LIST: + value = convertItems< sal_Int32 >(); + break; + case TYPE_LONG_LIST: + value = convertItems< sal_Int64 >(); + break; + case TYPE_DOUBLE_LIST: + value = convertItems< double >(); + break; + case TYPE_STRING_LIST: + value = convertItems< rtl::OUString >(); + break; + case TYPE_HEXBINARY_LIST: + value = convertItems< css::uno::Sequence< sal_Int8 > >(); + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } + items_.clear(); + } + switch (node_->kind()) { + case Node::KIND_PROPERTY: + dynamic_cast< PropertyNode * >(node_.get())->setValue( + layer_, value); + break; + case Node::KIND_LOCALIZED_PROPERTY: + { + NodeMap::iterator i( + node_->getMembers().find(localizedName_)); + if (i == node_->getMembers().end()) { + node_->getMembers().insert( + NodeMap::value_type( + localizedName_, + new LocalizedValueNode(layer_, value))); + } else { + dynamic_cast< LocalizedValueNode * >(i->second.get())-> + setValue(layer_, value); + } + } + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } + separator_.clear(); + node_.clear(); + } + break; + case STATE_TEXT_UNICODE: + case STATE_IT_UNICODE: + state_ = State(state_ - 1); + break; + case STATE_IT: + items_.push_back(parseValue(Span(), pad_.get(), elementType(type_))); + pad_.clear(); + state_ = STATE_TEXT; + break; + } + return true; +} + +void ValueParser::characters(Span const & text) { + if (node_.is()) { + OSL_ASSERT(state_ == STATE_TEXT || state_ == STATE_IT); + pad_.add(text.begin, text.length); + } +} + +void ValueParser::start( + rtl::Reference< Node > const & node, rtl::OUString const & localizedName) +{ + OSL_ASSERT(node.is() && !node_.is()); + node_ = node; + localizedName_ = localizedName; + state_ = STATE_TEXT; +} + +int ValueParser::getLayer() const { + return layer_; +} + +void ValueParser::checkEmptyPad(XmlReader const & reader) const { + if (pad_.is()) { + throw css::uno::RuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "mixed text and <it> elements in ")) + + reader.getUrl()), + css::uno::Reference< css::uno::XInterface >()); + } +} + +template< typename T > css::uno::Any ValueParser::convertItems() { + css::uno::Sequence< T > seq(items_.size()); + for (sal_Int32 i = 0; i < seq.getLength(); ++i) { + OSL_VERIFY(items_[i] >>= seq[i]); + } + return css::uno::makeAny(seq); +} + +} |