LCOV - code coverage report
Current view: top level - configmgr/source - components.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 233 366 63.7 %
Date: 2015-06-13 12:38:46 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        3750 : struct UnresolvedListItem {
      76             :     OUString name;
      77             :     rtl::Reference< ParseManager > manager;
      78             : 
      79        1250 :     UnresolvedListItem(
      80             :         OUString const & theName,
      81             :         rtl::Reference< ParseManager > theManager):
      82        1250 :         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         119 : 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         238 :             new XcuParser(layer, data, partial, modifications, additions)))->
     107         302 :         parse(0);
     108             :     assert(ok);
     109             :     (void) ok; // avoid warnings
     110          64 : }
     111             : 
     112         305 : OUString expand(OUString const & str) {
     113         305 :     OUString s(str);
     114         305 :     rtl::Bootstrap::expandMacros(s); //TODO: detect failure
     115         305 :     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         231 :     void flush() { delay_.set(); }
     150             : 
     151             : private:
     152        2444 :     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             :     std::shared_ptr<osl::Mutex> lock_;
     162             : };
     163             : 
     164        1222 : 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        1222 :     url_(url), data_(data)
     169             : {
     170        1222 :     lock_ = lock();
     171             :     assert(reference != 0);
     172        1222 : }
     173             : 
     174        1222 : void Components::WriteThread::execute() {
     175        1222 :     TimeValue t = { 1, 0 }; // 1 sec
     176        1222 :     delay_.wait(&t); // must not throw; result_error is harmless and ignored
     177        1222 :     osl::MutexGuard g(*lock_); // must not throw
     178             :     try {
     179             :         try {
     180        1222 :             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        1222 :     reference_->clear();
     192        1222 : }
     193             : 
     194             : class theComponentsSingleton :
     195             :     public rtl::StaticWithArg<
     196             :         Components,
     197             :         css::uno::Reference< css::uno::XComponentContext >,
     198             :         theComponentsSingleton>
     199             : {
     200             : };
     201             : 
     202    26827343 : Components & Components::getSingleton(
     203             :     css::uno::Reference< css::uno::XComponentContext > const & context)
     204             : {
     205             :     assert(context.is());
     206    26827343 :     return theComponentsSingleton::get(context);
     207             : }
     208             : 
     209      689483 : bool Components::allLocales(OUString const & locale) {
     210      689483 :     return locale == "*";
     211             : }
     212             : 
     213    26860321 : rtl::Reference< Node > Components::resolvePathRepresentation(
     214             :     OUString const & pathRepresentation,
     215             :     OUString * canonicRepresentation, Path * path, int * finalizedLayer)
     216             :     const
     217             : {
     218             :     return data_.resolvePathRepresentation(
     219    26860321 :         pathRepresentation, canonicRepresentation, path, finalizedLayer);
     220             : }
     221             : 
     222        3121 : rtl::Reference< Node > Components::getTemplate(
     223             :     int layer, OUString const & fullName) const
     224             : {
     225        3121 :     return data_.getTemplate(layer, fullName);
     226             : }
     227             : 
     228    26826746 : void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
     229    26826746 :     roots_.insert(access.get());
     230    26826746 : }
     231             : 
     232    26824930 : void Components::removeRootAccess(RootAccess * access) {
     233    26824930 :     roots_.erase(access);
     234    26824930 : }
     235             : 
     236       37476 : 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     2347414 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     242     2309938 :         rtl::Reference< RootAccess > root;
     243     2309938 :         if ((*i)->acquireCounting() > 1) {
     244     2309938 :             root.set(*i); // must not throw
     245             :         }
     246     2309938 :         (*i)->releaseNondeleting();
     247     2309938 :         if (root.is()) {
     248     2309938 :             if (root != exclude) {
     249     2272462 :                 Path path(root->getAbsolutePath());
     250     2272462 :                 Modifications::Node const * mods = &modifications.getRoot();
     251     2403384 :                 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
     252             :                     Modifications::Node::Children::const_iterator k(
     253     2236329 :                         mods->children.find(*j));
     254     2236329 :                     if (k == mods->children.end()) {
     255     2105407 :                         mods = 0;
     256     2105407 :                         break;
     257             :                     }
     258      130922 :                     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     2272462 :                 if (mods != 0) {
     264      167055 :                     root->initBroadcaster(*mods, broadcaster);
     265     2272462 :                 }
     266             :             }
     267             :         }
     268     2309938 :     }
     269       37476 : }
     270             : 
     271      222226 : void Components::addModification(Path const & path) {
     272      222226 :     data_.modifications.add(path);
     273      222226 : }
     274             : 
     275       37476 : bool Components::hasModifications() const
     276             : {
     277       74952 :     return data_.modifications.getRoot().children.begin() !=
     278      112428 :         data_.modifications.getRoot().children.end();
     279             : }
     280             : 
     281       37476 : void Components::writeModifications() {
     282             : 
     283       37476 :     if (!hasModifications() || modificationFileUrl_.isEmpty())
     284       65804 :         return;
     285             : 
     286        9148 :     if (!writeThread_.is()) {
     287        2444 :         writeThread_ = new WriteThread(
     288        2444 :             &writeThread_, *this, modificationFileUrl_, data_);
     289        1222 :         writeThread_->launch();
     290             :     }
     291             : }
     292             : 
     293         847 : void Components::flushModifications() {
     294         847 :     rtl::Reference< WriteThread > thread;
     295             :     {
     296         847 :         osl::MutexGuard g(*lock_);
     297         847 :         thread = writeThread_;
     298             :     }
     299         847 :     if (thread.is()) {
     300         231 :         thread->flush();
     301         231 :         thread->join();
     302         847 :     }
     303         847 : }
     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        1160 : css::beans::Optional< css::uno::Any > Components::getExternalValue(
     405             :     OUString const & descriptor)
     406             : {
     407        1160 :     sal_Int32 i = descriptor.indexOf(' ');
     408        1160 :     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        1160 :     OUString name(descriptor.copy(0, i));
     414        1160 :     ExternalServices::iterator j(externalServices_.find(name));
     415        1160 :     if (j == externalServices_.end()) {
     416         328 :         css::uno::Reference< css::uno::XInterface > service;
     417             :         try {
     418         984 :             service = context_->getServiceManager()->createInstanceWithContext(
     419         656 :                 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         656 :         css::uno::Reference< css::beans::XPropertySet > propset;
     432         328 :         if (service.is()) {
     433         496 :             propset = css::uno::Reference< css::beans::XPropertySet >(
     434         248 :                 service, css::uno::UNO_QUERY_THROW);
     435             :         }
     436             :         j = externalServices_.insert(
     437         656 :             ExternalServices::value_type(name, propset)).first;
     438             :     }
     439        1160 :     css::beans::Optional< css::uno::Any > value;
     440        1160 :     if (j->second.is()) {
     441             :         try {
     442         883 :             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        1160 :     return value;
     457             : }
     458             : 
     459         250 : Components::Components(
     460             :     css::uno::Reference< css::uno::XComponentContext > const & context):
     461         250 :     context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
     462             : {
     463             :     assert(context.is());
     464         250 :     lock_ = lock();
     465         250 :     OUString conf(expand("${CONFIGURATION_LAYERS}"));
     466         250 :     int layer = 0;
     467         250 :     for (sal_Int32 i = 0;;) {
     468        3148 :         while (i != conf.getLength() && conf[i] == ' ') {
     469         716 :             ++i;
     470             :         }
     471        1216 :         if (i == conf.getLength()) {
     472         250 :             break;
     473             :         }
     474         966 :         if (!modificationFileUrl_.isEmpty()) {
     475             :             throw css::uno::RuntimeException(
     476           0 :                 "CONFIGURATION_LAYERS: \"user\" followed by further layers");
     477             :         }
     478         966 :         sal_Int32 c = i;
     479        6153 :         for (;; ++c) {
     480        7119 :             if (c == conf.getLength() || conf[c] == ' ') {
     481             :                 throw css::uno::RuntimeException(
     482           0 :                     "CONFIGURATION_LAYERS: missing \":\"");
     483             :             }
     484        7119 :             if (conf[c] == ':') {
     485         966 :                 break;
     486             :             }
     487             :         }
     488         966 :         sal_Int32 n = conf.indexOf(' ', c + 1);
     489         966 :         if (n == -1) {
     490         250 :             n = conf.getLength();
     491             :         }
     492         966 :         OUString type(conf.copy(i, c - i));
     493        1932 :         OUString url(conf.copy(c + 1, n - c - 1));
     494         966 :         if ( type == "xcsxcu" ) {
     495         371 :             sal_uInt32 nStartTime = osl_getGlobalTimer();
     496         371 :             parseXcsXcuLayer(layer, url);
     497             :             SAL_INFO("configmgr", "parseXcsXcuLayer() took " << (osl_getGlobalTimer() - nStartTime) << " ms");
     498         371 :             layer += 2; //TODO: overflow
     499         595 :         } else if ( type == "bundledext" )
     500             :         {
     501         119 :             parseXcsXcuIniLayer(layer, url, false);
     502         119 :             layer += 2; //TODO: overflow
     503         476 :         } else if ( type == "sharedext" ) {
     504         119 :             if (sharedExtensionLayer_ != -1) {
     505             :                 throw css::uno::RuntimeException(
     506           0 :                     "CONFIGURATION_LAYERS: multiple \"sharedext\" layers");
     507             :             }
     508         119 :             sharedExtensionLayer_ = layer;
     509         119 :             parseXcsXcuIniLayer(layer, url, true);
     510         119 :             layer += 2; //TODO: overflow
     511         357 :         } else if ( type == "userext" ) {
     512         119 :             if (userExtensionLayer_ != -1) {
     513             :                 throw css::uno::RuntimeException(
     514           0 :                     "CONFIGURATION_LAYERS: multiple \"userext\" layers");
     515             :             }
     516         119 :             userExtensionLayer_ = layer;
     517         119 :             parseXcsXcuIniLayer(layer, url, true);
     518         119 :             layer += 2; //TODO: overflow
     519         238 :         } else if ( type == "module" ) {
     520           0 :             parseModuleLayer(layer, url);
     521           0 :             ++layer; //TODO: overflow
     522         238 :         } else if ( type == "res" ) {
     523         119 :             sal_uInt32 nStartTime = osl_getGlobalTimer();
     524         119 :             parseResLayer(layer, url);
     525             :             SAL_INFO("configmgr", "parseResLayer() took " << (osl_getGlobalTimer() - nStartTime) << " ms");
     526         119 :             ++layer; //TODO: overflow
     527         119 :         } else if ( type == "user" ) {
     528         119 :             if (url.isEmpty()) {
     529             :                 throw css::uno::RuntimeException(
     530           0 :                     "CONFIGURATION_LAYERS: empty \"user\" URL");
     531             :             }
     532         119 :             modificationFileUrl_ = url;
     533         119 :             parseModificationLayer(url);
     534             :         }
     535             : #ifdef WNT
     536             :         else if ( type == "winreg" )
     537             :         {
     538             :             if (!url.isEmpty()) {
     539             :                 SAL_WARN(
     540             :                     "configmgr",
     541             :                     "winreg URL is not empty, URL handling is not implemented for winreg");
     542             :             }
     543             :             OUString aTempFileURL;
     544             :             if ( dumpWindowsRegistry(&aTempFileURL) )
     545             :             {
     546             :                 parseFileLeniently(&parseXcuFile, aTempFileURL, layer, data_, 0, 0, 0);
     547             :                 layer++;
     548             :                 osl::File::remove(aTempFileURL);
     549             :             }
     550             :         }
     551             : #endif
     552             :         else {
     553             :             throw css::uno::RuntimeException(
     554           0 :                 "CONFIGURATION_LAYERS: unknown layer type \"" + type + "\"");
     555             :         }
     556         966 :         i = n;
     557        7369 :     }
     558         250 : }
     559             : 
     560         500 : Components::~Components()
     561             : {
     562         250 :     flushModifications();
     563        2066 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     564        1816 :         (*i)->setAlive(false);
     565             :     }
     566         250 : }
     567             : 
     568         119 : void Components::parseFileLeniently(
     569             :     FileParser * parseFile, OUString const & url, int layer, Data & data,
     570             :     Partial const * partial, Modifications * modifications,
     571             :     Additions * additions)
     572             : {
     573             :     assert(parseFile != 0);
     574             :     try {
     575         119 :         (*parseFile)(url, layer, data, partial, modifications, additions);
     576          55 :     } catch (css::container::NoSuchElementException &) {
     577          55 :         throw;
     578           0 :     } catch (css::uno::Exception & e) { //TODO: more specific exception catching
     579             :         // Ignore invalid XML files, instead of completely preventing OOo from
     580             :         // starting:
     581             :         SAL_WARN(
     582             :             "configmgr",
     583             :             "error reading \"" << url << "\": \"" << e.Message << '"');
     584             :     }
     585          64 : }
     586             : 
     587         916 : void Components::parseFiles(
     588             :     int layer, OUString const & extension, FileParser * parseFile,
     589             :     OUString const & url, bool recursive)
     590             : {
     591         916 :     osl::Directory dir(url);
     592         916 :     switch (dir.open()) {
     593             :     case osl::FileBase::E_None:
     594         119 :         break;
     595             :     case osl::FileBase::E_NOENT:
     596         797 :         if (!recursive) {
     597        1713 :             return;
     598             :         }
     599             :         // fall through
     600             :     default:
     601             :         throw css::uno::RuntimeException(
     602           0 :             "cannot open directory " + url);
     603             :     }
     604             :     for (;;) {
     605         357 :         osl::DirectoryItem i;
     606         357 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     607         357 :         if (rc == osl::FileBase::E_NOENT) {
     608         119 :             break;
     609             :         }
     610         238 :         if (rc != osl::FileBase::E_None) {
     611             :             throw css::uno::RuntimeException(
     612           0 :                 "cannot iterate directory " + url);
     613             :         }
     614             :         osl::FileStatus stat(
     615             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     616         476 :             osl_FileStatus_Mask_FileURL);
     617         238 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     618             :             throw css::uno::RuntimeException(
     619           0 :                 "cannot stat in directory " + url);
     620             :         }
     621         238 :         if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
     622           0 :             parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
     623             :         } else {
     624         238 :             OUString file(stat.getFileName());
     625         238 :             if (file.endsWith(extension)) {
     626             :                 try {
     627             :                     parseFileLeniently(
     628           0 :                         parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
     629           0 :                 } catch (css::container::NoSuchElementException & e) {
     630             :                     throw css::uno::RuntimeException(
     631           0 :                         "stat'ed file does not exist: " + e.Message);
     632             :                 }
     633         238 :             }
     634             :         }
     635         238 :     }
     636             : }
     637             : 
     638           0 : void Components::parseFileList(
     639             :     int layer, FileParser * parseFile, OUString const & urls,
     640             :     bool recordAdditions)
     641             : {
     642           0 :     for (sal_Int32 i = 0;;) {
     643           0 :         OUString url(urls.getToken(0, ' ', i));
     644           0 :         if (!url.isEmpty()) {
     645           0 :             Additions * adds = 0;
     646           0 :             if (recordAdditions) {
     647           0 :                 adds = data_.addExtensionXcuAdditions(url, layer);
     648             :             }
     649             :             try {
     650           0 :                 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
     651           0 :             } catch (css::container::NoSuchElementException & e) {
     652             :                 SAL_WARN(
     653             :                     "configmgr", "file does not exist: \"" << e.Message << '"');
     654           0 :                 if (adds != 0) {
     655           0 :                     data_.removeExtensionXcuAdditions(url);
     656             :                 }
     657             :             }
     658             :         }
     659           0 :         if (i == -1) {
     660           0 :             break;
     661             :         }
     662           0 :     }
     663           0 : }
     664             : 
     665         490 : void Components::parseXcdFiles(int layer, OUString const & url) {
     666         490 :     osl::Directory dir(url);
     667         490 :     switch (dir.open()) {
     668             :     case osl::FileBase::E_None:
     669         490 :         break;
     670             :     case osl::FileBase::E_NOENT:
     671         490 :         return;
     672             :     default:
     673             :         throw css::uno::RuntimeException(
     674           0 :             "cannot open directory " + url);
     675             :     }
     676         490 :     UnresolvedList unres;
     677         980 :     std::set< OUString > existingDeps;
     678         980 :     std::set< OUString > processedDeps;
     679             :     for (;;) {
     680        6349 :         osl::DirectoryItem i;
     681        6349 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     682        6349 :         if (rc == osl::FileBase::E_NOENT) {
     683         490 :             break;
     684             :         }
     685        5859 :         if (rc != osl::FileBase::E_None) {
     686             :             throw css::uno::RuntimeException(
     687           0 :                 "cannot iterate directory " + url);
     688             :         }
     689             :         osl::FileStatus stat(
     690             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     691       11718 :             osl_FileStatus_Mask_FileURL);
     692        5859 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     693             :             throw css::uno::RuntimeException(
     694           0 :                 "cannot stat in directory " + url);
     695             :         }
     696        5859 :         if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
     697        5609 :             OUString file(stat.getFileName());
     698       11218 :             OUString name;
     699        5609 :             if (file.endsWith(".xcd", &name)) {
     700        5109 :                 existingDeps.insert(name);
     701        5109 :                 rtl::Reference< ParseManager > manager;
     702             :                 try {
     703       15327 :                     manager = new ParseManager(
     704             :                         stat.getFileURL(),
     705       10218 :                         new XcdParser(layer, processedDeps, data_));
     706           0 :                 } catch (css::container::NoSuchElementException & e) {
     707             :                     throw css::uno::RuntimeException(
     708           0 :                         "stat'ed file does not exist: " + e.Message);
     709             :                 }
     710        5109 :                 if (manager->parse(0)) {
     711        3859 :                     processedDeps.insert(name);
     712             :                 } else {
     713        1250 :                     unres.push_back(UnresolvedListItem(name, manager));
     714        5109 :                 }
     715        5609 :             }
     716             :         }
     717        5859 :     }
     718        1230 :     while (!unres.empty()) {
     719         250 :         bool resolved = false;
     720        1750 :         for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
     721        1250 :             if (i->manager->parse(&existingDeps)) {
     722        1250 :                 processedDeps.insert(i->name);
     723        1250 :                 unres.erase(i++);
     724        1250 :                 resolved = true;
     725             :             } else {
     726           0 :                 ++i;
     727             :             }
     728             :         }
     729         250 :         if (!resolved) {
     730             :             throw css::uno::RuntimeException(
     731           0 :                 "xcd: unresolved dependencies in " + url);
     732             :         }
     733         490 :     }
     734             : }
     735             : 
     736         371 : void Components::parseXcsXcuLayer(int layer, OUString const & url) {
     737         371 :     parseXcdFiles(layer, url);
     738         371 :     parseFiles(layer, ".xcs", &parseXcsFile, url + "/schema", false);
     739         371 :     parseFiles(layer + 1, ".xcu", &parseXcuFile, url + "/data", false);
     740         371 : }
     741             : 
     742         357 : void Components::parseXcsXcuIniLayer(
     743             :     int layer, OUString const & url, bool recordAdditions)
     744             : {
     745             :     // Check if ini file exists (otherwise .override would still read global
     746             :     // SCHEMA/DATA variables, which could interfere with unrelated environment
     747             :     // variables):
     748         357 :     if (rtl::Bootstrap(url).getHandle() != 0) {
     749           0 :         OUStringBuffer prefix("${.override:");
     750           0 :         for (sal_Int32 i = 0; i != url.getLength(); ++i) {
     751           0 :             sal_Unicode c = url[i];
     752           0 :             switch (c) {
     753             :             case '$':
     754             :             case ':':
     755             :             case '\\':
     756           0 :                 prefix.append('\\');
     757             :                 // fall through
     758             :             default:
     759           0 :                 prefix.append(c);
     760             :             }
     761             :         }
     762           0 :         prefix.append(':');
     763           0 :         OUString urls(prefix.toString() + "SCHEMA}");
     764           0 :         rtl::Bootstrap::expandMacros(urls);
     765           0 :         if (!urls.isEmpty()) {
     766           0 :             parseFileList(layer, &parseXcsFile, urls, false);
     767             :         }
     768           0 :         urls = prefix.makeStringAndClear() + "DATA}";
     769           0 :         rtl::Bootstrap::expandMacros(urls);
     770           0 :         if (!urls.isEmpty()) {
     771           0 :             parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
     772           0 :         }
     773             :     }
     774         357 : }
     775             : 
     776           0 : void Components::parseModuleLayer(int layer, OUString const & url) {
     777           0 :     parseFiles(layer, ".xcu", &parseXcuFile, url, false);
     778           0 : }
     779             : 
     780         119 : void Components::parseResLayer(int layer, OUString const & url) {
     781         119 :     OUString resUrl(url + "/res");
     782         119 :     parseXcdFiles(layer, resUrl);
     783         119 :     parseFiles(layer, ".xcu", &parseXcuFile, resUrl, false);
     784         119 : }
     785             : 
     786         119 : void Components::parseModificationLayer(OUString const & url) {
     787             :     try {
     788         119 :         parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
     789          55 :     } catch (css::container::NoSuchElementException &) {
     790             :         SAL_INFO(
     791             :             "configmgr", "user registrymodifications.xcu does not (yet) exist");
     792             :         // Migrate old user layer data (can be removed once migration is no
     793             :         // longer relevant, probably OOo 4; also see hack for xsi namespace in
     794             :         // xmlreader::XmlReader::registerNamespaceIri):
     795             :         parseFiles(
     796             :             Data::NO_LAYER, ".xcu", &parseXcuFile,
     797             :             expand(
     798             :                 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
     799             :                 ":UserInstallation}/user/registry/data"),
     800          55 :             false);
     801             :     }
     802         119 : }
     803             : 
     804           0 : int Components::getExtensionLayer(bool shared) {
     805           0 :     int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
     806           0 :     if (layer == -1) {
     807             :         throw css::uno::RuntimeException(
     808           0 :             "insert extension xcs/xcu file into undefined layer");
     809             :     }
     810           0 :     return layer;
     811             : }
     812             : 
     813             : }
     814             : 
     815             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11