summaryrefslogtreecommitdiffstats
path: root/configmgr/source/valueparser.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'configmgr/source/valueparser.cxx')
-rw-r--r--configmgr/source/valueparser.cxx454
1 files changed, 454 insertions, 0 deletions
diff --git a/configmgr/source/valueparser.cxx b/configmgr/source/valueparser.cxx
new file mode 100644
index 000000000..82778e6c8
--- /dev/null
+++ b/configmgr/source/valueparser.cxx
@@ -0,0 +1,454 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/math.h>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <xmlreader/span.hxx>
+#include <xmlreader/xmlreader.hxx>
+
+#include "localizedvaluenode.hxx"
+#include "node.hxx"
+#include "nodemap.hxx"
+#include "parsemanager.hxx"
+#include "propertynode.hxx"
+#include "type.hxx"
+#include "valueparser.hxx"
+
+namespace configmgr {
+
+namespace {
+
+bool parseHexDigit(char c, int * value) {
+ assert(value != nullptr);
+ 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(xmlreader::Span const & text, sal_Bool * value) {
+ assert(text.is() && value != nullptr);
+ if (text == "true" || text == "1") {
+ *value = true;
+ return true;
+ }
+ if (text == "false" || text == "0") {
+ *value = false;
+ return true;
+ }
+ return false;
+}
+
+bool parseValue(xmlreader::Span const & text, sal_Int16 * value) {
+ assert(text.is() && value != nullptr);
+ // For backwards compatibility, support hexadecimal values:
+ sal_Int32 n =
+ rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
+ RTL_CONSTASCII_LENGTH("0X")) == 0 ?
+ static_cast< sal_Int32 >(
+ OString(
+ text.begin + RTL_CONSTASCII_LENGTH("0X"),
+ text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
+ 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(xmlreader::Span const & text, sal_Int32 * value) {
+ assert(text.is() && value != nullptr);
+ // For backwards compatibility, support hexadecimal values:
+ *value =
+ rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
+ RTL_CONSTASCII_LENGTH("0X")) == 0 ?
+ static_cast< sal_Int32 >(
+ OString(
+ text.begin + RTL_CONSTASCII_LENGTH("0X"),
+ text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt32(16)) :
+ OString(text.begin, text.length).toInt32();
+ //TODO: check valid lexical representation
+ return true;
+}
+
+bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
+ assert(text.is() && value != nullptr);
+ // For backwards compatibility, support hexadecimal values:
+ *value =
+ rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+ text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
+ RTL_CONSTASCII_LENGTH("0X")) == 0 ?
+ static_cast< sal_Int64 >(
+ OString(
+ text.begin + RTL_CONSTASCII_LENGTH("0X"),
+ text.length - RTL_CONSTASCII_LENGTH("0X")).toUInt64(16)) :
+ OString(text.begin, text.length).toInt64();
+ //TODO: check valid lexical representation
+ return true;
+}
+
+bool parseValue(xmlreader::Span const & text, double * value) {
+ assert(text.is() && value != nullptr);
+ *value = rtl_math_stringToDouble(
+ text.begin, text.begin + text.length, '.', 0, nullptr, nullptr);
+ //TODO: check valid lexical representation
+ return true;
+}
+
+bool parseValue(xmlreader::Span const & text, OUString * value) {
+ assert(text.is() && value != nullptr);
+ *value = text.convertFromUtf8();
+ return true;
+}
+
+bool parseValue(
+ xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value)
+{
+ assert(text.is() && value != nullptr);
+ if ((text.length & 1) != 0) {
+ return false;
+ }
+ std::vector< 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 = comphelper::containerToSequence(seq);
+ return true;
+}
+
+template< typename T > css::uno::Any parseSingleValue(
+ xmlreader::Span const & text)
+{
+ T val;
+ if (!parseValue(text, &val)) {
+ throw css::uno::RuntimeException("invalid value");
+ }
+ return css::uno::Any(val);
+}
+
+template< typename T > css::uno::Any parseListValue(
+ OString const & separator, xmlreader::Span const & text)
+{
+ std::vector< T > seq;
+ xmlreader::Span sep;
+ if (separator.isEmpty()) {
+ sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" "));
+ } else {
+ sep = xmlreader::Span(separator.getStr(), separator.getLength());
+ }
+ if (text.length != 0) {
+ for (xmlreader::Span t(text);;) {
+ sal_Int32 i = rtl_str_indexOfStr_WithLength(
+ t.begin, t.length, sep.begin, sep.length);
+ T val;
+ if (!parseValue(
+ xmlreader::Span(t.begin, i == -1 ? t.length : i), &val))
+ {
+ throw css::uno::RuntimeException("invalid value");
+ }
+ seq.push_back(val);
+ if (i < 0) {
+ break;
+ }
+ t.begin += i + sep.length;
+ t.length -= i + sep.length;
+ }
+ }
+ return css::uno::Any(comphelper::containerToSequence(seq));
+}
+
+css::uno::Any parseValue(
+ OString const & separator, xmlreader::Span const & text, Type type)
+{
+ switch (type) {
+ case TYPE_ANY:
+ throw css::uno::RuntimeException("invalid value of type any");
+ 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< 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< OUString >(separator, text);
+ case TYPE_HEXBINARY_LIST:
+ return parseListValue< css::uno::Sequence< sal_Int8 > >(
+ separator, text);
+ default:
+ assert(false);
+ throw css::uno::RuntimeException("this cannot happen");
+ }
+}
+
+}
+
+ValueParser::ValueParser(int layer): type_(TYPE_ERROR), layer_(layer), state_() {}
+
+ValueParser::~ValueParser() {}
+
+xmlreader::XmlReader::Text ValueParser::getTextMode() const {
+ if (!node_)
+ return xmlreader::XmlReader::Text::NONE;
+
+ switch (state_) {
+ case State::Text:
+ if (!items_.empty()) {
+ break;
+ }
+ [[fallthrough]];
+ case State::IT:
+ return
+ (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
+ !separator_.isEmpty())
+ ? xmlreader::XmlReader::Text::Raw
+ : xmlreader::XmlReader::Text::Normalized;
+ default:
+ break;
+ }
+ return xmlreader::XmlReader::Text::NONE;
+}
+
+bool ValueParser::startElement(
+ xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
+{
+ if (!node_.is()) {
+ return false;
+ }
+ switch (state_) {
+ case State::Text:
+ if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && name == "it" &&
+ isListType(type_) && separator_.isEmpty())
+ {
+ pad_.clear();
+ // before first <it>, characters are not ignored; assume they
+ // are only whitespace
+ state_ = State::IT;
+ return true;
+ }
+ [[fallthrough]];
+ case State::IT:
+ if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
+ name == "unicode" &&
+ (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST))
+ {
+ sal_Int32 scalar = -1;
+ for (;;) {
+ int attrNsId;
+ xmlreader::Span attrLn;
+ if (!reader.nextAttribute(&attrNsId, &attrLn)) {
+ break;
+ }
+ if (attrNsId == ParseManager::NAMESPACE_OOR &&
+ attrLn == "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(
+ "bad unicode scalar attribute in " + reader.getUrl());
+ }
+ state_ = state_ == State::Text ? State::TextUnicode : State::ITUnicode;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ throw css::uno::RuntimeException(
+ "bad member <" + name.convertFromUtf8() + "> in " + reader.getUrl());
+}
+
+bool ValueParser::endElement() {
+ if (!node_.is()) {
+ return false;
+ }
+ switch (state_) {
+ case State::Text:
+ {
+ css::uno::Any *pValue = nullptr;
+
+ switch (node_->kind()) {
+ case Node::KIND_PROPERTY:
+ pValue = static_cast< PropertyNode * >(node_.get())->getValuePtr(layer_);
+ break;
+ case Node::KIND_LOCALIZED_PROPERTY:
+ {
+ NodeMap & members = node_->getMembers();
+ NodeMap::iterator i(members.find(localizedName_));
+ LocalizedValueNode *pLVNode;
+ if (i == members.end()) {
+ pLVNode = new LocalizedValueNode(layer_);
+ members.insert(
+ NodeMap::value_type(localizedName_, pLVNode ));
+ } else {
+ pLVNode = static_cast< LocalizedValueNode * >(i->second.get());
+ }
+ pValue = pLVNode->getValuePtr(layer_);
+ }
+ break;
+ default:
+ assert(false); // this cannot happen
+ return false;
+ }
+
+ if (items_.empty()) {
+ *pValue = parseValue(separator_, pad_.get(), type_);
+ pad_.clear();
+ } else {
+ switch (type_) {
+ case TYPE_BOOLEAN_LIST:
+ *pValue = convertItems< sal_Bool >();
+ break;
+ case TYPE_SHORT_LIST:
+ *pValue = convertItems< sal_Int16 >();
+ break;
+ case TYPE_INT_LIST:
+ *pValue = convertItems< sal_Int32 >();
+ break;
+ case TYPE_LONG_LIST:
+ *pValue = convertItems< sal_Int64 >();
+ break;
+ case TYPE_DOUBLE_LIST:
+ *pValue = convertItems< double >();
+ break;
+ case TYPE_STRING_LIST:
+ *pValue = convertItems< OUString >();
+ break;
+ case TYPE_HEXBINARY_LIST:
+ *pValue = convertItems< css::uno::Sequence< sal_Int8 > >();
+ break;
+ default:
+ assert(false); // this cannot happen
+ break;
+ }
+ items_.clear();
+ }
+ separator_.clear();
+ node_.clear();
+ }
+ break;
+ case State::TextUnicode:
+ state_ = State::Text;
+ break;
+ case State::ITUnicode:
+ state_ = State::IT;
+ break;
+ case State::IT:
+ items_.push_back(
+ parseValue(OString(), pad_.get(), elementType(type_)));
+ pad_.clear();
+ state_ = State::Text;
+ break;
+ }
+ return true;
+}
+
+void ValueParser::characters(xmlreader::Span const & text) {
+ if (node_.is()) {
+ assert(state_ == State::Text || state_ == State::IT);
+ pad_.add(text.begin, text.length);
+ }
+}
+
+void ValueParser::start(
+ rtl::Reference< Node > const & node, OUString const & localizedName)
+{
+ assert(node.is() && !node_.is());
+ node_ = node;
+ localizedName_ = localizedName;
+ state_ = State::Text;
+}
+
+
+template< typename T > css::uno::Any ValueParser::convertItems() {
+ css::uno::Sequence< T > seq(items_.size());
+ auto seqRange = asNonConstRange(seq);
+ for (sal_Int32 i = 0; i < seq.getLength(); ++i) {
+ bool ok = (items_[i] >>= seqRange[i]);
+ assert(ok);
+ (void) ok; // avoid warnings
+ }
+ return css::uno::Any(seq);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */