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