blob: 12c3f77642ce7547ea644cbefaac197de51c6aba [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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 "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"
#include "xmldata.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(xmlreader::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(xmlreader::Span const & text, sal_Int16 * value) {
OSL_ASSERT(text.is() && value != 0);
// 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 ?
rtl::OString(
text.begin + RTL_CONSTASCII_LENGTH("0X"),
text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
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(xmlreader::Span const & text, sal_Int32 * value) {
OSL_ASSERT(text.is() && value != 0);
// For backwards compatibility, support hexadecimal values:
*value =
rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
RTL_CONSTASCII_LENGTH("0X")) == 0 ?
rtl::OString(
text.begin + RTL_CONSTASCII_LENGTH("0X"),
text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) :
rtl::OString(text.begin, text.length).toInt32();
//TODO: check valid lexical representation
return true;
}
bool parseValue(xmlreader::Span const & text, sal_Int64 * value) {
OSL_ASSERT(text.is() && value != 0);
// For backwards compatibility, support hexadecimal values:
*value =
rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"),
RTL_CONSTASCII_LENGTH("0X")) == 0 ?
rtl::OString(
text.begin + RTL_CONSTASCII_LENGTH("0X"),
text.length - RTL_CONSTASCII_LENGTH("0X")).toInt64(16) :
rtl::OString(text.begin, text.length).toInt64();
//TODO: check valid lexical representation
return true;
}
bool parseValue(xmlreader::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(xmlreader::Span const & text, rtl::OUString * value) {
OSL_ASSERT(text.is() && value != 0);
*value = text.convertFromUtf8();
return true;
}
bool parseValue(
xmlreader::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(
xmlreader::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(
rtl::OString const & separator, xmlreader::Span const & text)
{
comphelper::SequenceAsVector< T > seq;
xmlreader::Span sep;
if (separator.getLength() == 0) {
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(
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(
rtl::OString const & separator, xmlreader::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::XmlReader::Text ValueParser::getTextMode() const {
if (node_.is()) {
switch (state_) {
case STATE_TEXT:
if (!items_.empty()) {
break;
}
// fall through
case STATE_IT:
return
(type_ == TYPE_STRING || type_ == TYPE_STRING_LIST ||
separator_.getLength() != 0)
? 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.equals(RTL_CONSTASCII_STRINGPARAM("it")) &&
isListType(type_) && separator_.getLength() == 0)
{
pad_.clear();
// before first <it>, characters are not ignored; assume they
// are only whitespace
state_ = STATE_IT;
return true;
}
// fall through
case STATE_IT:
if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
name.equals(RTL_CONSTASCII_STRINGPARAM("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.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 <")) +
name.convertFromUtf8() +
rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()),
css::uno::Reference< css::uno::XInterface >());
}
bool ValueParser::endElement() {
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 {
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_ = rtl::OString();
node_.clear();
}
break;
case STATE_TEXT_UNICODE:
case STATE_IT_UNICODE:
state_ = State(state_ - 1);
break;
case STATE_IT:
items_.push_back(
parseValue(rtl::OString(), pad_.get(), elementType(type_)));
pad_.clear();
state_ = STATE_TEXT;
break;
}
return true;
}
void ValueParser::characters(xmlreader::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_;
}
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);
}
}