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 <algorithm> 32 33 #include "com/sun/star/uno/Any.hxx" 34 #include "com/sun/star/uno/Reference.hxx" 35 #include "com/sun/star/uno/RuntimeException.hpp" 36 #include "com/sun/star/uno/XInterface.hpp" 37 #include "osl/diagnose.h" 38 #include "rtl/ref.hxx" 39 #include "rtl/strbuf.hxx" 40 #include "rtl/string.h" 41 #include "rtl/string.hxx" 42 #include "rtl/ustring.h" 43 #include "rtl/ustring.hxx" 44 #include "xmlreader/span.hxx" 45 #include "xmlreader/xmlreader.hxx" 46 47 #include "data.hxx" 48 #include "localizedpropertynode.hxx" 49 #include "localizedvaluenode.hxx" 50 #include "groupnode.hxx" 51 #include "modifications.hxx" 52 #include "node.hxx" 53 #include "nodemap.hxx" 54 #include "parsemanager.hxx" 55 #include "partial.hxx" 56 #include "path.hxx" 57 #include "propertynode.hxx" 58 #include "setnode.hxx" 59 #include "xcuparser.hxx" 60 #include "xmldata.hxx" 61 62 namespace configmgr { 63 64 namespace { 65 66 namespace css = com::sun::star; 67 68 } 69 70 XcuParser::XcuParser( 71 int layer, Data & data, Partial const * partial, 72 Modifications * broadcastModifications, Additions * additions): 73 valueParser_(layer), data_(data), 74 partial_(partial), broadcastModifications_(broadcastModifications), 75 additions_(additions), recordModifications_(layer == Data::NO_LAYER), 76 trackPath_( 77 partial_ != 0 || broadcastModifications_ != 0 || additions_ != 0 || 78 recordModifications_) 79 {} 80 81 XcuParser::~XcuParser() {} 82 83 xmlreader::XmlReader::Text XcuParser::getTextMode() { 84 return valueParser_.getTextMode(); 85 } 86 87 bool XcuParser::startElement( 88 xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name) 89 { 90 if (valueParser_.startElement(reader, nsId, name)) { 91 return true; 92 } 93 if (state_.empty()) { 94 if (nsId == ParseManager::NAMESPACE_OOR && 95 name.equals(RTL_CONSTASCII_STRINGPARAM("component-data"))) 96 { 97 handleComponentData(reader); 98 } else if (nsId == ParseManager::NAMESPACE_OOR && 99 name.equals(RTL_CONSTASCII_STRINGPARAM("items"))) 100 { 101 state_.push(State(rtl::Reference< Node >(), false)); 102 } else { 103 throw css::uno::RuntimeException( 104 (rtl::OUString( 105 RTL_CONSTASCII_USTRINGPARAM("bad root element <")) + 106 name.convertFromUtf8() + 107 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 108 reader.getUrl()), 109 css::uno::Reference< css::uno::XInterface >()); 110 } 111 } else if (state_.top().ignore) { 112 state_.push(State(false)); 113 } else if (!state_.top().node.is()) { 114 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 115 name.equals(RTL_CONSTASCII_STRINGPARAM("item"))) 116 { 117 handleItem(reader); 118 } else { 119 throw css::uno::RuntimeException( 120 (rtl::OUString( 121 RTL_CONSTASCII_USTRINGPARAM("bad items node member <")) + 122 name.convertFromUtf8() + 123 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 124 reader.getUrl()), 125 css::uno::Reference< css::uno::XInterface >()); 126 } 127 } else { 128 switch (state_.top().node->kind()) { 129 case Node::KIND_PROPERTY: 130 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 131 name.equals(RTL_CONSTASCII_STRINGPARAM("value"))) 132 { 133 handlePropValue( 134 reader, 135 dynamic_cast< PropertyNode * >(state_.top().node.get())); 136 } else { 137 throw css::uno::RuntimeException( 138 (rtl::OUString( 139 RTL_CONSTASCII_USTRINGPARAM( 140 "bad property node member <")) + 141 name.convertFromUtf8() + 142 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 143 reader.getUrl()), 144 css::uno::Reference< css::uno::XInterface >()); 145 } 146 break; 147 case Node::KIND_LOCALIZED_PROPERTY: 148 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 149 name.equals(RTL_CONSTASCII_STRINGPARAM("value"))) 150 { 151 handleLocpropValue( 152 reader, 153 dynamic_cast< LocalizedPropertyNode * >( 154 state_.top().node.get())); 155 } else { 156 throw css::uno::RuntimeException( 157 (rtl::OUString( 158 RTL_CONSTASCII_USTRINGPARAM( 159 "bad localized property node member <")) + 160 name.convertFromUtf8() + 161 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 162 reader.getUrl()), 163 css::uno::Reference< css::uno::XInterface >()); 164 } 165 break; 166 case Node::KIND_LOCALIZED_VALUE: 167 throw css::uno::RuntimeException( 168 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) + 169 name.convertFromUtf8() + 170 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 171 reader.getUrl()), 172 css::uno::Reference< css::uno::XInterface >()); 173 case Node::KIND_GROUP: 174 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 175 name.equals(RTL_CONSTASCII_STRINGPARAM("prop"))) 176 { 177 handleGroupProp( 178 reader, 179 dynamic_cast< GroupNode * >(state_.top().node.get())); 180 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 181 name.equals(RTL_CONSTASCII_STRINGPARAM("node"))) 182 { 183 handleGroupNode(reader, state_.top().node); 184 } else { 185 throw css::uno::RuntimeException( 186 (rtl::OUString( 187 RTL_CONSTASCII_USTRINGPARAM( 188 "bad group node member <")) + 189 name.convertFromUtf8() + 190 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 191 reader.getUrl()), 192 css::uno::Reference< css::uno::XInterface >()); 193 } 194 break; 195 case Node::KIND_SET: 196 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 197 name.equals(RTL_CONSTASCII_STRINGPARAM("node"))) 198 { 199 handleSetNode( 200 reader, dynamic_cast< SetNode * >(state_.top().node.get())); 201 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE && 202 name.equals(RTL_CONSTASCII_STRINGPARAM("prop"))) 203 { 204 OSL_TRACE( 205 "configmgr bad set node <prop> member in %s", 206 rtl::OUStringToOString( 207 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 208 state_.push(State(true)); // ignored 209 } else { 210 throw css::uno::RuntimeException( 211 (rtl::OUString( 212 RTL_CONSTASCII_USTRINGPARAM("bad set node member <")) + 213 name.convertFromUtf8() + 214 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + 215 reader.getUrl()), 216 css::uno::Reference< css::uno::XInterface >()); 217 } 218 break; 219 } 220 } 221 return true; 222 } 223 224 void XcuParser::endElement(xmlreader::XmlReader const &) { 225 if (valueParser_.endElement()) { 226 return; 227 } 228 OSL_ASSERT(!state_.empty()); 229 bool pop = state_.top().pop; 230 rtl::Reference< Node > insert; 231 rtl::OUString name; 232 if (state_.top().insert) { 233 insert = state_.top().node; 234 OSL_ASSERT(insert.is()); 235 name = state_.top().name; 236 } 237 state_.pop(); 238 if (insert.is()) { 239 OSL_ASSERT(!state_.empty() && state_.top().node.is()); 240 state_.top().node->getMembers()[name] = insert; 241 } 242 if (pop && !path_.empty()) { 243 path_.pop_back(); 244 // </item> will pop less than <item> pushed, but that is harmless, 245 // as the next <item> will reset path_ 246 } 247 } 248 249 void XcuParser::characters(xmlreader::Span const & text) { 250 valueParser_.characters(text); 251 } 252 253 XcuParser::Operation XcuParser::parseOperation(xmlreader::Span const & text) { 254 OSL_ASSERT(text.is()); 255 if (text.equals(RTL_CONSTASCII_STRINGPARAM("modify"))) { 256 return OPERATION_MODIFY; 257 } 258 if (text.equals(RTL_CONSTASCII_STRINGPARAM("replace"))) { 259 return OPERATION_REPLACE; 260 } 261 if (text.equals(RTL_CONSTASCII_STRINGPARAM("fuse"))) { 262 return OPERATION_FUSE; 263 } 264 if (text.equals(RTL_CONSTASCII_STRINGPARAM("remove"))) { 265 return OPERATION_REMOVE; 266 } 267 throw css::uno::RuntimeException( 268 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("invalid op ")) + 269 text.convertFromUtf8()), 270 css::uno::Reference< css::uno::XInterface >()); 271 } 272 273 void XcuParser::handleComponentData(xmlreader::XmlReader & reader) { 274 rtl::OStringBuffer buf; 275 buf.append('.'); 276 bool hasPackage = false; 277 bool hasName = false; 278 Operation op = OPERATION_MODIFY; 279 bool finalized = false; 280 for (;;) { 281 int attrNsId; 282 xmlreader::Span attrLn; 283 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 284 break; 285 } 286 if (attrNsId == ParseManager::NAMESPACE_OOR && 287 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("package"))) 288 { 289 if (hasPackage) { 290 throw css::uno::RuntimeException( 291 (rtl::OUString( 292 RTL_CONSTASCII_USTRINGPARAM( 293 "multiple component-update package attributes" 294 " in ")) + 295 reader.getUrl()), 296 css::uno::Reference< css::uno::XInterface >()); 297 } 298 hasPackage = true; 299 xmlreader::Span s(reader.getAttributeValue(false)); 300 buf.insert(0, s.begin, s.length); 301 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 302 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name"))) 303 { 304 if (hasName) { 305 throw css::uno::RuntimeException( 306 (rtl::OUString( 307 RTL_CONSTASCII_USTRINGPARAM( 308 "multiple component-update name attributes in ")) + 309 reader.getUrl()), 310 css::uno::Reference< css::uno::XInterface >()); 311 } 312 hasName = true; 313 xmlreader::Span s(reader.getAttributeValue(false)); 314 buf.append(s.begin, s.length); 315 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 316 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op"))) 317 { 318 op = parseOperation(reader.getAttributeValue(true)); 319 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 320 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized"))) 321 { 322 finalized = xmldata::parseBoolean(reader.getAttributeValue(true)); 323 } 324 } 325 if (!hasPackage) { 326 throw css::uno::RuntimeException( 327 (rtl::OUString( 328 RTL_CONSTASCII_USTRINGPARAM( 329 "no component-data package attribute in ")) + 330 reader.getUrl()), 331 css::uno::Reference< css::uno::XInterface >()); 332 } 333 if (!hasName) { 334 throw css::uno::RuntimeException( 335 (rtl::OUString( 336 RTL_CONSTASCII_USTRINGPARAM( 337 "no component-data name attribute in ")) + 338 reader.getUrl()), 339 css::uno::Reference< css::uno::XInterface >()); 340 } 341 componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()). 342 convertFromUtf8(); 343 if (trackPath_) { 344 OSL_ASSERT(path_.empty()); 345 path_.push_back(componentName_); 346 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT) 347 { 348 state_.push(State(true)); // ignored 349 return; 350 } 351 } 352 rtl::Reference< Node > node( 353 Data::findNode( 354 valueParser_.getLayer(), data_.components, componentName_)); 355 if (!node.is()) { 356 OSL_TRACE( 357 "configmgr unknown component %s in %s", 358 rtl::OUStringToOString( 359 componentName_, RTL_TEXTENCODING_UTF8).getStr(), 360 rtl::OUStringToOString( 361 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 362 state_.push(State(true)); // ignored 363 return; 364 } 365 switch (op) { 366 case OPERATION_MODIFY: 367 case OPERATION_FUSE: 368 break; 369 default: 370 throw css::uno::RuntimeException( 371 (rtl::OUString( 372 RTL_CONSTASCII_USTRINGPARAM( 373 "invalid operation on root node in ")) + 374 reader.getUrl()), 375 css::uno::Reference< css::uno::XInterface >()); 376 } 377 int finalizedLayer = std::min( 378 finalized ? valueParser_.getLayer() : Data::NO_LAYER, 379 node->getFinalized()); 380 node->setFinalized(finalizedLayer); 381 state_.push(State(node, finalizedLayer < valueParser_.getLayer())); 382 } 383 384 void XcuParser::handleItem(xmlreader::XmlReader & reader) { 385 xmlreader::Span attrPath; 386 for (;;) { 387 int attrNsId; 388 xmlreader::Span attrLn; 389 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 390 break; 391 } 392 if (attrNsId == ParseManager::NAMESPACE_OOR && 393 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("path"))) 394 { 395 attrPath = reader.getAttributeValue(false); 396 } 397 } 398 if (!attrPath.is()) { 399 throw css::uno::RuntimeException( 400 (rtl::OUString( 401 RTL_CONSTASCII_USTRINGPARAM("missing path attribute in ")) + 402 reader.getUrl()), 403 css::uno::Reference< css::uno::XInterface >()); 404 } 405 rtl::OUString path(attrPath.convertFromUtf8()); 406 int finalizedLayer; 407 rtl::Reference< Node > node( 408 data_.resolvePathRepresentation( 409 path, 0, &path_, &finalizedLayer)); 410 if (!node.is()) { 411 OSL_TRACE( 412 "configmgr unknown item %s in %s", 413 rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr(), 414 rtl::OUStringToOString( 415 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 416 state_.push(State(true)); // ignored 417 return; 418 } 419 OSL_ASSERT(!path_.empty()); 420 componentName_ = path_.front(); 421 if (trackPath_) { 422 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT) 423 { 424 state_.push(State(true)); // ignored 425 return; 426 } 427 } else { 428 path_.clear(); 429 } 430 switch (node->kind()) { 431 case Node::KIND_PROPERTY: 432 case Node::KIND_LOCALIZED_VALUE: 433 OSL_TRACE( 434 "configmgr item of bad type %s in %s", 435 rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8).getStr(), 436 rtl::OUStringToOString( 437 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 438 state_.push(State(true)); // ignored 439 return; 440 case Node::KIND_LOCALIZED_PROPERTY: 441 valueParser_.type_ = dynamic_cast< LocalizedPropertyNode * >( 442 node.get())->getStaticType(); 443 break; 444 default: 445 break; 446 } 447 state_.push(State(node, finalizedLayer < valueParser_.getLayer())); 448 } 449 450 void XcuParser::handlePropValue( 451 xmlreader::XmlReader & reader, PropertyNode * prop) 452 { 453 bool nil = false; 454 rtl::OString separator; 455 rtl::OUString external; 456 for (;;) { 457 int attrNsId; 458 xmlreader::Span attrLn; 459 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 460 break; 461 } 462 if (attrNsId == ParseManager::NAMESPACE_XSI && 463 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil"))) 464 { 465 nil = xmldata::parseBoolean(reader.getAttributeValue(true)); 466 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 467 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type"))) 468 { 469 Type type = xmldata::parseType( 470 reader, reader.getAttributeValue(true)); 471 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) { 472 throw css::uno::RuntimeException( 473 (rtl::OUString( 474 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) + 475 reader.getUrl()), 476 css::uno::Reference< css::uno::XInterface >()); 477 } 478 valueParser_.type_ = type; 479 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 480 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator"))) 481 { 482 xmlreader::Span s(reader.getAttributeValue(false)); 483 if (s.length == 0) { 484 throw css::uno::RuntimeException( 485 (rtl::OUString( 486 RTL_CONSTASCII_USTRINGPARAM( 487 "bad oor:separator attribute in ")) + 488 reader.getUrl()), 489 css::uno::Reference< css::uno::XInterface >()); 490 } 491 separator = rtl::OString(s.begin, s.length); 492 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 493 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("external"))) 494 { 495 external = reader.getAttributeValue(true).convertFromUtf8(); 496 if (external.getLength() == 0) { 497 throw css::uno::RuntimeException( 498 (rtl::OUString( 499 RTL_CONSTASCII_USTRINGPARAM( 500 "bad oor:external attribute value in ")) + 501 reader.getUrl()), 502 css::uno::Reference< css::uno::XInterface >()); 503 } 504 } 505 } 506 if (nil) { 507 if (!prop->isNillable()) { 508 throw css::uno::RuntimeException( 509 (rtl::OUString( 510 RTL_CONSTASCII_USTRINGPARAM( 511 "xsi:nil attribute for non-nillable prop in ")) + 512 reader.getUrl()), 513 css::uno::Reference< css::uno::XInterface >()); 514 } 515 if (external.getLength() != 0) { 516 throw css::uno::RuntimeException( 517 (rtl::OUString( 518 RTL_CONSTASCII_USTRINGPARAM( 519 "xsi:nil and oor:external attributes for prop in ")) + 520 reader.getUrl()), 521 css::uno::Reference< css::uno::XInterface >()); 522 } 523 prop->setValue(valueParser_.getLayer(), css::uno::Any()); 524 state_.push(State(false)); 525 } else if (external.getLength() == 0) { 526 valueParser_.separator_ = separator; 527 valueParser_.start(prop); 528 } else { 529 prop->setExternal(valueParser_.getLayer(), external); 530 state_.push(State(false)); 531 } 532 } 533 534 void XcuParser::handleLocpropValue( 535 xmlreader::XmlReader & reader, LocalizedPropertyNode * locprop) 536 { 537 rtl::OUString name; 538 bool nil = false; 539 rtl::OString separator; 540 Operation op = OPERATION_FUSE; 541 for (;;) { 542 int attrNsId; 543 xmlreader::Span attrLn; 544 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 545 break; 546 } 547 if (attrNsId == xmlreader::XmlReader::NAMESPACE_XML && 548 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("lang"))) 549 { 550 name = reader.getAttributeValue(false).convertFromUtf8(); 551 } else if (attrNsId == ParseManager::NAMESPACE_XSI && 552 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nil"))) 553 { 554 nil = xmldata::parseBoolean(reader.getAttributeValue(true)); 555 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 556 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type"))) 557 { 558 Type type = xmldata::parseType( 559 reader, reader.getAttributeValue(true)); 560 if (valueParser_.type_ != TYPE_ANY && type != valueParser_.type_) { 561 throw css::uno::RuntimeException( 562 (rtl::OUString( 563 RTL_CONSTASCII_USTRINGPARAM("invalid value type in ")) + 564 reader.getUrl()), 565 css::uno::Reference< css::uno::XInterface >()); 566 } 567 valueParser_.type_ = type; 568 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 569 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator"))) 570 { 571 xmlreader::Span s(reader.getAttributeValue(false)); 572 if (s.length == 0) { 573 throw css::uno::RuntimeException( 574 (rtl::OUString( 575 RTL_CONSTASCII_USTRINGPARAM( 576 "bad oor:separator attribute in ")) + 577 reader.getUrl()), 578 css::uno::Reference< css::uno::XInterface >()); 579 } 580 separator = rtl::OString(s.begin, s.length); 581 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 582 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op"))) 583 { 584 op = parseOperation(reader.getAttributeValue(true)); 585 } 586 } 587 if (trackPath_) { 588 path_.push_back(name); 589 if (partial_ != 0 && 590 partial_->contains(path_) != Partial::CONTAINS_NODE) 591 { 592 state_.push(State(true)); // ignored 593 return; 594 } 595 } 596 NodeMap::iterator i(locprop->getMembers().find(name)); 597 if (i != locprop->getMembers().end() && 598 i->second->getLayer() > valueParser_.getLayer()) 599 { 600 state_.push(State(true)); // ignored 601 return; 602 } 603 if (nil && !locprop->isNillable()) { 604 throw css::uno::RuntimeException( 605 (rtl::OUString( 606 RTL_CONSTASCII_USTRINGPARAM( 607 "xsi:nil attribute for non-nillable prop in ")) + 608 reader.getUrl()), 609 css::uno::Reference< css::uno::XInterface >()); 610 } 611 switch (op) { 612 case OPERATION_FUSE: 613 { 614 bool pop = false; 615 if (nil) { 616 if (i == locprop->getMembers().end()) { 617 locprop->getMembers()[name] = new LocalizedValueNode( 618 valueParser_.getLayer(), css::uno::Any()); 619 } else { 620 dynamic_cast< LocalizedValueNode * >( 621 i->second.get())->setValue( 622 valueParser_.getLayer(), css::uno::Any()); 623 } 624 state_.push(State(true)); 625 } else { 626 valueParser_.separator_ = separator; 627 valueParser_.start(locprop, name); 628 pop = true; 629 } 630 if (trackPath_) { 631 recordModification(false); 632 if (pop) { 633 path_.pop_back(); 634 } 635 } 636 } 637 break; 638 case OPERATION_REMOVE: 639 //TODO: only allow if parent.op == OPERATION_FUSE 640 //TODO: disallow removing when e.g. lang=""? 641 if (i != locprop->getMembers().end()) { 642 locprop->getMembers().erase(i); 643 } 644 state_.push(State(true)); 645 recordModification(false); 646 break; 647 default: 648 throw css::uno::RuntimeException( 649 (rtl::OUString( 650 RTL_CONSTASCII_USTRINGPARAM( 651 "bad op attribute for value element in ")) + 652 reader.getUrl()), 653 css::uno::Reference< css::uno::XInterface >()); 654 } 655 } 656 657 void XcuParser::handleGroupProp( 658 xmlreader::XmlReader & reader, GroupNode * group) 659 { 660 bool hasName = false; 661 rtl::OUString name; 662 Type type = TYPE_ERROR; 663 Operation op = OPERATION_MODIFY; 664 bool finalized = false; 665 for (;;) { 666 int attrNsId; 667 xmlreader::Span attrLn; 668 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 669 break; 670 } 671 if (attrNsId == ParseManager::NAMESPACE_OOR && 672 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name"))) 673 { 674 hasName = true; 675 name = reader.getAttributeValue(false).convertFromUtf8(); 676 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 677 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type"))) 678 { 679 type = xmldata::parseType(reader, reader.getAttributeValue(true)); 680 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 681 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op"))) 682 { 683 op = parseOperation(reader.getAttributeValue(true)); 684 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 685 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized"))) 686 { 687 finalized = xmldata::parseBoolean(reader.getAttributeValue(true)); 688 } 689 } 690 if (!hasName) { 691 throw css::uno::RuntimeException( 692 (rtl::OUString( 693 RTL_CONSTASCII_USTRINGPARAM("no prop name attribute in ")) + 694 reader.getUrl()), 695 css::uno::Reference< css::uno::XInterface >()); 696 } 697 if (trackPath_) { 698 path_.push_back(name); 699 //TODO: This ignores locprop values for which specific include paths 700 // exist (i.e., for which contains(locprop path) = CONTAINS_SUBNODES): 701 if (partial_ != 0 && 702 partial_->contains(path_) != Partial::CONTAINS_NODE) 703 { 704 state_.push(State(true)); // ignored 705 return; 706 } 707 } 708 NodeMap::iterator i(group->getMembers().find(name)); 709 if (i == group->getMembers().end()) { 710 handleUnknownGroupProp(reader, group, name, type, op, finalized); 711 } else { 712 switch (i->second->kind()) { 713 case Node::KIND_PROPERTY: 714 handlePlainGroupProp(reader, group, i, name, type, op, finalized); 715 break; 716 case Node::KIND_LOCALIZED_PROPERTY: 717 handleLocalizedGroupProp( 718 reader, 719 dynamic_cast< LocalizedPropertyNode * >(i->second.get()), name, 720 type, op, finalized); 721 break; 722 default: 723 throw css::uno::RuntimeException( 724 (rtl::OUString( 725 RTL_CONSTASCII_USTRINGPARAM("inappropriate prop ")) + 726 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 727 reader.getUrl()), 728 css::uno::Reference< css::uno::XInterface >()); 729 } 730 } 731 } 732 733 void XcuParser::handleUnknownGroupProp( 734 xmlreader::XmlReader const & reader, GroupNode * group, 735 rtl::OUString const & name, Type type, Operation operation, bool finalized) 736 { 737 switch (operation) { 738 case OPERATION_REPLACE: 739 case OPERATION_FUSE: 740 if (group->isExtensible()) { 741 if (type == TYPE_ERROR) { 742 throw css::uno::RuntimeException( 743 (rtl::OUString( 744 RTL_CONSTASCII_USTRINGPARAM( 745 "missing type attribute for prop ")) + 746 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 747 reader.getUrl()), 748 css::uno::Reference< css::uno::XInterface >()); 749 } 750 valueParser_.type_ = type; 751 rtl::Reference< Node > prop( 752 new PropertyNode( 753 valueParser_.getLayer(), TYPE_ANY, true, css::uno::Any(), 754 true)); 755 if (finalized) { 756 prop->setFinalized(valueParser_.getLayer()); 757 } 758 state_.push(State(prop, name, state_.top().locked)); 759 recordModification(false); 760 break; 761 } 762 // fall through 763 default: 764 OSL_TRACE( 765 "configmgr unknown property %s in %s", 766 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(), 767 rtl::OUStringToOString( 768 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 769 state_.push(State(true)); // ignored 770 break; 771 } 772 } 773 774 void XcuParser::handlePlainGroupProp( 775 xmlreader::XmlReader const & reader, GroupNode * group, 776 NodeMap::iterator const & propertyIndex, rtl::OUString const & name, 777 Type type, Operation operation, bool finalized) 778 { 779 PropertyNode * property = dynamic_cast< PropertyNode * >( 780 propertyIndex->second.get()); 781 if (property->getLayer() > valueParser_.getLayer()) { 782 state_.push(State(true)); // ignored 783 return; 784 } 785 int finalizedLayer = std::min( 786 finalized ? valueParser_.getLayer() : Data::NO_LAYER, 787 property->getFinalized()); 788 property->setFinalized(finalizedLayer); 789 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY && 790 type != property->getStaticType()) 791 { 792 throw css::uno::RuntimeException( 793 (rtl::OUString( 794 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) + 795 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 796 reader.getUrl()), 797 css::uno::Reference< css::uno::XInterface >()); 798 } 799 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type; 800 switch (operation) { 801 case OPERATION_MODIFY: 802 case OPERATION_REPLACE: 803 case OPERATION_FUSE: 804 state_.push( 805 State( 806 property, 807 (state_.top().locked || 808 finalizedLayer < valueParser_.getLayer()))); 809 recordModification(false); 810 break; 811 case OPERATION_REMOVE: 812 if (!property->isExtension()) { 813 throw css::uno::RuntimeException( 814 (rtl::OUString( 815 RTL_CONSTASCII_USTRINGPARAM( 816 "invalid remove of non-extension prop ")) + 817 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 818 reader.getUrl()), 819 css::uno::Reference< css::uno::XInterface >()); 820 } 821 group->getMembers().erase(propertyIndex); 822 state_.push(State(true)); // ignore children 823 recordModification(false); 824 break; 825 } 826 } 827 828 void XcuParser::handleLocalizedGroupProp( 829 xmlreader::XmlReader const & reader, LocalizedPropertyNode * property, 830 rtl::OUString const & name, Type type, Operation operation, bool finalized) 831 { 832 if (property->getLayer() > valueParser_.getLayer()) { 833 state_.push(State(true)); // ignored 834 return; 835 } 836 int finalizedLayer = std::min( 837 finalized ? valueParser_.getLayer() : Data::NO_LAYER, 838 property->getFinalized()); 839 property->setFinalized(finalizedLayer); 840 if (type != TYPE_ERROR && property->getStaticType() != TYPE_ANY && 841 type != property->getStaticType()) 842 { 843 throw css::uno::RuntimeException( 844 (rtl::OUString( 845 RTL_CONSTASCII_USTRINGPARAM("invalid type for prop ")) + 846 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 847 reader.getUrl()), 848 css::uno::Reference< css::uno::XInterface >()); 849 } 850 valueParser_.type_ = type == TYPE_ERROR ? property->getStaticType() : type; 851 switch (operation) { 852 case OPERATION_MODIFY: 853 case OPERATION_FUSE: 854 state_.push( 855 State( 856 property, 857 (state_.top().locked || 858 finalizedLayer < valueParser_.getLayer()))); 859 break; 860 case OPERATION_REPLACE: 861 { 862 rtl::Reference< Node > replacement( 863 new LocalizedPropertyNode( 864 valueParser_.getLayer(), property->getStaticType(), 865 property->isNillable())); 866 replacement->setFinalized(property->getFinalized()); 867 state_.push( 868 State( 869 replacement, name, 870 (state_.top().locked || 871 finalizedLayer < valueParser_.getLayer()))); 872 recordModification(false); 873 } 874 break; 875 case OPERATION_REMOVE: 876 throw css::uno::RuntimeException( 877 (rtl::OUString( 878 RTL_CONSTASCII_USTRINGPARAM( 879 "invalid remove of non-extension prop ")) + 880 name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 881 reader.getUrl()), 882 css::uno::Reference< css::uno::XInterface >()); 883 } 884 } 885 886 void XcuParser::handleGroupNode( 887 xmlreader::XmlReader & reader, rtl::Reference< Node > const & group) 888 { 889 bool hasName = false; 890 rtl::OUString name; 891 Operation op = OPERATION_MODIFY; 892 bool finalized = false; 893 for (;;) { 894 int attrNsId; 895 xmlreader::Span attrLn; 896 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 897 break; 898 } 899 if (attrNsId == ParseManager::NAMESPACE_OOR && 900 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name"))) 901 { 902 hasName = true; 903 name = reader.getAttributeValue(false).convertFromUtf8(); 904 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 905 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op"))) 906 { 907 op = parseOperation(reader.getAttributeValue(true)); 908 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 909 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized"))) 910 { 911 finalized = xmldata::parseBoolean(reader.getAttributeValue(true)); 912 } 913 } 914 if (!hasName) { 915 throw css::uno::RuntimeException( 916 (rtl::OUString( 917 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) + 918 reader.getUrl()), 919 css::uno::Reference< css::uno::XInterface >()); 920 } 921 if (trackPath_) { 922 path_.push_back(name); 923 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT) 924 { 925 state_.push(State(true)); // ignored 926 return; 927 } 928 } 929 rtl::Reference< Node > child( 930 Data::findNode(valueParser_.getLayer(), group->getMembers(), name)); 931 if (!child.is()) { 932 OSL_TRACE( 933 "configmgr unknown node %s in %s", 934 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(), 935 rtl::OUStringToOString( 936 reader.getUrl(), RTL_TEXTENCODING_UTF8).getStr()); 937 state_.push(State(true)); // ignored 938 return; 939 } 940 if (op != OPERATION_MODIFY && op != OPERATION_FUSE) { 941 throw css::uno::RuntimeException( 942 (rtl::OUString( 943 RTL_CONSTASCII_USTRINGPARAM( 944 "invalid operation on group node in ")) + 945 reader.getUrl()), 946 css::uno::Reference< css::uno::XInterface >()); 947 } 948 int finalizedLayer = std::min( 949 finalized ? valueParser_.getLayer() : Data::NO_LAYER, 950 child->getFinalized()); 951 child->setFinalized(finalizedLayer); 952 state_.push( 953 State( 954 child, 955 state_.top().locked || finalizedLayer < valueParser_.getLayer())); 956 } 957 958 void XcuParser::handleSetNode(xmlreader::XmlReader & reader, SetNode * set) { 959 bool hasName = false; 960 rtl::OUString name; 961 rtl::OUString component(componentName_); 962 bool hasNodeType = false; 963 rtl::OUString nodeType; 964 Operation op = OPERATION_MODIFY; 965 bool finalized = false; 966 bool mandatory = false; 967 for (;;) { 968 int attrNsId; 969 xmlreader::Span attrLn; 970 if (!reader.nextAttribute(&attrNsId, &attrLn)) { 971 break; 972 } 973 if (attrNsId == ParseManager::NAMESPACE_OOR && 974 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name"))) 975 { 976 hasName = true; 977 name = reader.getAttributeValue(false).convertFromUtf8(); 978 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 979 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component"))) 980 { 981 component = reader.getAttributeValue(false).convertFromUtf8(); 982 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 983 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type"))) 984 { 985 hasNodeType = true; 986 nodeType = reader.getAttributeValue(false).convertFromUtf8(); 987 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 988 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("op"))) 989 { 990 op = parseOperation(reader.getAttributeValue(true)); 991 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 992 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("finalized"))) 993 { 994 finalized = xmldata::parseBoolean(reader.getAttributeValue(true)); 995 } else if (attrNsId == ParseManager::NAMESPACE_OOR && 996 attrLn.equals(RTL_CONSTASCII_STRINGPARAM("mandatory"))) 997 { 998 mandatory = xmldata::parseBoolean(reader.getAttributeValue(true)); 999 } 1000 } 1001 if (!hasName) { 1002 throw css::uno::RuntimeException( 1003 (rtl::OUString( 1004 RTL_CONSTASCII_USTRINGPARAM("no node name attribute in ")) + 1005 reader.getUrl()), 1006 css::uno::Reference< css::uno::XInterface >()); 1007 } 1008 if (trackPath_) { 1009 path_.push_back(name); 1010 if (partial_ != 0 && partial_->contains(path_) == Partial::CONTAINS_NOT) 1011 { 1012 state_.push(State(true)); // ignored 1013 return; 1014 } 1015 } 1016 rtl::OUString templateName( 1017 xmldata::parseTemplateReference( 1018 component, hasNodeType, nodeType, &set->getDefaultTemplateName())); 1019 if (!set->isValidTemplate(templateName)) { 1020 throw css::uno::RuntimeException( 1021 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) + 1022 name + 1023 rtl::OUString( 1024 RTL_CONSTASCII_USTRINGPARAM(" references invalid template ")) + 1025 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 1026 reader.getUrl()), 1027 css::uno::Reference< css::uno::XInterface >()); 1028 } 1029 rtl::Reference< Node > tmpl( 1030 data_.getTemplate(valueParser_.getLayer(), templateName)); 1031 if (!tmpl.is()) { 1032 throw css::uno::RuntimeException( 1033 (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("set member node ")) + 1034 name + 1035 rtl::OUString( 1036 RTL_CONSTASCII_USTRINGPARAM( 1037 " references undefined template ")) + 1038 templateName + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) + 1039 reader.getUrl()), 1040 css::uno::Reference< css::uno::XInterface >()); 1041 } 1042 int finalizedLayer = finalized ? valueParser_.getLayer() : Data::NO_LAYER; 1043 int mandatoryLayer = mandatory ? valueParser_.getLayer() : Data::NO_LAYER; 1044 NodeMap::iterator i(set->getMembers().find(name)); 1045 if (i != set->getMembers().end()) { 1046 finalizedLayer = std::min(finalizedLayer, i->second->getFinalized()); 1047 i->second->setFinalized(finalizedLayer); 1048 mandatoryLayer = std::min(mandatoryLayer, i->second->getMandatory()); 1049 i->second->setMandatory(mandatoryLayer); 1050 if (i->second->getLayer() > valueParser_.getLayer()) { 1051 state_.push(State(true)); // ignored 1052 return; 1053 } 1054 } 1055 switch (op) { 1056 case OPERATION_MODIFY: 1057 if (i == set->getMembers().end()) { 1058 OSL_TRACE("ignoring modify of unknown set member node"); 1059 state_.push(State(true)); // ignored 1060 } else { 1061 state_.push( 1062 State( 1063 i->second, 1064 (state_.top().locked || 1065 finalizedLayer < valueParser_.getLayer()))); 1066 } 1067 break; 1068 case OPERATION_REPLACE: 1069 if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) { 1070 state_.push(State(true)); // ignored 1071 } else { 1072 rtl::Reference< Node > member(tmpl->clone(true)); 1073 member->setLayer(valueParser_.getLayer()); 1074 member->setFinalized(finalizedLayer); 1075 member->setMandatory(mandatoryLayer); 1076 state_.push(State(member, name, false)); 1077 recordModification(i == set->getMembers().end()); 1078 } 1079 break; 1080 case OPERATION_FUSE: 1081 if (i == set->getMembers().end()) { 1082 if (state_.top().locked || finalizedLayer < valueParser_.getLayer()) 1083 { 1084 state_.push(State(true)); // ignored 1085 } else { 1086 rtl::Reference< Node > member(tmpl->clone(true)); 1087 member->setLayer(valueParser_.getLayer()); 1088 member->setFinalized(finalizedLayer); 1089 member->setMandatory(mandatoryLayer); 1090 state_.push(State(member, name, false)); 1091 recordModification(true); 1092 } 1093 } else { 1094 state_.push( 1095 State( 1096 i->second, 1097 (state_.top().locked || 1098 finalizedLayer < valueParser_.getLayer()))); 1099 } 1100 break; 1101 case OPERATION_REMOVE: 1102 { 1103 // Ignore removal of unknown members, members finalized in a lower 1104 // layer, and members made mandatory in this or a lower layer; 1105 // forget about user-layer removals that no longer remove anything 1106 // (so that paired additions/removals in the user layer do not grow 1107 // registrymodifications.xcu unbounded): 1108 bool known = i != set->getMembers().end(); 1109 if (known && !state_.top().locked && 1110 finalizedLayer >= valueParser_.getLayer() && 1111 mandatoryLayer > valueParser_.getLayer()) 1112 { 1113 set->getMembers().erase(i); 1114 } 1115 state_.push(State(true)); 1116 if (known) { 1117 recordModification(false); 1118 } 1119 break; 1120 } 1121 } 1122 } 1123 1124 void XcuParser::recordModification(bool addition) { 1125 if (broadcastModifications_ != 0) { 1126 broadcastModifications_->add(path_); 1127 } 1128 if (addition && additions_ != 0) { 1129 additions_->push_back(path_); 1130 } 1131 if (recordModifications_) { 1132 data_.modifications.add(path_); 1133 } 1134 } 1135 1136 } 1137