LCOV - code coverage report
Current view: top level - configmgr/source - components.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 232 364 63.7 %
Date: 2014-11-03 Functions: 31 40 77.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <config_folders.h>
      21             : 
      22             : #include <sal/config.h>
      23             : 
      24             : #include <algorithm>
      25             : #include <cassert>
      26             : #include <cstddef>
      27             : #include <list>
      28             : #include <set>
      29             : 
      30             : #include <com/sun/star/beans/Optional.hpp>
      31             : #include <com/sun/star/beans/UnknownPropertyException.hpp>
      32             : #include <com/sun/star/beans/XPropertySet.hpp>
      33             : #include <com/sun/star/container/NoSuchElementException.hpp>
      34             : #include <com/sun/star/lang/WrappedTargetException.hpp>
      35             : #include <com/sun/star/uno/Any.hxx>
      36             : #include <com/sun/star/uno/Exception.hpp>
      37             : #include <com/sun/star/uno/Reference.hxx>
      38             : #include <com/sun/star/uno/RuntimeException.hpp>
      39             : #include <com/sun/star/uno/XComponentContext.hpp>
      40             : #include <com/sun/star/uno/XInterface.hpp>
      41             : #include <osl/conditn.hxx>
      42             : #include <osl/file.hxx>
      43             : #include <osl/mutex.hxx>
      44             : #include <rtl/bootstrap.hxx>
      45             : #include <rtl/ref.hxx>
      46             : #include <rtl/ustrbuf.hxx>
      47             : #include <rtl/ustring.hxx>
      48             : #include <rtl/instance.hxx>
      49             : #include <sal/log.hxx>
      50             : #include <sal/types.h>
      51             : #include <salhelper/thread.hxx>
      52             : 
      53             : #include "additions.hxx"
      54             : #include "components.hxx"
      55             : #include "data.hxx"
      56             : #include "lock.hxx"
      57             : #include "modifications.hxx"
      58             : #include "node.hxx"
      59             : #include "nodemap.hxx"
      60             : #include "parsemanager.hxx"
      61             : #include "partial.hxx"
      62             : #include "rootaccess.hxx"
      63             : #include "writemodfile.hxx"
      64             : #include "xcdparser.hxx"
      65             : #include "xcuparser.hxx"
      66             : #include "xcsparser.hxx"
      67             : #ifdef WNT
      68             : #include "winreg.hxx"
      69             : #endif
      70             : 
      71             : namespace configmgr {
      72             : 
      73             : namespace {
      74             : 
      75       13716 : struct UnresolvedListItem {
      76             :     OUString name;
      77             :     rtl::Reference< ParseManager > manager;
      78             : 
      79        4572 :     UnresolvedListItem(
      80             :         OUString const & theName,
      81             :         rtl::Reference< ParseManager > theManager):
      82        4572 :         name(theName), manager(theManager) {}
      83             : };
      84             : 
      85             : typedef std::list< UnresolvedListItem > UnresolvedList;
      86             : 
      87           0 : void parseXcsFile(
      88             :     OUString const & url, int layer, Data & data, Partial const * partial,
      89             :     Modifications * modifications, Additions * additions)
      90             : {
      91             :     assert(partial == 0 && modifications == 0 && additions == 0);
      92             :     (void) partial; (void) modifications; (void) additions;
      93             :     bool ok = rtl::Reference< ParseManager >(
      94           0 :         new ParseManager(url, new XcsParser(layer, data)))->parse(0);
      95             :     assert(ok);
      96             :     (void) ok; // avoid warnings
      97           0 : }
      98             : 
      99         166 : void parseXcuFile(
     100             :     OUString const & url, int layer, Data & data, Partial const * partial,
     101             :     Modifications * modifications, Additions * additions)
     102             : {
     103             :     bool ok = rtl::Reference< ParseManager >(
     104             :         new ParseManager(
     105             :             url,
     106         332 :             new XcuParser(layer, data, partial, modifications, additions)))->
     107         430 :         parse(0);
     108             :     assert(ok);
     109             :     (void) ok; // avoid warnings
     110          98 : }
     111             : 
     112         449 : OUString expand(OUString const & str) {
     113         449 :     OUString s(str);
     114         449 :     rtl::Bootstrap::expandMacros(s); //TODO: detect failure
     115         449 :     return s;
     116             : }
     117             : 
     118           0 : bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
     119             :     assert(node.is());
     120           0 :     if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
     121           0 :         return false;
     122             :     }
     123           0 :     switch (node->kind()) {
     124             :     case Node::KIND_LOCALIZED_PROPERTY:
     125             :     case Node::KIND_GROUP:
     126           0 :         for (NodeMap::const_iterator i(node->getMembers().begin());
     127           0 :              i != node->getMembers().end(); ++i)
     128             :         {
     129           0 :             if (!canRemoveFromLayer(layer, i->second)) {
     130           0 :                 return false;
     131             :             }
     132             :         }
     133           0 :         return true;
     134             :     case Node::KIND_SET:
     135           0 :         return node->getMembers().empty();
     136             :     default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
     137           0 :         return true;
     138             :     }
     139             : }
     140             : 
     141             : }
     142             : 
     143             : class Components::WriteThread: public salhelper::Thread {
     144             : public:
     145             :     WriteThread(
     146             :         rtl::Reference< WriteThread > * reference, Components & components,
     147             :         OUString const & url, Data const & data);
     148             : 
     149         322 :     void flush() { delay_.set(); }
     150             : 
     151             : private:
     152        2708 :     virtual ~WriteThread() {}
     153             : 
     154             :     virtual void execute() SAL_OVERRIDE;
     155             : 
     156             :     rtl::Reference< WriteThread > * reference_;
     157             :     Components & components_;
     158             :     OUString url_;
     159             :     Data const & data_;
     160             :     osl::Condition delay_;
     161             :     boost::shared_ptr<osl::Mutex> lock_;
     162             : };
     163             : 
     164        1354 : Components::WriteThread::WriteThread(
     165             :     rtl::Reference< WriteThread > * reference, Components & components,
     166             :     OUString const & url, Data const & data):
     167             :     Thread("configmgrWriter"), reference_(reference), components_(components),
     168        1354 :     url_(url), data_(data)
     169             : {
     170        1354 :     lock_ = lock();
     171             :     assert(reference != 0);
     172        1354 : }
     173             : 
     174        1354 : void Components::WriteThread::execute() {
     175        1354 :     TimeValue t = { 1, 0 }; // 1 sec
     176        1354 :     delay_.wait(&t); // must not throw; result_error is harmless and ignored
     177        1354 :     osl::MutexGuard g(*lock_); // must not throw
     178             :     try {
     179             :         try {
     180        1354 :             writeModFile(components_, url_, data_);
     181           0 :         } catch (css::uno::RuntimeException & e) {
     182             :             // Ignore write errors, instead of aborting:
     183             :             SAL_WARN(
     184             :                 "configmgr",
     185             :                 "error writing modifications: \"" << e.Message << '"');
     186             :         }
     187           0 :     } catch (...) {
     188           0 :         reference_->clear();
     189           0 :         throw;
     190             :     }
     191        1354 :     reference_->clear();
     192        1354 : }
     193             : 
     194             : class theComponentsSingleton :
     195             :     public rtl::StaticWithArg<
     196             :         Components,
     197             :         css::uno::Reference< css::uno::XComponentContext >,
     198             :         theComponentsSingleton>
     199             : {
     200             : };
     201             : 
     202      179097 : Components & Components::getSingleton(
     203             :     css::uno::Reference< css::uno::XComponentContext > const & context)
     204             : {
     205             :     assert(context.is());
     206      179097 :     return theComponentsSingleton::get(context);
     207             : }
     208             : 
     209     1184371 : bool Components::allLocales(OUString const & locale) {
     210     1184371 :     return locale == "*";
     211             : }
     212             : 
     213      237273 : rtl::Reference< Node > Components::resolvePathRepresentation(
     214             :     OUString const & pathRepresentation,
     215             :     OUString * canonicRepresentation, Path * path, int * finalizedLayer)
     216             :     const
     217             : {
     218             :     return data_.resolvePathRepresentation(
     219      237273 :         pathRepresentation, canonicRepresentation, path, finalizedLayer);
     220             : }
     221             : 
     222        5116 : rtl::Reference< Node > Components::getTemplate(
     223             :     int layer, OUString const & fullName) const
     224             : {
     225        5116 :     return data_.getTemplate(layer, fullName);
     226             : }
     227             : 
     228      178200 : void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
     229      178200 :     roots_.insert(access.get());
     230      178200 : }
     231             : 
     232      175661 : void Components::removeRootAccess(RootAccess * access) {
     233      175661 :     roots_.erase(access);
     234      175661 : }
     235             : 
     236       65721 : void Components::initGlobalBroadcaster(
     237             :     Modifications const & modifications,
     238             :     rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
     239             : {
     240             :     //TODO: Iterate only over roots w/ listeners:
     241     4187008 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     242     4121287 :         rtl::Reference< RootAccess > root;
     243     4121287 :         if ((*i)->acquireCounting() > 1) {
     244     4121287 :             root.set(*i); // must not throw
     245             :         }
     246     4121287 :         (*i)->releaseNondeleting();
     247     4121287 :         if (root.is()) {
     248     4121287 :             if (root != exclude) {
     249     4055566 :                 Path path(root->getAbsolutePath());
     250     4055566 :                 Modifications::Node const * mods = &modifications.getRoot();
     251     4242171 :                 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
     252             :                     Modifications::Node::Children::const_iterator k(
     253     3966163 :                         mods->children.find(*j));
     254     3966163 :                     if (k == mods->children.end()) {
     255     3779558 :                         mods = 0;
     256     3779558 :                         break;
     257             :                     }
     258      186605 :                     mods = &k->second;
     259             :                 }
     260             :                 //TODO: If the complete tree of which root is a part is deleted,
     261             :                 // or replaced, mods will be null, but some of the listeners
     262             :                 // from within root should probably fire nonetheless:
     263     4055566 :                 if (mods != 0) {
     264      276008 :                     root->initBroadcaster(*mods, broadcaster);
     265     4055566 :                 }
     266             :             }
     267             :         }
     268     4121287 :     }
     269       65721 : }
     270             : 
     271      433478 : void Components::addModification(Path const & path) {
     272      433478 :     data_.modifications.add(path);
     273      433478 : }
     274             : 
     275       65721 : bool Components::hasModifications() const
     276             : {
     277      131442 :     return data_.modifications.getRoot().children.begin() !=
     278      197163 :         data_.modifications.getRoot().children.end();
     279             : }
     280             : 
     281       65721 : void Components::writeModifications() {
     282             : 
     283       65721 :     if (!hasModifications() || modificationFileUrl_.isEmpty())
     284      112019 :         return;
     285             : 
     286       19423 :     if (!writeThread_.is()) {
     287        2708 :         writeThread_ = new WriteThread(
     288        2708 :             &writeThread_, *this, modificationFileUrl_, data_);
     289        1354 :         writeThread_->launch();
     290             :     }
     291             : }
     292             : 
     293        1278 : void Components::flushModifications() {
     294        1278 :     rtl::Reference< WriteThread > thread;
     295             :     {
     296        1278 :         osl::MutexGuard g(*lock_);
     297        1278 :         thread = writeThread_;
     298             :     }
     299        1278 :     if (thread.is()) {
     300         322 :         thread->flush();
     301         322 :         thread->join();
     302        1278 :     }
     303        1278 : }
     304             : 
     305           0 : void Components::insertExtensionXcsFile(
     306             :     bool shared, OUString const & fileUri)
     307             : {
     308           0 :     int layer = getExtensionLayer(shared);
     309             :     try {
     310           0 :         parseXcsFile(fileUri, layer, data_, 0, 0, 0);
     311           0 :     } catch (css::container::NoSuchElementException & e) {
     312             :         throw css::uno::RuntimeException(
     313           0 :             "insertExtensionXcsFile does not exist: " + e.Message);
     314             :     }
     315           0 : }
     316             : 
     317           0 : void Components::insertExtensionXcuFile(
     318             :     bool shared, OUString const & fileUri, Modifications * modifications)
     319             : {
     320             :     assert(modifications != 0);
     321           0 :     int layer = getExtensionLayer(shared) + 1;
     322           0 :     Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
     323             :     try {
     324           0 :         parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
     325           0 :     } catch (css::container::NoSuchElementException & e) {
     326           0 :         data_.removeExtensionXcuAdditions(fileUri);
     327             :         throw css::uno::RuntimeException(
     328           0 :             "insertExtensionXcuFile does not exist: " + e.Message);
     329             :     }
     330           0 : }
     331             : 
     332           0 : void Components::removeExtensionXcuFile(
     333             :     OUString const & fileUri, Modifications * modifications)
     334             : {
     335             :     //TODO: Ideally, exactly the data coming from the specified xcu file would
     336             :     // be removed.  However, not enough information is recorded in the in-memory
     337             :     // data structures to do so.  So, as a workaround, all those set elements
     338             :     // that were freshly added by the xcu and have afterwards been left
     339             :     // unchanged or have only had their properties changed in the user layer are
     340             :     // removed (and nothing else).  The heuristic to determine
     341             :     // whether a node has been left unchanged is to check the layer ID (as
     342             :     // usual) and additionally to check that the node does not recursively
     343             :     // contain any non-empty sets (multiple extension xcu files are merged into
     344             :     // one layer, so checking layer ID alone is not enough).  Since
     345             :     // item->additions records all additions of set members in textual order,
     346             :     // the latter check works well when iterating through item->additions in
     347             :     // reverse order.
     348             :     assert(modifications != 0);
     349             :     rtl::Reference< Data::ExtensionXcu > item(
     350           0 :         data_.removeExtensionXcuAdditions(fileUri));
     351           0 :     if (item.is()) {
     352           0 :         for (Additions::reverse_iterator i(item->additions.rbegin());
     353           0 :              i != item->additions.rend(); ++i)
     354             :         {
     355           0 :             rtl::Reference< Node > parent;
     356           0 :             NodeMap const * map = &data_.getComponents();
     357           0 :             rtl::Reference< Node > node;
     358           0 :             for (Path::const_iterator j(i->begin()); j != i->end(); ++j) {
     359           0 :                 parent = node;
     360           0 :                 node = map->findNode(Data::NO_LAYER, *j);
     361           0 :                 if (!node.is()) {
     362           0 :                     break;
     363             :                 }
     364           0 :                 map = &node->getMembers();
     365             :             }
     366           0 :             if (node.is()) {
     367             :                 assert(parent.is());
     368           0 :                 if (parent->kind() == Node::KIND_SET) {
     369             :                     assert(
     370             :                         node->kind() == Node::KIND_GROUP ||
     371             :                         node->kind() == Node::KIND_SET);
     372           0 :                     if (canRemoveFromLayer(item->layer, node)) {
     373           0 :                         parent->getMembers().erase(i->back());
     374           0 :                         data_.modifications.remove(*i);
     375           0 :                         modifications->add(*i);
     376             :                     }
     377             :                 }
     378             :             }
     379           0 :         }
     380           0 :         writeModifications();
     381           0 :     }
     382           0 : }
     383             : 
     384           0 : void Components::insertModificationXcuFile(
     385             :     OUString const & fileUri,
     386             :     std::set< OUString > const & includedPaths,
     387             :     std::set< OUString > const & excludedPaths,
     388             :     Modifications * modifications)
     389             : {
     390             :     assert(modifications != 0);
     391           0 :     Partial part(includedPaths, excludedPaths);
     392             :     try {
     393             :         parseFileLeniently(
     394             :             &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications,
     395           0 :             0);
     396           0 :     } catch (css::container::NoSuchElementException & e) {
     397             :         SAL_WARN(
     398             :             "configmgr",
     399             :             "error inserting non-existing \"" << fileUri << "\": \""
     400             :                 << e.Message << '"');
     401           0 :     }
     402           0 : }
     403             : 
     404        1722 : css::beans::Optional< css::uno::Any > Components::getExternalValue(
     405             :     OUString const & descriptor)
     406             : {
     407        1722 :     sal_Int32 i = descriptor.indexOf(' ');
     408        1722 :     if (i <= 0) {
     409             :         throw css::uno::RuntimeException(
     410           0 :             "bad external value descriptor " + descriptor);
     411             :     }
     412             :     //TODO: Do not make calls with mutex locked:
     413        1722 :     OUString name(descriptor.copy(0, i));
     414        1722 :     ExternalServices::iterator j(externalServices_.find(name));
     415        1722 :     if (j == externalServices_.end()) {
     416         475 :         css::uno::Reference< css::uno::XInterface > service;
     417             :         try {
     418        1425 :             service = context_->getServiceManager()->createInstanceWithContext(
     419         950 :                 name, context_);
     420           0 :         } catch (css::uno::RuntimeException &) {
     421             :             // Assuming these exceptions are real errors:
     422           0 :             throw;
     423           0 :         } catch (css::uno::Exception & e) {
     424             :             // Assuming these exceptions indicate that the service is not
     425             :             // installed:
     426             :             SAL_WARN(
     427             :                 "configmgr",
     428             :                 "createInstance(" << name << ") failed with \"" << e.Message
     429             :                     << '"');
     430             :         }
     431         950 :         css::uno::Reference< css::beans::XPropertySet > propset;
     432         475 :         if (service.is()) {
     433         676 :             propset = css::uno::Reference< css::beans::XPropertySet >(
     434         338 :                 service, css::uno::UNO_QUERY_THROW);
     435             :         }
     436             :         j = externalServices_.insert(
     437         950 :             ExternalServices::value_type(name, propset)).first;
     438             :     }
     439        1722 :     css::beans::Optional< css::uno::Any > value;
     440        1722 :     if (j->second.is()) {
     441             :         try {
     442        1204 :             if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
     443             :                   value))
     444             :             {
     445             :                 throw css::uno::RuntimeException(
     446           0 :                     "cannot obtain external value through " + descriptor);
     447             :             }
     448           0 :         } catch (css::beans::UnknownPropertyException & e) {
     449             :             throw css::uno::RuntimeException(
     450           0 :                 "unknown external value descriptor ID: " + e.Message);
     451           0 :         } catch (css::lang::WrappedTargetException & e) {
     452             :             throw css::uno::RuntimeException(
     453           0 :                 "cannot obtain external value: " + e.Message);
     454             :         }
     455             :     }
     456        1722 :     return value;
     457             : }
     458             : 
     459         381 : Components::Components(
     460             :     css::uno::Reference< css::uno::XComponentContext > const & context):
     461         381 :     context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
     462             : {
     463             :     assert(context.is());
     464         381 :     lock_ = lock();
     465         381 :     OUString conf(expand("${CONFIGURATION_LAYERS}"));
     466         381 :     int layer = 0;
     467         381 :     for (sal_Int32 i = 0;;) {
     468        4314 :         while (i != conf.getLength() && conf[i] == ' ') {
     469         930 :             ++i;
     470             :         }
     471        1692 :         if (i == conf.getLength()) {
     472         381 :             break;
     473             :         }
     474        1311 :         if (!modificationFileUrl_.isEmpty()) {
     475             :             throw css::uno::RuntimeException(
     476           0 :                 "CONFIGURATION_LAYERS: \"user\" followed by further layers");
     477             :         }
     478        1311 :         sal_Int32 c = i;
     479        8364 :         for (;; ++c) {
     480        9675 :             if (c == conf.getLength() || conf[c] == ' ') {
     481             :                 throw css::uno::RuntimeException(
     482           0 :                     "CONFIGURATION_LAYERS: missing \":\"");
     483             :             }
     484        9675 :             if (conf[c] == ':') {
     485        1311 :                 break;
     486             :             }
     487             :         }
     488        1311 :         sal_Int32 n = conf.indexOf(' ', c + 1);
     489        1311 :         if (n == -1) {
     490         381 :             n = conf.getLength();
     491             :         }
     492        1311 :         OUString type(conf.copy(i, c - i));
     493        2622 :         OUString url(conf.copy(c + 1, n - c - 1));
     494        1311 :         if ( type == "xcsxcu" ) {
     495         481 :             parseXcsXcuLayer(layer, url);
     496         481 :             layer += 2; //TODO: overflow
     497         830 :         } else if ( type == "bundledext" )
     498             :         {
     499         166 :             parseXcsXcuIniLayer(layer, url, false);
     500         166 :             layer += 2; //TODO: overflow
     501         664 :         } else if ( type == "sharedext" ) {
     502         166 :             if (sharedExtensionLayer_ != -1) {
     503             :                 throw css::uno::RuntimeException(
     504           0 :                     "CONFIGURATION_LAYERS: multiple \"sharedext\" layers");
     505             :             }
     506         166 :             sharedExtensionLayer_ = layer;
     507         166 :             parseXcsXcuIniLayer(layer, url, true);
     508         166 :             layer += 2; //TODO: overflow
     509         498 :         } else if ( type == "userext" ) {
     510         166 :             if (userExtensionLayer_ != -1) {
     511             :                 throw css::uno::RuntimeException(
     512           0 :                     "CONFIGURATION_LAYERS: multiple \"userext\" layers");
     513             :             }
     514         166 :             userExtensionLayer_ = layer;
     515         166 :             parseXcsXcuIniLayer(layer, url, true);
     516         166 :             layer += 2; //TODO: overflow
     517         332 :         } else if ( type == "module" ) {
     518           0 :             parseModuleLayer(layer, url);
     519           0 :             ++layer; //TODO: overflow
     520         332 :         } else if ( type == "res" ) {
     521         166 :             parseResLayer(layer, url);
     522         166 :             ++layer; //TODO: overflow
     523         166 :         } else if ( type == "user" ) {
     524         166 :             if (url.isEmpty()) {
     525             :                 throw css::uno::RuntimeException(
     526           0 :                     "CONFIGURATION_LAYERS: empty \"user\" URL");
     527             :             }
     528         166 :             modificationFileUrl_ = url;
     529         166 :             parseModificationLayer(url);
     530             :         }
     531             : #ifdef WNT
     532             :         else if ( type == "winreg" )
     533             :         {
     534             :             if (!url.isEmpty()) {
     535             :                 SAL_WARN(
     536             :                     "configmgr",
     537             :                     "winreg URL is not empty, URL handling is not implemented for winreg");
     538             :             }
     539             :             OUString aTempFileURL;
     540             :             if ( dumpWindowsRegistry(&aTempFileURL) )
     541             :             {
     542             :                 parseFileLeniently(&parseXcuFile, aTempFileURL, layer, data_, 0, 0, 0);
     543             :                 layer++;
     544             :                 osl::File::remove(aTempFileURL);
     545             :             }
     546             :         }
     547             : #endif
     548             :         else {
     549             :             throw css::uno::RuntimeException(
     550           0 :                 "CONFIGURATION_LAYERS: unknown layer type \"" + type + "\"");
     551             :         }
     552        1311 :         i = n;
     553       10056 :     }
     554         381 : }
     555             : 
     556         762 : Components::~Components()
     557             : {
     558         381 :     flushModifications();
     559        2920 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     560        2539 :         (*i)->setAlive(false);
     561             :     }
     562         381 : }
     563             : 
     564         166 : void Components::parseFileLeniently(
     565             :     FileParser * parseFile, OUString const & url, int layer, Data & data,
     566             :     Partial const * partial, Modifications * modifications,
     567             :     Additions * additions)
     568             : {
     569             :     assert(parseFile != 0);
     570             :     try {
     571         166 :         (*parseFile)(url, layer, data, partial, modifications, additions);
     572          68 :     } catch (css::container::NoSuchElementException &) {
     573          68 :         throw;
     574           0 :     } catch (css::uno::Exception & e) { //TODO: more specific exception catching
     575             :         // Ignore invalid XML files, instead of completely preventing OOo from
     576             :         // starting:
     577             :         SAL_WARN(
     578             :             "configmgr",
     579             :             "error reading \"" << url << "\": \"" << e.Message << '"');
     580             :     }
     581          98 : }
     582             : 
     583        1196 : void Components::parseFiles(
     584             :     int layer, OUString const & extension, FileParser * parseFile,
     585             :     OUString const & url, bool recursive)
     586             : {
     587        1196 :     osl::Directory dir(url);
     588        1196 :     switch (dir.open()) {
     589             :     case osl::FileBase::E_None:
     590         166 :         break;
     591             :     case osl::FileBase::E_NOENT:
     592        1030 :         if (!recursive) {
     593        2226 :             return;
     594             :         }
     595             :         // fall through
     596             :     default:
     597             :         throw css::uno::RuntimeException(
     598           0 :             "cannot open directory " + url);
     599             :     }
     600             :     for (;;) {
     601         498 :         osl::DirectoryItem i;
     602         498 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     603         498 :         if (rc == osl::FileBase::E_NOENT) {
     604         166 :             break;
     605             :         }
     606         332 :         if (rc != osl::FileBase::E_None) {
     607             :             throw css::uno::RuntimeException(
     608           0 :                 "cannot iterate directory " + url);
     609             :         }
     610             :         osl::FileStatus stat(
     611             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     612         664 :             osl_FileStatus_Mask_FileURL);
     613         332 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     614             :             throw css::uno::RuntimeException(
     615           0 :                 "cannot stat in directory " + url);
     616             :         }
     617         332 :         if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
     618           0 :             parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
     619             :         } else {
     620         332 :             OUString file(stat.getFileName());
     621         332 :             if (file.endsWith(extension)) {
     622             :                 try {
     623             :                     parseFileLeniently(
     624           0 :                         parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
     625           0 :                 } catch (css::container::NoSuchElementException & e) {
     626             :                     throw css::uno::RuntimeException(
     627           0 :                         "stat'ed file does not exist: " + e.Message);
     628             :                 }
     629         332 :             }
     630             :         }
     631         332 :     }
     632             : }
     633             : 
     634           0 : void Components::parseFileList(
     635             :     int layer, FileParser * parseFile, OUString const & urls,
     636             :     bool recordAdditions)
     637             : {
     638           0 :     for (sal_Int32 i = 0;;) {
     639           0 :         OUString url(urls.getToken(0, ' ', i));
     640           0 :         if (!url.isEmpty()) {
     641           0 :             Additions * adds = 0;
     642           0 :             if (recordAdditions) {
     643           0 :                 adds = data_.addExtensionXcuAdditions(url, layer);
     644             :             }
     645             :             try {
     646           0 :                 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
     647           0 :             } catch (css::container::NoSuchElementException & e) {
     648             :                 SAL_WARN(
     649             :                     "configmgr", "file does not exist: \"" << e.Message << '"');
     650           0 :                 if (adds != 0) {
     651           0 :                     data_.removeExtensionXcuAdditions(url);
     652             :                 }
     653             :             }
     654             :         }
     655           0 :         if (i == -1) {
     656           0 :             break;
     657             :         }
     658           0 :     }
     659           0 : }
     660             : 
     661         647 : void Components::parseXcdFiles(int layer, OUString const & url) {
     662         647 :     osl::Directory dir(url);
     663         647 :     switch (dir.open()) {
     664             :     case osl::FileBase::E_None:
     665         647 :         break;
     666             :     case osl::FileBase::E_NOENT:
     667         647 :         return;
     668             :     default:
     669             :         throw css::uno::RuntimeException(
     670           0 :             "cannot open directory " + url);
     671             :     }
     672         647 :     UnresolvedList unres;
     673        1294 :     std::set< OUString > existingDeps;
     674        1294 :     std::set< OUString > processedDeps;
     675             :     for (;;) {
     676       10223 :         osl::DirectoryItem i;
     677       10223 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     678       10223 :         if (rc == osl::FileBase::E_NOENT) {
     679         647 :             break;
     680             :         }
     681        9576 :         if (rc != osl::FileBase::E_None) {
     682             :             throw css::uno::RuntimeException(
     683           0 :                 "cannot iterate directory " + url);
     684             :         }
     685             :         osl::FileStatus stat(
     686             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     687       19152 :             osl_FileStatus_Mask_FileURL);
     688        9576 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     689             :             throw css::uno::RuntimeException(
     690           0 :                 "cannot stat in directory " + url);
     691             :         }
     692        9576 :         if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
     693        9195 :             OUString file(stat.getFileName());
     694       18390 :             OUString name;
     695        9195 :             if (file.endsWith(".xcd", &name)) {
     696        8433 :                 existingDeps.insert(name);
     697        8433 :                 rtl::Reference< ParseManager > manager;
     698             :                 try {
     699       25299 :                     manager = new ParseManager(
     700             :                         stat.getFileURL(),
     701       16866 :                         new XcdParser(layer, processedDeps, data_));
     702           0 :                 } catch (css::container::NoSuchElementException & e) {
     703             :                     throw css::uno::RuntimeException(
     704           0 :                         "stat'ed file does not exist: " + e.Message);
     705             :                 }
     706        8433 :                 if (manager->parse(0)) {
     707        3861 :                     processedDeps.insert(name);
     708             :                 } else {
     709        4572 :                     unres.push_back(UnresolvedListItem(name, manager));
     710        8433 :                 }
     711        9195 :             }
     712             :         }
     713        9576 :     }
     714        2056 :     while (!unres.empty()) {
     715         762 :         bool resolved = false;
     716        6477 :         for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
     717        4953 :             if (i->manager->parse(&existingDeps)) {
     718        4572 :                 processedDeps.insert(i->name);
     719        4572 :                 unres.erase(i++);
     720        4572 :                 resolved = true;
     721             :             } else {
     722         381 :                 ++i;
     723             :             }
     724             :         }
     725         762 :         if (!resolved) {
     726             :             throw css::uno::RuntimeException(
     727           0 :                 "xcd: unresolved dependencies in " + url);
     728             :         }
     729         647 :     }
     730             : }
     731             : 
     732         481 : void Components::parseXcsXcuLayer(int layer, OUString const & url) {
     733         481 :     parseXcdFiles(layer, url);
     734         481 :     parseFiles(layer, ".xcs", &parseXcsFile, url + "/schema", false);
     735         481 :     parseFiles(layer + 1, ".xcu", &parseXcuFile, url + "/data", false);
     736         481 : }
     737             : 
     738         498 : void Components::parseXcsXcuIniLayer(
     739             :     int layer, OUString const & url, bool recordAdditions)
     740             : {
     741             :     // Check if ini file exists (otherwise .override would still read global
     742             :     // SCHEMA/DATA variables, which could interfere with unrelated environment
     743             :     // variables):
     744         498 :     if (rtl::Bootstrap(url).getHandle() != 0) {
     745           0 :         OUStringBuffer prefix("${.override:");
     746           0 :         for (sal_Int32 i = 0; i != url.getLength(); ++i) {
     747           0 :             sal_Unicode c = url[i];
     748           0 :             switch (c) {
     749             :             case '$':
     750             :             case ':':
     751             :             case '\\':
     752           0 :                 prefix.append('\\');
     753             :                 // fall through
     754             :             default:
     755           0 :                 prefix.append(c);
     756             :             }
     757             :         }
     758           0 :         prefix.append(':');
     759           0 :         OUString urls(prefix.toString() + "SCHEMA}");
     760           0 :         rtl::Bootstrap::expandMacros(urls);
     761           0 :         if (!urls.isEmpty()) {
     762           0 :             parseFileList(layer, &parseXcsFile, urls, false);
     763             :         }
     764           0 :         urls = prefix.makeStringAndClear() + "DATA}";
     765           0 :         rtl::Bootstrap::expandMacros(urls);
     766           0 :         if (!urls.isEmpty()) {
     767           0 :             parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
     768           0 :         }
     769             :     }
     770         498 : }
     771             : 
     772           0 : void Components::parseModuleLayer(int layer, OUString const & url) {
     773           0 :     parseFiles(layer, ".xcu", &parseXcuFile, url, false);
     774           0 : }
     775             : 
     776         166 : void Components::parseResLayer(int layer, OUString const & url) {
     777         166 :     OUString resUrl(url + "/res");
     778         166 :     parseXcdFiles(layer, resUrl);
     779         166 :     parseFiles(layer, ".xcu", &parseXcuFile, resUrl, false);
     780         166 : }
     781             : 
     782         166 : void Components::parseModificationLayer(OUString const & url) {
     783             :     try {
     784         166 :         parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
     785          68 :     } catch (css::container::NoSuchElementException &) {
     786             :         SAL_INFO(
     787             :             "configmgr", "user registrymodifications.xcu does not (yet) exist");
     788             :         // Migrate old user layer data (can be removed once migration is no
     789             :         // longer relevant, probably OOo 4; also see hack for xsi namespace in
     790             :         // xmlreader::XmlReader::registerNamespaceIri):
     791             :         parseFiles(
     792             :             Data::NO_LAYER, ".xcu", &parseXcuFile,
     793             :             expand(
     794             :                 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
     795             :                 ":UserInstallation}/user/registry/data"),
     796          68 :             false);
     797             :     }
     798         166 : }
     799             : 
     800           0 : int Components::getExtensionLayer(bool shared) {
     801           0 :     int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
     802           0 :     if (layer == -1) {
     803             :         throw css::uno::RuntimeException(
     804           0 :             "insert extension xcs/xcu file into undefined layer");
     805             :     }
     806           0 :     return layer;
     807             : }
     808             : 
     809             : }
     810             : 
     811             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10