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