1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_configmgr.hxx" 25 #include "sal/config.h" 26 27 #include "com/sun/star/uno/Any.hxx" 28 #include "com/sun/star/uno/Reference.hxx" 29 #include "com/sun/star/uno/RuntimeException.hpp" 30 #include "com/sun/star/uno/Sequence.hxx" 31 #include "com/sun/star/uno/XInterface.hpp" 32 #include "comphelper/sequenceasvector.hxx" 33 #include "osl/diagnose.h" 34 #include "rtl/string.h" 35 #include "rtl/string.hxx" 36 #include "rtl/ustring.h" 37 #include "rtl/ustring.hxx" 38 #include "sal/types.h" 39 #include "xmlreader/span.hxx" 40 #include "xmlreader/xmlreader.hxx" 41 42 #include "localizedvaluenode.hxx" 43 #include "node.hxx" 44 #include "nodemap.hxx" 45 #include "parsemanager.hxx" 46 #include "propertynode.hxx" 47 #include "type.hxx" 48 #include "valueparser.hxx" 49 #include "xmldata.hxx" 50 51 namespace configmgr { 52 53 namespace { 54 55 namespace css = com::sun::star; 56 57 bool parseHexDigit(char c, int * value) { 58 OSL_ASSERT(value != 0); 59 if (c >= '0' && c <= '9') { 60 *value = c - '0'; 61 return true; 62 } 63 if (c >= 'A' && c <= 'F') { 64 *value = c - 'A' + 10; 65 return true; 66 } 67 if (c >= 'a' && c <= 'f') { 68 *value = c - 'a' + 10; 69 return true; 70 } 71 return false; 72 } 73 74 bool parseValue(xmlreader::Span const & text, sal_Bool * value) { 75 OSL_ASSERT(text.is() && value != 0); 76 if (text.equals(RTL_CONSTASCII_STRINGPARAM("true")) || 77 text.equals(RTL_CONSTASCII_STRINGPARAM("1"))) 78 { 79 *value = true; 80 return true; 81 } 82 if (text.equals(RTL_CONSTASCII_STRINGPARAM("false")) || 83 text.equals(RTL_CONSTASCII_STRINGPARAM("0"))) 84 { 85 *value = false; 86 return true; 87 } 88 return false; 89 } 90 91 bool parseValue(xmlreader::Span const & text, sal_Int16 * value) { 92 OSL_ASSERT(text.is() && value != 0); 93 // For backwards compatibility, support hexadecimal values: 94 sal_Int32 n = 95 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( 96 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"), 97 RTL_CONSTASCII_LENGTH("0X")) == 0 ? 98 rtl::OString( 99 text.begin + RTL_CONSTASCII_LENGTH("0X"), 100 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) : 101 rtl::OString(text.begin, text.length).toInt32(); 102 //TODO: check valid lexical representation 103 if (n >= SAL_MIN_INT16 && n <= SAL_MAX_INT16) { 104 *value = static_cast< sal_Int16 >(n); 105 return true; 106 } 107 return false; 108 } 109 110 bool parseValue(xmlreader::Span const & text, sal_Int32 * value) { 111 OSL_ASSERT(text.is() && value != 0); 112 // For backwards compatibility, support hexadecimal values: 113 *value = 114 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( 115 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"), 116 RTL_CONSTASCII_LENGTH("0X")) == 0 ? 117 rtl::OString( 118 text.begin + RTL_CONSTASCII_LENGTH("0X"), 119 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt32(16) : 120 rtl::OString(text.begin, text.length).toInt32(); 121 //TODO: check valid lexical representation 122 return true; 123 } 124 125 bool parseValue(xmlreader::Span const & text, sal_Int64 * value) { 126 OSL_ASSERT(text.is() && value != 0); 127 // For backwards compatibility, support hexadecimal values: 128 *value = 129 rtl_str_shortenedCompareIgnoreAsciiCase_WithLength( 130 text.begin, text.length, RTL_CONSTASCII_STRINGPARAM("0X"), 131 RTL_CONSTASCII_LENGTH("0X")) == 0 ? 132 rtl::OString( 133 text.begin + RTL_CONSTASCII_LENGTH("0X"), 134 text.length - RTL_CONSTASCII_LENGTH("0X")).toInt64(16) : 135 rtl::OString(text.begin, text.length).toInt64(); 136 //TODO: check valid lexical representation 137 return true; 138 } 139 140 bool parseValue(xmlreader::Span const & text, double * value) { 141 OSL_ASSERT(text.is() && value != 0); 142 *value = rtl::OString(text.begin, text.length).toDouble(); 143 //TODO: check valid lexical representation 144 return true; 145 } 146 147 bool parseValue(xmlreader::Span const & text, rtl::OUString * value) { 148 OSL_ASSERT(text.is() && value != 0); 149 *value = text.convertFromUtf8(); 150 return true; 151 } 152 153 bool parseValue( 154 xmlreader::Span const & text, css::uno::Sequence< sal_Int8 > * value) 155 { 156 OSL_ASSERT(text.is() && value != 0); 157 if ((text.length & 1) != 0) { 158 return false; 159 } 160 comphelper::SequenceAsVector< sal_Int8 > seq; 161 for (sal_Int32 i = 0; i != text.length;) { 162 int n1; 163 int n2; 164 if (!parseHexDigit(text.begin[i++], &n1) || 165 !parseHexDigit(text.begin[i++], &n2)) 166 { 167 return false; 168 } 169 seq.push_back(static_cast< sal_Int8 >((n1 << 4) | n2)); 170 } 171 *value = seq.getAsConstList(); 172 return true; 173 } 174 175 template< typename T > css::uno::Any parseSingleValue( 176 xmlreader::Span const & text) 177 { 178 T val; 179 if (!parseValue(text, &val)) { 180 throw css::uno::RuntimeException( 181 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")), 182 css::uno::Reference< css::uno::XInterface >()); 183 } 184 return css::uno::makeAny(val); 185 } 186 187 template< typename T > css::uno::Any parseListValue( 188 rtl::OString const & separator, xmlreader::Span const & text) 189 { 190 comphelper::SequenceAsVector< T > seq; 191 xmlreader::Span sep; 192 if (separator.getLength() == 0) { 193 sep = xmlreader::Span(RTL_CONSTASCII_STRINGPARAM(" ")); 194 } else { 195 sep = xmlreader::Span(separator.getStr(), separator.getLength()); 196 } 197 if (text.length != 0) { 198 for (xmlreader::Span t(text);;) { 199 sal_Int32 i = rtl_str_indexOfStr_WithLength( 200 t.begin, t.length, sep.begin, sep.length); 201 T val; 202 if (!parseValue( 203 xmlreader::Span(t.begin, i == -1 ? t.length : i), &val)) 204 { 205 throw css::uno::RuntimeException( 206 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid value")), 207 css::uno::Reference< css::uno::XInterface >()); 208 } 209 seq.push_back(val); 210 if (i < 0) { 211 break; 212 } 213 t.begin += i + sep.length; 214 t.length -= i + sep.length; 215 } 216 } 217 return css::uno::makeAny(seq.getAsConstList()); 218 } 219 220 css::uno::Any parseValue( 221 rtl::OString const & separator, xmlreader::Span const & text, Type type) 222 { 223 switch (type) { 224 case TYPE_ANY: 225 throw css::uno::RuntimeException( 226 rtl::OUString( 227 RTL_CONSTASCII_USTRINGPARAM("invalid value of type any")), 228 css::uno::Reference< css::uno::XInterface >()); 229 case TYPE_BOOLEAN: 230 return parseSingleValue< sal_Bool >(text); 231 case TYPE_SHORT: 232 return parseSingleValue< sal_Int16 >(text); 233 case TYPE_INT: 234 return parseSingleValue< sal_Int32 >(text); 235 case TYPE_LONG: 236 return parseSingleValue< sal_Int64 >(text); 237 case TYPE_DOUBLE: 238 return parseSingleValue< double >(text); 239 case TYPE_STRING: 240 return parseSingleValue< rtl::OUString >(text); 241 case TYPE_HEXBINARY: 242 return parseSingleValue< css::uno::Sequence< sal_Int8 > >(text); 243 case TYPE_BOOLEAN_LIST: 244 return parseListValue< sal_Bool >(separator, text); 245 case TYPE_SHORT_LIST: 246 return parseListValue< sal_Int16 >(separator, text); 247 case TYPE_INT_LIST: 248 return parseListValue< sal_Int32 >(separator, text); 249 case TYPE_LONG_LIST: 250 return parseListValue< sal_Int64 >(separator, text); 251 case TYPE_DOUBLE_LIST: 252 return parseListValue< double >(separator, text); 253 case TYPE_STRING_LIST: 254 return parseListValue< rtl::OUString >(separator, text); 255 case TYPE_HEXBINARY_LIST: 256 return parseListValue< css::uno::Sequence< sal_Int8 > >( 257 separator, text); 258 default: 259 OSL_ASSERT(false); 260 throw css::uno::RuntimeException( 261 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("this cannot happen")), 262 css::uno::Reference< css::uno::XInterface >()); 263 } 264 } 265 266 } 267 268 ValueParser::ValueParser(int layer): layer_(layer) {} 269 270 ValueParser::~ValueParser() {} 271 272 xmlreader::XmlReader::Text ValueParser::getTextMode() const { 273 if (node_.is()) { 274 switch (state_) { 275 case STATE_TEXT: 276 if (!items_.empty()) { 277 break; 278 } 279 // fall through 280 case STATE_IT: 281 return 282 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST || 283 separator_.getLength() != 0) 284 ? xmlreader::XmlReader::TEXT_RAW 285 : xmlreader::XmlReader::TEXT_NORMALIZED; 286 default: 287 break; 288 } 289 } 290 return xmlreader::XmlReader::TEXT_NONE; 291 } 292 293 bool ValueParser::startElement( 294 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name) 295 { 296 if (!node_.is()) { 297 return false; 298 } 299 switch (state_) { 300 case STATE_TEXT: 301 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 302 name.equals(RTL_CONSTASCII_STRINGPARAM("it")) && 303 isListType(type_) && separator_.getLength() == 0) 304 { 305 pad_.clear(); 306 // before first <it>, characters are not ignored; assume they 307 // are only whitespace 308 state_ = STATE_IT; 309 return true; 310 } 311 // fall through 312 case STATE_IT: 313 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 314 name.equals(RTL_CONSTASCII_STRINGPARAM("unicode")) && 315 (type_ == TYPE_STRING || type_ == TYPE_STRING_LIST)) 316 { 317 sal_Int32 scalar = -1; 318 for (;;) { 319 int attrNsId; 320 xmlreader::Span attrLn; 321 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 322 break; 323 } 324 if (attrNsId == ParseManager::NAMESPACE_OOR && 325 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("scalar"))) 326 { 327 if (!parseValue(reader.getAttributeValue(true), &scalar)) { 328 scalar = -1; 329 } 330 break; 331 } 332 } 333 if (scalar >= 0 && scalar < 0x20 && scalar != 0x09 && 334 scalar != 0x0A && scalar != 0x0D) 335 { 336 char c = static_cast< char >(scalar); 337 pad_.add(&c, 1); 338 } else if (scalar == 0xFFFE) { 339 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBE")); 340 } else if (scalar == 0xFFFF) { 341 pad_.add(RTL_CONSTASCII_STRINGPARAM("\xEF\xBF\xBF")); 342 } else { 343 throw css::uno::RuntimeException( 344 (rtl::OUString( 345 RTL_CONSTASCII_USTRINGPARAM( 346 "bad unicode scalar attribute in ")) + 347 reader.getUrl()), 348 css::uno::Reference< css::uno::XInterface >()); 349 } 350 state_ = State(state_ + 1); 351 return true; 352 } 353 break; 354 default: 355 break; 356 } 357 throw css::uno::RuntimeException( 358 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) + 359 name.convertFromUtf8() + 360 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()), 361 css::uno::Reference< css::uno::XInterface >()); 362 } 363 364 bool ValueParser::endElement() { 365 if (!node_.is()) { 366 return false; 367 } 368 switch (state_) { 369 case STATE_TEXT: 370 { 371 css::uno::Any value; 372 if (items_.empty()) { 373 value = parseValue(separator_, pad_.get(), type_); 374 pad_.clear(); 375 } else { 376 switch (type_) { 377 case TYPE_BOOLEAN_LIST: 378 value = convertItems< sal_Bool >(); 379 break; 380 case TYPE_SHORT_LIST: 381 value = convertItems< sal_Int16 >(); 382 break; 383 case TYPE_INT_LIST: 384 value = convertItems< sal_Int32 >(); 385 break; 386 case TYPE_LONG_LIST: 387 value = convertItems< sal_Int64 >(); 388 break; 389 case TYPE_DOUBLE_LIST: 390 value = convertItems< double >(); 391 break; 392 case TYPE_STRING_LIST: 393 value = convertItems< rtl::OUString >(); 394 break; 395 case TYPE_HEXBINARY_LIST: 396 value = convertItems< css::uno::Sequence< sal_Int8 > >(); 397 break; 398 default: 399 OSL_ASSERT(false); // this cannot happen 400 break; 401 } 402 items_.clear(); 403 } 404 switch (node_->kind()) { 405 case Node::KIND_PROPERTY: 406 dynamic_cast< PropertyNode * >(node_.get())->setValue( 407 layer_, value); 408 break; 409 case Node::KIND_LOCALIZED_PROPERTY: 410 { 411 NodeMap::iterator i( 412 node_->getMembers().find(localizedName_)); 413 if (i == node_->getMembers().end()) { 414 node_->getMembers().insert( 415 NodeMap::value_type( 416 localizedName_, 417 new LocalizedValueNode(layer_, value))); 418 } else { 419 dynamic_cast< LocalizedValueNode * >(i->second.get())-> 420 setValue(layer_, value); 421 } 422 } 423 break; 424 default: 425 OSL_ASSERT(false); // this cannot happen 426 break; 427 } 428 separator_ = rtl::OString(); 429 node_.clear(); 430 } 431 break; 432 case STATE_TEXT_UNICODE: 433 case STATE_IT_UNICODE: 434 state_ = State(state_ - 1); 435 break; 436 case STATE_IT: 437 items_.push_back( 438 parseValue(rtl::OString(), pad_.get(), elementType(type_))); 439 pad_.clear(); 440 state_ = STATE_TEXT; 441 break; 442 } 443 return true; 444 } 445 446 void ValueParser::characters(xmlreader::Span const & text) { 447 if (node_.is()) { 448 OSL_ASSERT(state_ == STATE_TEXT || state_ == STATE_IT); 449 pad_.add(text.begin, text.length); 450 } 451 } 452 453 void ValueParser::start( 454 rtl::Reference< Node > const & node, rtl::OUString const & localizedName) 455 { 456 OSL_ASSERT(node.is() && !node_.is()); 457 node_ = node; 458 localizedName_ = localizedName; 459 state_ = STATE_TEXT; 460 } 461 462 int ValueParser::getLayer() const { 463 return layer_; 464 } 465 466 template< typename T > css::uno::Any ValueParser::convertItems() { 467 css::uno::Sequence< T > seq(items_.size()); 468 for (sal_Int32 i = 0; i < seq.getLength(); ++i) { 469 OSL_VERIFY(items_[i] >>= seq[i]); 470 } 471 return css::uno::makeAny(seq); 472 } 473 474 } 475