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 parseXcsXcuIniLayer( 519 7, 520 expand( 521 rtl::OUString( 522 RTL_CONSTASCII_USTRINGPARAM( 523 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 524 ":BUNDLED_EXTENSIONS_USER}/registry/" 525 "com.sun.star.comp.deployment.configuration." 526 "PackageRegistryBackend/configmgr.ini"))), 527 false); 528 parseXcsXcuIniLayer( 529 9, 530 expand( 531 rtl::OUString( 532 RTL_CONSTASCII_USTRINGPARAM( 533 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 534 ":SHARED_EXTENSIONS_USER}/registry/" 535 "com.sun.star.comp.deployment.configuration." 536 "PackageRegistryBackend/configmgr.ini"))), 537 true); 538 parseXcsXcuLayer( 539 11, 540 expand( 541 rtl::OUString( 542 RTL_CONSTASCII_USTRINGPARAM( 543 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 544 ":UNO_USER_PACKAGES_CACHE}/registry/" 545 "com.sun.star.comp.deployment.configuration." 546 "PackageRegistryBackend/registry")))); 547 // can be dropped once old UserInstallation format can no longer exist 548 // (probably OOo 4) 549 parseXcsXcuIniLayer( 550 13, 551 expand( 552 rtl::OUString( 553 RTL_CONSTASCII_USTRINGPARAM( 554 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") 555 ":UNO_USER_PACKAGES_CACHE}/registry/" 556 "com.sun.star.comp.deployment.configuration." 557 "PackageRegistryBackend/configmgr.ini"))), 558 true); 559 parseModificationLayer(); 560 RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "end parsing"); 561 } 562 563 Components::~Components() {} 564 565 void Components::parseFileLeniently( 566 FileParser * parseFile, rtl::OUString const & url, int layer, Data & data, 567 Partial const * partial, Modifications * modifications, 568 Additions * additions) 569 { 570 OSL_ASSERT(parseFile != 0); 571 try { 572 (*parseFile)(url, layer, data, partial, modifications, additions); 573 } catch (css::container::NoSuchElementException &) { 574 throw; 575 } catch (css::uno::Exception & e) { //TODO: more specific exception catching 576 // Silently ignore invalid XML files, instead of completely preventing 577 // OOo from starting: 578 OSL_TRACE( 579 "configmgr error reading %s: %s", 580 rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr(), 581 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 582 } 583 } 584 585 void Components::parseFiles( 586 int layer, rtl::OUString const & extension, FileParser * parseFile, 587 rtl::OUString const & url, bool recursive) 588 { 589 osl::Directory dir(url); 590 switch (dir.open()) { 591 case osl::FileBase::E_None: 592 break; 593 case osl::FileBase::E_NOENT: 594 if (!recursive) { 595 return; 596 } 597 // fall through 598 default: 599 throw css::uno::RuntimeException( 600 (rtl::OUString( 601 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + 602 url), 603 css::uno::Reference< css::uno::XInterface >()); 604 } 605 for (;;) { 606 osl::DirectoryItem i; 607 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); 608 if (rc == osl::FileBase::E_NOENT) { 609 break; 610 } 611 if (rc != osl::FileBase::E_None) { 612 throw css::uno::RuntimeException( 613 (rtl::OUString( 614 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + 615 url), 616 css::uno::Reference< css::uno::XInterface >()); 617 } 618 osl::FileStatus stat( 619 FileStatusMask_Type | FileStatusMask_FileName | 620 FileStatusMask_FileURL); 621 if (i.getFileStatus(stat) != osl::FileBase::E_None) { 622 throw css::uno::RuntimeException( 623 (rtl::OUString( 624 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + 625 url), 626 css::uno::Reference< css::uno::XInterface >()); 627 } 628 if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks 629 parseFiles(layer, extension, parseFile, stat.getFileURL(), true); 630 } else { 631 rtl::OUString file(stat.getFileName()); 632 if (file.getLength() >= extension.getLength() && 633 file.match(extension, file.getLength() - extension.getLength())) 634 { 635 try { 636 parseFileLeniently( 637 parseFile, stat.getFileURL(), layer, data_, 0, 0, 0); 638 } catch (css::container::NoSuchElementException & e) { 639 throw css::uno::RuntimeException( 640 (rtl::OUString( 641 RTL_CONSTASCII_USTRINGPARAM( 642 "stat'ed file does not exist: ")) + 643 e.Message), 644 css::uno::Reference< css::uno::XInterface >()); 645 } 646 } 647 } 648 } 649 } 650 651 void Components::parseFileList( 652 int layer, FileParser * parseFile, rtl::OUString const & urls, 653 rtl::Bootstrap const & ini, bool recordAdditions) 654 { 655 for (sal_Int32 i = 0;;) { 656 rtl::OUString url(urls.getToken(0, ' ', i)); 657 if (url.getLength() != 0) { 658 ini.expandMacrosFrom(url); //TODO: detect failure 659 Additions * adds = 0; 660 if (recordAdditions) { 661 adds = data_.addExtensionXcuAdditions(url, layer); 662 } 663 try { 664 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds); 665 } catch (css::container::NoSuchElementException & e) { 666 OSL_TRACE( 667 "configmgr file does not exist: %s", 668 rtl::OUStringToOString( 669 e.Message, RTL_TEXTENCODING_UTF8).getStr()); 670 if (adds != 0) { 671 data_.removeExtensionXcuAdditions(url); 672 } 673 } 674 } 675 if (i == -1) { 676 break; 677 } 678 } 679 } 680 681 void Components::parseXcdFiles(int layer, rtl::OUString const & url) { 682 osl::Directory dir(url); 683 switch (dir.open()) { 684 case osl::FileBase::E_None: 685 break; 686 case osl::FileBase::E_NOENT: 687 return; 688 default: 689 throw css::uno::RuntimeException( 690 (rtl::OUString( 691 RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + 692 url), 693 css::uno::Reference< css::uno::XInterface >()); 694 } 695 UnresolvedList unres; 696 XcdParser::Dependencies deps; 697 for (;;) { 698 osl::DirectoryItem i; 699 osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); 700 if (rc == osl::FileBase::E_NOENT) { 701 break; 702 } 703 if (rc != osl::FileBase::E_None) { 704 throw css::uno::RuntimeException( 705 (rtl::OUString( 706 RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + 707 url), 708 css::uno::Reference< css::uno::XInterface >()); 709 } 710 osl::FileStatus stat( 711 FileStatusMask_Type | FileStatusMask_FileName | 712 FileStatusMask_FileURL); 713 if (i.getFileStatus(stat) != osl::FileBase::E_None) { 714 throw css::uno::RuntimeException( 715 (rtl::OUString( 716 RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + 717 url), 718 css::uno::Reference< css::uno::XInterface >()); 719 } 720 if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks 721 rtl::OUString file(stat.getFileName()); 722 if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") && 723 file.matchAsciiL( 724 RTL_CONSTASCII_STRINGPARAM(".xcd"), 725 file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))) 726 { 727 rtl::OUString name( 728 file.copy( 729 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))); 730 rtl::Reference< ParseManager > manager; 731 try { 732 manager = new ParseManager( 733 stat.getFileURL(), new XcdParser(layer, deps, data_)); 734 } catch (css::container::NoSuchElementException & e) { 735 throw css::uno::RuntimeException( 736 (rtl::OUString( 737 RTL_CONSTASCII_USTRINGPARAM( 738 "stat'ed file does not exist: ")) + 739 e.Message), 740 css::uno::Reference< css::uno::XInterface >()); 741 } 742 if (manager->parse()) { 743 deps.insert(name); 744 } else { 745 unres.push_back(UnresolvedListItem(name, manager)); 746 } 747 } 748 } 749 } 750 while (!unres.empty()) { 751 bool resolved = false; 752 for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) { 753 if (i->manager->parse()) { 754 deps.insert(i->name); 755 unres.erase(i++); 756 resolved = true; 757 } else { 758 ++i; 759 } 760 } 761 if (!resolved) { 762 throw css::uno::RuntimeException( 763 (rtl::OUString( 764 RTL_CONSTASCII_USTRINGPARAM( 765 "xcd: unresolved dependencies in ")) + 766 url), 767 css::uno::Reference< css::uno::XInterface >()); 768 } 769 } 770 } 771 772 void Components::parseXcsXcuLayer(int layer, rtl::OUString const & url) { 773 parseXcdFiles(layer, url); 774 parseFiles( 775 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcs")), 776 &parseXcsFile, 777 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/schema")), false); 778 parseFiles( 779 layer + 1, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 780 &parseXcuFile, 781 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/data")), false); 782 } 783 784 void Components::parseXcsXcuIniLayer( 785 int layer, rtl::OUString const & url, bool recordAdditions) 786 { 787 //TODO: rtl::Bootstrap::getFrom "first trie[s] to retrieve the value via the 788 // global function" 789 rtl::Bootstrap ini(url); 790 rtl::OUString urls; 791 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SCHEMA")), urls)) 792 { 793 parseFileList(layer, &parseXcsFile, urls, ini, false); 794 } 795 if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DATA")), urls)) 796 { 797 parseFileList(layer + 1, &parseXcuFile, urls, ini, recordAdditions); 798 } 799 } 800 801 void Components::parseModuleLayer(int layer, rtl::OUString const & url) { 802 parseFiles( 803 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 804 &parseXcuFile, url, false); 805 } 806 807 void Components::parseResLayer(int layer, rtl::OUString const & url) { 808 rtl::OUString resUrl( 809 url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/res"))); 810 parseXcdFiles(layer, resUrl); 811 parseFiles( 812 layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 813 &parseXcuFile, resUrl, false); 814 } 815 816 rtl::OUString Components::getModificationFileUrl() const { 817 return expand( 818 rtl::OUString( 819 RTL_CONSTASCII_USTRINGPARAM( 820 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") 821 ":UserInstallation}/user/registrymodifications.xcu"))); 822 } 823 824 void Components::parseModificationLayer() { 825 try { 826 parseFileLeniently( 827 &parseXcuFile, getModificationFileUrl(), Data::NO_LAYER, data_, 0, 828 0, 0); 829 } catch (css::container::NoSuchElementException &) { 830 OSL_TRACE( 831 "configmgr user registrymodifications.xcu does not (yet) exist"); 832 // Migrate old user layer data (can be removed once migration is no 833 // longer relevant, probably OOo 4; also see hack for xsi namespace in 834 // xmlreader::XmlReader::registerNamespaceIri): 835 parseFiles( 836 Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), 837 &parseXcuFile, 838 expand( 839 rtl::OUString( 840 RTL_CONSTASCII_USTRINGPARAM( 841 "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") 842 ":UserInstallation}/user/registry/data"))), 843 false); 844 } 845 } 846 847 } 848