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

Generated by: LCOV version 1.10