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