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 #include <cstddef> 33 #include <list> 34 35 #include "com/sun/star/beans/Optional.hpp" 36 #include "com/sun/star/beans/UnknownPropertyException.hpp" 37 #include "com/sun/star/beans/XPropertySet.hpp" 38 #include "com/sun/star/container/NoSuchElementException.hpp" 39 #include "com/sun/star/lang/WrappedTargetException.hpp" 40 #include "com/sun/star/lang/XMultiComponentFactory.hpp" 41 #include "com/sun/star/uno/Any.hxx" 42 #include "com/sun/star/uno/Exception.hpp" 43 #include "com/sun/star/uno/Reference.hxx" 44 #include "com/sun/star/uno/RuntimeException.hpp" 45 #include "com/sun/star/uno/XComponentContext.hpp" 46 #include "com/sun/star/uno/XInterface.hpp" 47 #include "osl/conditn.hxx" 48 #include "osl/diagnose.h" 49 #include "osl/file.hxx" 50 #include "osl/mutex.hxx" 51 #include "osl/thread.hxx" 52 #include "rtl/bootstrap.hxx" 53 #include "rtl/logfile.h" 54 #include "rtl/ref.hxx" 55 #include "rtl/string.h" 56 #include "rtl/textenc.h" 57 #include "rtl/ustring.h" 58 #include "rtl/ustring.hxx" 59 #include "sal/types.h" 60 #include "salhelper/simplereferenceobject.hxx" 61 62 #include "additions.hxx" 63 #include "components.hxx" 64 #include "data.hxx" 65 #include "lock.hxx" 66 #include "modifications.hxx" 67 #include "node.hxx" 68 #include "nodemap.hxx" 69 #include "parsemanager.hxx" 70 #include "partial.hxx" 71 #include "rootaccess.hxx" 72 #include "writemodfile.hxx" 73 #include "xcdparser.hxx" 74 #include "xcuparser.hxx" 75 #include "xcsparser.hxx" 76 77 namespace configmgr { 78 79 namespace { 80 81 namespace css = com::sun::star; 82 83 struct UnresolvedListItem { 84 rtl::OUString name; 85 rtl::Reference< ParseManager > manager; 86 87 UnresolvedListItem( 88 rtl::OUString const & theName, 89 rtl::Reference< ParseManager > theManager): 90 name(theName), manager(theManager) {} 91 }; 92 93 typedef std::list< UnresolvedListItem > UnresolvedList; 94 95 void parseXcsFile( 96 rtl::OUString const & url, int layer, Data & data, Partial const * partial, 97 Modifications * modifications, Additions * additions) 98 SAL_THROW(( 99 css::container::NoSuchElementException, css::uno::RuntimeException)) 100 { 101 OSL_ASSERT(partial == 0 && modifications == 0 && additions == 0); 102 (void) partial; (void) modifications; (void) additions; 103 OSL_VERIFY( 104 rtl::Reference< ParseManager >( 105 new ParseManager(url, new XcsParser(layer, data)))->parse()); 106 } 107 108 void parseXcuFile( 109 rtl::OUString const & url, int layer, Data & data, Partial const * partial, 110 Modifications * modifications, Additions * additions) 111 SAL_THROW(( 112 css::container::NoSuchElementException, css::uno::RuntimeException)) 113 { 114 OSL_VERIFY( 115 rtl::Reference< ParseManager >( 116 new ParseManager( 117 url, 118 new XcuParser( 119 layer, data, partial, modifications, additions)))-> 120 parse()); 121 } 122 123 rtl::OUString expand(rtl::OUString const & str) { 124 rtl::OUString s(str); 125 rtl::Bootstrap::expandMacros(s); //TODO: detect failure 126 return s; 127 } 128 129 bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) { 130 OSL_ASSERT(node.is()); 131 if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) { 132 return false; 133 } 134 switch (node->kind()) { 135 case Node::KIND_LOCALIZED_PROPERTY: 136 case Node::KIND_GROUP: 137 for (NodeMap::iterator i(node->getMembers().begin()); 138 i != node->getMembers().end(); ++i) 139 { 140 if (!canRemoveFromLayer(layer, i->second)) { 141 return false; 142 } 143 } 144 return true; 145 case Node::KIND_SET: 146 return node->getMembers().empty(); 147 default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE 148 return true; 149 } 150 } 151 152 static bool singletonCreated = false; 153 static Components * singleton = 0; 154 155 } 156 157 class Components::WriteThread: 158 public osl::Thread, public salhelper::SimpleReferenceObject 159 { 160 public: 161 static void * operator new(std::size_t size) 162 { return Thread::operator new(size); } 163 164 static void operator delete(void * pointer) 165 { Thread::operator delete(pointer); } 166 167 WriteThread( 168 rtl::Reference< WriteThread > * reference, Components & components, 169 rtl::OUString const & url, Data const & data); 170 171 void flush() { delay_.set(); } 172 173 private: 174 virtual ~WriteThread() {} 175 176 virtual void SAL_CALL run(); 177 178 virtual void SAL_CALL onTerminated() { release(); } 179 180 rtl::Reference< WriteThread > * reference_; 181 Components & components_; 182 rtl::OUString url_; 183 Data const & data_; 184 osl::Condition delay_; 185 }; 186 187 Components::WriteThread::WriteThread( 188 rtl::Reference< WriteThread > * reference, Components & components, 189 rtl::OUString const & url, Data const & data): 190 reference_(reference), components_(components), url_(url), data_(data) 191 { 192 OSL_ASSERT(reference != 0); 193 acquire(); 194 } 195 196 void Components::WriteThread::run() { 197 TimeValue t = { 1, 0 }; // 1 sec 198 delay_.wait(&t); // must not throw; result_error is harmless and ignored 199 osl::MutexGuard g(lock); // must not throw 200 try { 201 try { 202 writeModFile(components_, url_, data_); 203 } catch (css::uno::RuntimeException & e) { 204 // Silently ignore write errors, instead of aborting: 205 OSL_TRACE( 206 "configmgr error writing modifications: %s", 207 rtl::OUStringToOString( 208 e.Message, RTL_TEXTENCODING_UTF8).getStr()); 209 } 210 } catch (...) { 211 reference_->clear(); 212 throw; 213 } 214 reference_->clear(); 215 } 216 217 Components & Components::getSingleton( 218 css::uno::Reference< css::uno::XComponentContext > const & context) 219 { 220 OSL_ASSERT(context.is()); 221 if (!singletonCreated) { 222 singletonCreated = true; 223 static Components theSingleton(context); 224 singleton = &theSingleton; 225 } 226 if (singleton == 0) { 227 throw css::uno::RuntimeException( 228 rtl::OUString( 229 RTL_CONSTASCII_USTRINGPARAM( 230 "configmgr no Components singleton")), 231 css::uno::Reference< css::uno::XInterface >()); 232 } 233 return *singleton; 234 } 235 236 bool Components::allLocales(rtl::OUString const & locale) { 237 return locale.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("*")); 238 } 239 240 rtl::Reference< Node > Components::resolvePathRepresentation( 241 rtl::OUString const & pathRepresentation, 242 rtl::OUString * canonicRepresentation, Path * path, int * finalizedLayer) 243 const 244 { 245 return data_.resolvePathRepresentation( 246 pathRepresentation, canonicRepresentation, path, finalizedLayer); 247 } 248 249 rtl::Reference< Node > Components::getTemplate( 250 int layer, rtl::OUString const & fullName) const 251 { 252 return data_.getTemplate(layer, fullName); 253 } 254 255 void Components::addRootAccess(rtl::Reference< RootAccess > const & access) { 256 roots_.insert(access.get()); 257 } 258 259 void Components::removeRootAccess(RootAccess * access) { 260 roots_.erase(access); 261 } 262 263 void Components::initGlobalBroadcaster( 264 Modifications const & modifications, 265 rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster) 266 { 267 //TODO: Iterate only over roots w/ listeners: 268 for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) { 269 rtl::Reference< RootAccess > root; 270 if ((*i)->acquireCounting() > 1) { 271 root.set(*i); // must not throw 272 } 273 (*i)->releaseNondeleting(); 274 if (root.is()) { 275 if (root != exclude) { 276 Path path(root->getAbsolutePath()); 277 Modifications::Node const * mods = &modifications.getRoot(); 278 for (Path::iterator j(path.begin()); j != path.end(); ++j) { 279 Modifications::Node::Children::const_iterator k( 280 mods->children.find(*j)); 281 if (k == mods->children.end()) { 282 mods = 0; 283 break; 284 } 285 mods = &k->second; 286 } 287 //TODO: If the complete tree of which root is a part is deleted, 288 // or replaced, mods will be null, but some of the listeners 289 // from within root should probably fire nonetheless: 290 if (mods != 0) { 291 root->initBroadcaster(*mods, broadcaster); 292 } 293 } 294 } 295 } 296 } 297 298 void Components::addModification(Path const & path) { 299 data_.modifications.add(path); 300 } 301 302 void Components::writeModifications() { 303 if (!writeThread_.is()) { 304 writeThread_ = new WriteThread( 305 &writeThread_, *this, getModificationFileUrl(), data_); 306 writeThread_->create(); 307 } 308 } 309 310 void Components::flushModifications() { 311 rtl::Reference< WriteThread > thread; 312 { 313 osl::MutexGuard g(lock); 314 thread = writeThread_; 315 } 316 if (thread.is()) { 317 thread->flush(); 318 thread->join(); 319 } 320 } 321 322 void Components::insertExtensionXcsFile( 323 bool shared, rtl::OUString const & fileUri) 324 { 325 try { 326 parseXcsFile(fileUri, shared ? 9 : 13, data_, 0, 0, 0); 327 } catch (css::container::NoSuchElementException & e) { 328 throw css::uno::RuntimeException( 329 (rtl::OUString( 330 RTL_CONSTASCII_USTRINGPARAM( 331 "insertExtensionXcsFile does not exist: ")) + 332 e.Message), 333 css::uno::Reference< css::uno::XInterface >()); 334 } 335 } 336 337 void Components::insertExtensionXcuFile( 338 bool shared, rtl::OUString const & fileUri, Modifications * modifications) 339 { 340 OSL_ASSERT(modifications != 0); 341 int layer = shared ? 10 : 14; 342 Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer); 343 try { 344 parseXcuFile(fileUri, layer, data_, 0, modifications, adds); 345 } catch (css::container::NoSuchElementException & e) { 346 data_.removeExtensionXcuAdditions(fileUri); 347 throw css::uno::RuntimeException( 348 (rtl::OUString( 349 RTL_CONSTASCII_USTRINGPARAM( 350 "insertExtensionXcuFile does not exist: ")) + 351 e.Message), 352 css::uno::Reference< css::uno::XInterface >()); 353 } 354 } 355 356 void Components::removeExtensionXcuFile( 357 rtl::OUString const & fileUri, Modifications * modifications) 358 { 359 //TODO: Ideally, exactly the data coming from the specified xcu file would 360 // be removed. However, not enough information is recorded in the in-memory 361 // data structures to do so. So, as a workaround, all those set elements 362 // that were freshly added by the xcu and have afterwards been left 363 // unchanged or have only had their properties changed in the user layer are 364 // removed (and nothing else). The heuristic to determine 365 // whether a node has been left unchanged is to check the layer ID (as 366 // usual) and additionally to check that the node does not recursively 367 // contain any non-empty sets (multiple extension xcu files are merged into 368 // one layer, so checking layer ID alone is not enough). Since 369 // item->additions records all additions of set members in textual order, 370 // the latter check works well when iterating through item->additions in 371 // reverse order. 372 OSL_ASSERT(modifications != 0); 373 rtl::Reference< Data::ExtensionXcu > item( 374 data_.removeExtensionXcuAdditions(fileUri)); 375 if (item.is()) { 376 for (Additions::reverse_iterator i(item->additions.rbegin()); 377 i != item->additions.rend(); ++i) 378 { 379 rtl::Reference< Node > parent; 380 NodeMap const * map = &data_.components; 381 rtl::Reference< Node > node; 382 for (Path::const_iterator j(i->begin()); j != i->end(); ++j) { 383 parent = node; 384 node = Data::findNode(Data::NO_LAYER, *map, *j); 385 if (!node.is()) { 386 break; 387 } 388 map = &node->getMembers(); 389 } 390 if (node.is()) { 391 OSL_ASSERT(parent.is()); 392 if (parent->kind() == Node::KIND_SET) { 393 OSL_ASSERT( 394 node->kind() == Node::KIND_GROUP || 395 node->kind() == Node::KIND_SET); 396 if (canRemoveFromLayer(item->layer, node)) { 397 parent->getMembers().erase(i->back()); 398 data_.modifications.remove(*i); 399 modifications->add(*i); 400 } 401 } 402 } 403 } 404 writeModifications(); 405 } 406 } 407 408 void Components::insertModificationXcuFile( 409 rtl::OUString const & fileUri, 410 std::set< rtl::OUString > const & includedPaths, 411 std::set< rtl::OUString > const & excludedPaths, 412 Modifications * modifications) 413 { 414 OSL_ASSERT(modifications != 0); 415 Partial part(includedPaths, excludedPaths); 416 try { 417 parseFileLeniently( 418 &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications, 419 0); 420 } catch (css::container::NoSuchElementException & e) { 421 OSL_TRACE( 422 "configmgr error inserting non-existing %s: %s", 423 rtl::OUStringToOString(fileUri, RTL_TEXTENCODING_UTF8).getStr(), 424 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 425 } 426 } 427 428 css::beans::Optional< css::uno::Any > Components::getExternalValue( 429 rtl::OUString const & descriptor) 430 { 431 sal_Int32 i = descriptor.indexOf(' '); 432 if (i <= 0) { 433 throw css::uno::RuntimeException( 434 (rtl::OUString( 435 RTL_CONSTASCII_USTRINGPARAM("bad external value descriptor ")) + 436 descriptor), 437 css::uno::Reference< css::uno::XInterface >()); 438 } 439 //TODO: Do not make calls with mutex locked: 440 rtl::OUString name(descriptor.copy(0, i)); 441 ExternalServices::iterator j(externalServices_.find(name)); 442 if (j == externalServices_.end()) { 443 css::uno::Reference< css::uno::XInterface > service; 444 try { 445 service = css::uno::Reference< css::lang::XMultiComponentFactory >( 446 context_->getServiceManager(), css::uno::UNO_SET_THROW)-> 447 createInstanceWithContext(name, context_); 448 } catch (css::uno::RuntimeException &) { 449 // Assuming these exceptions are real errors: 450 throw; 451 } catch (css::uno::Exception & e) { 452 // Assuming these exceptions indicate that the service is not 453 // installed: 454 OSL_TRACE( 455 "createInstance(%s) failed with %s", 456 rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(), 457 rtl::OUStringToOString( 458 e.Message, RTL_TEXTENCODING_UTF8).getStr()); 459 } 460 css::uno::Reference< css::beans::XPropertySet > propset; 461 if (service.is()) { 462 propset = css::uno::Reference< css::beans::XPropertySet >( 463 service, css::uno::UNO_QUERY_THROW); 464 } 465 j = externalServices_.insert( 466 ExternalServices::value_type(name, propset)).first; 467 } 468 css::beans::Optional< css::uno::Any > value; 469 if (j->second.is()) { 470 try { 471 if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>= 472 value)) 473 { 474 throw css::uno::RuntimeException( 475 (rtl::OUString( 476 RTL_CONSTASCII_USTRINGPARAM( 477 "cannot obtain external value through ")) + 478 descriptor), 479 css::uno::Reference< css::uno::XInterface >()); 480 } 481 } catch (css::beans::UnknownPropertyException & e) { 482 throw css::uno::RuntimeException( 483 (rtl::OUString( 484 RTL_CONSTASCII_USTRINGPARAM( 485 "unknwon external value descriptor ID: ")) + 486 e.Message), 487 css::uno::Reference< css::uno::XInterface >()); 488 } catch (css::lang::WrappedTargetException & e) { 489 throw css::uno::RuntimeException( 490 (rtl::OUString( 491 RTL_CONSTASCII_USTRINGPARAM( 492 "cannot obtain external value: ")) + 493 e.Message), 494 css::uno::Reference< css::uno::XInterface >()); 495 } 496 } 497 return value; 498 } 499 500 Components::Components( 501 css::uno::Reference< css::uno::XComponentContext > const & context): 502 context_(context) 503 { 504 OSL_ASSERT(context.is()); 505 RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "begin parsing"); 506 parseXcsXcuLayer( 507 0, 508 expand( 509 rtl::OUString( 510 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry")))); 511 parseModuleLayer( 512 2, 513 expand( 514 rtl::OUString( 515 RTL_CONSTASCII_USTRINGPARAM( 516 "$OOO_BASE_DIR/share/registry/modules")))); 517 parseResLayer( 518 3, 519 expand( 520 rtl::OUString( 521 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry")))); 522 parseXcsXcuLayer( 523 4, 524 expand( 525 rtl::OUString( 526 RTL_CONSTASCII_USTRINGPARAM( 527 "$BRAND_BASE_DIR/share/registry")))); 528 parseModuleLayer( 529 6, 530 expand( 531 rtl::OUString( 532 RTL_CONSTASCII_USTRINGPARAM( 533 "$BRAND_BASE_DIR/share/registry/modules")))); 534 parseXcsXcuIniLayer( 535 7, 536 expand( 537 rtl::OUString( 538 RTL_CONSTASCII_USTRINGPARAM( 539 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 540 ":BUNDLED_EXTENSIONS_USER}/registry/" 541 "com.sun.star.comp.deployment.configuration." 542 "PackageRegistryBackend/configmgr.ini"))), 543 false); 544 parseXcsXcuIniLayer( 545 9, 546 expand( 547 rtl::OUString( 548 RTL_CONSTASCII_USTRINGPARAM( 549 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 550 ":SHARED_EXTENSIONS_USER}/registry/" 551 "com.sun.star.comp.deployment.configuration." 552 "PackageRegistryBackend/configmgr.ini"))), 553 true); 554 parseXcsXcuLayer( 555 11, 556 expand( 557 rtl::OUString( 558 RTL_CONSTASCII_USTRINGPARAM( 559 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 560 ":UNO_USER_PACKAGES_CACHE}/registry/" 561 "com.sun.star.comp.deployment.configuration." 562 "PackageRegistryBackend/registry")))); 563 // can be dropped once old UserInstallation format can no longer exist 564 // (probably OOo 4) 565 parseXcsXcuIniLayer( 566 13, 567 expand( 568 rtl::OUString( 569 RTL_CONSTASCII_USTRINGPARAM( 570 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 571 ":UNO_USER_PACKAGES_CACHE}/registry/" 572 "com.sun.star.comp.deployment.configuration." 573 "PackageRegistryBackend/configmgr.ini"))), 574 true); 575 parseModificationLayer(); 576 RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "end parsing"); 577 } 578 579 Components::~Components() {} 580 581 void Components::parseFileLeniently( 582 FileParser * parseFile, rtl::OUString const & url, int layer, Data & data, 583 Partial const * partial, Modifications * modifications, 584 Additions * additions) 585 { 586 OSL_ASSERT(parseFile != 0); 587 try { 588 (*parseFile)(url, layer, data, partial, modifications, additions); 589 } catch (css::container::NoSuchElementException &) { 590 throw; 591 } catch (css::uno::Exception & e) { //TODO: more specific exception catching 592 // Silently ignore invalid XML files, instead of completely preventing 593 // OOo from starting: 594 OSL_TRACE( 595 "configmgr error reading %s: %s", 596 rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr(), 597 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 598 } 599 } 600 601 void Components::parseFiles( 602 int layer, rtl::OUString const & extension, FileParser * parseFile, 603 rtl::OUString const & url, bool recursive) 604 { 605 osl::Directory dir(url); 606 switch (dir.open()) { 607 case osl::FileBase::E_None: 608 break; 609 case osl::FileBase::E_NOENT: 610 if (!recursive) { 611 return; 612 } 613 // fall through 614 default: 615 throw css::uno::RuntimeException( 616 (rtl::OUString( 617 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + 618 url), 619 css::uno::Reference< css::uno::XInterface >()); 620 } 621 for (;;) { 622 osl::DirectoryItem i; 623 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); 624 if (rc == osl::FileBase::E_NOENT) { 625 break; 626 } 627 if (rc != osl::FileBase::E_None) { 628 throw css::uno::RuntimeException( 629 (rtl::OUString( 630 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + 631 url), 632 css::uno::Reference< css::uno::XInterface >()); 633 } 634 osl::FileStatus stat( 635 FileStatusMask_Type | FileStatusMask_FileName | 636 FileStatusMask_FileURL); 637 if (i.getFileStatus(stat) != osl::FileBase::E_None) { 638 throw css::uno::RuntimeException( 639 (rtl::OUString( 640 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + 641 url), 642 css::uno::Reference< css::uno::XInterface >()); 643 } 644 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks 645 parseFiles(layer, extension, parseFile, stat.getFileURL(), true); 646 } else { 647 rtl::OUString file(stat.getFileName()); 648 if (file.getLength() >= extension.getLength() && 649 file.match(extension, file.getLength() - extension.getLength())) 650 { 651 try { 652 parseFileLeniently( 653 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0); 654 } catch (css::container::NoSuchElementException & e) { 655 throw css::uno::RuntimeException( 656 (rtl::OUString( 657 RTL_CONSTASCII_USTRINGPARAM( 658 "stat'ed file does not exist: ")) + 659 e.Message), 660 css::uno::Reference< css::uno::XInterface >()); 661 } 662 } 663 } 664 } 665 } 666 667 void Components::parseFileList( 668 int layer, FileParser * parseFile, rtl::OUString const & urls, 669 rtl::Bootstrap const & ini, bool recordAdditions) 670 { 671 for (sal_Int32 i = 0;;) { 672 rtl::OUString url(urls.getToken(0, ' ', i)); 673 if (url.getLength() != 0) { 674 ini.expandMacrosFrom(url); //TODO: detect failure 675 Additions * adds = 0; 676 if (recordAdditions) { 677 adds = data_.addExtensionXcuAdditions(url, layer); 678 } 679 try { 680 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds); 681 } catch (css::container::NoSuchElementException & e) { 682 OSL_TRACE( 683 "configmgr file does not exist: %s", 684 rtl::OUStringToOString( 685 e.Message, RTL_TEXTENCODING_UTF8).getStr()); 686 if (adds != 0) { 687 data_.removeExtensionXcuAdditions(url); 688 } 689 } 690 } 691 if (i == -1) { 692 break; 693 } 694 } 695 } 696 697 void Components::parseXcdFiles(int layer, rtl::OUString const & url) { 698 osl::Directory dir(url); 699 switch (dir.open()) { 700 case osl::FileBase::E_None: 701 break; 702 case osl::FileBase::E_NOENT: 703 return; 704 default: 705 throw css::uno::RuntimeException( 706 (rtl::OUString( 707 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + 708 url), 709 css::uno::Reference< css::uno::XInterface >()); 710 } 711 UnresolvedList unres; 712 XcdParser::Dependencies deps; 713 for (;;) { 714 osl::DirectoryItem i; 715 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); 716 if (rc == osl::FileBase::E_NOENT) { 717 break; 718 } 719 if (rc != osl::FileBase::E_None) { 720 throw css::uno::RuntimeException( 721 (rtl::OUString( 722 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + 723 url), 724 css::uno::Reference< css::uno::XInterface >()); 725 } 726 osl::FileStatus stat( 727 FileStatusMask_Type | FileStatusMask_FileName | 728 FileStatusMask_FileURL); 729 if (i.getFileStatus(stat) != osl::FileBase::E_None) { 730 throw css::uno::RuntimeException( 731 (rtl::OUString( 732 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + 733 url), 734 css::uno::Reference< css::uno::XInterface >()); 735 } 736 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks 737 rtl::OUString file(stat.getFileName()); 738 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") && 739 file.matchAsciiL( 740 RTL_CONSTASCII_STRINGPARAM(".xcd"), 741 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))) 742 { 743 rtl::OUString name( 744 file.copy( 745 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))); 746 rtl::Reference< ParseManager > manager; 747 try { 748 manager = new ParseManager( 749 stat.getFileURL(), new XcdParser(layer, deps, data_)); 750 } catch (css::container::NoSuchElementException & e) { 751 throw css::uno::RuntimeException( 752 (rtl::OUString( 753 RTL_CONSTASCII_USTRINGPARAM( 754 "stat'ed file does not exist: ")) + 755 e.Message), 756 css::uno::Reference< css::uno::XInterface >()); 757 } 758 if (manager->parse()) { 759 deps.insert(name); 760 } else { 761 unres.push_back(UnresolvedListItem(name, manager)); 762 } 763 } 764 } 765 } 766 while (!unres.empty()) { 767 bool resolved = false; 768 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) { 769 if (i->manager->parse()) { 770 deps.insert(i->name); 771 unres.erase(i++); 772 resolved = true; 773 } else { 774 ++i; 775 } 776 } 777 if (!resolved) { 778 throw css::uno::RuntimeException( 779 (rtl::OUString( 780 RTL_CONSTASCII_USTRINGPARAM( 781 "xcd: unresolved dependencies in ")) + 782 url), 783 css::uno::Reference< css::uno::XInterface >()); 784 } 785 } 786 } 787 788 void Components::parseXcsXcuLayer(int layer, rtl::OUString const & url) { 789 parseXcdFiles(layer, url); 790 parseFiles( 791 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcs")), 792 &parseXcsFile, 793 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/schema")), false); 794 parseFiles( 795 layer + 1, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 796 &parseXcuFile, 797 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/data")), false); 798 } 799 800 void Components::parseXcsXcuIniLayer( 801 int layer, rtl::OUString const & url, bool recordAdditions) 802 { 803 //TODO: rtl::Bootstrap::getFrom "first trie[s] to retrieve the value via the 804 // global function" 805 rtl::Bootstrap ini(url); 806 rtl::OUString urls; 807 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SCHEMA")), urls)) 808 { 809 parseFileList(layer, &parseXcsFile, urls, ini, false); 810 } 811 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DATA")), urls)) 812 { 813 parseFileList(layer + 1, &parseXcuFile, urls, ini, recordAdditions); 814 } 815 } 816 817 void Components::parseModuleLayer(int layer, rtl::OUString const & url) { 818 parseFiles( 819 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 820 &parseXcuFile, url, false); 821 } 822 823 void Components::parseResLayer(int layer, rtl::OUString const & url) { 824 rtl::OUString resUrl( 825 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/res"))); 826 parseXcdFiles(layer, resUrl); 827 parseFiles( 828 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 829 &parseXcuFile, resUrl, false); 830 } 831 832 rtl::OUString Components::getModificationFileUrl() const { 833 return expand( 834 rtl::OUString( 835 RTL_CONSTASCII_USTRINGPARAM( 836 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") 837 ":UserInstallation}/user/registrymodifications.xcu"))); 838 } 839 840 void Components::parseModificationLayer() { 841 try { 842 parseFileLeniently( 843 &parseXcuFile, getModificationFileUrl(), Data::NO_LAYER, data_, 0, 844 0, 0); 845 } catch (css::container::NoSuchElementException &) { 846 OSL_TRACE( 847 "configmgr user registrymodifications.xcu does not (yet) exist"); 848 // Migrate old user layer data (can be removed once migration is no 849 // longer relevant, probably OOo 4; also see hack for xsi namespace in 850 // xmlreader::XmlReader::registerNamespaceIri): 851 parseFiles( 852 Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 853 &parseXcuFile, 854 expand( 855 rtl::OUString( 856 RTL_CONSTASCII_USTRINGPARAM( 857 "${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") 858 ":UserInstallation}/user/registry/data"))), 859 false); 860 } 861 } 862 863 } 864