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