LCOV - code coverage report
Current view: top level - configmgr/source - components.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 380 0.0 %
Date: 2014-04-14 Functions: 0 40 0.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 <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           0 : struct UnresolvedListItem {
      76             :     OUString name;
      77             :     rtl::Reference< ParseManager > manager;
      78             : 
      79           0 :     UnresolvedListItem(
      80             :         OUString const & theName,
      81             :         rtl::Reference< ParseManager > theManager):
      82           0 :         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             :     SAL_THROW((
      91             :         css::container::NoSuchElementException, css::uno::RuntimeException))
      92             : {
      93             :     assert(partial == 0 && modifications == 0 && additions == 0);
      94             :     (void) partial; (void) modifications; (void) additions;
      95             :     bool ok = rtl::Reference< ParseManager >(
      96           0 :         new ParseManager(url, new XcsParser(layer, data)))->parse(0);
      97             :     assert(ok);
      98             :     (void) ok; // avoid warnings
      99           0 : }
     100             : 
     101           0 : void parseXcuFile(
     102             :     OUString const & url, int layer, Data & data, Partial const * partial,
     103             :     Modifications * modifications, Additions * additions)
     104             :     SAL_THROW((
     105             :         css::container::NoSuchElementException, css::uno::RuntimeException))
     106             : {
     107             :     bool ok = rtl::Reference< ParseManager >(
     108             :         new ParseManager(
     109             :             url,
     110           0 :             new XcuParser(layer, data, partial, modifications, additions)))->
     111           0 :         parse(0);
     112             :     assert(ok);
     113             :     (void) ok; // avoid warnings
     114           0 : }
     115             : 
     116           0 : OUString expand(OUString const & str) {
     117           0 :     OUString s(str);
     118           0 :     rtl::Bootstrap::expandMacros(s); //TODO: detect failure
     119           0 :     return s;
     120             : }
     121             : 
     122           0 : bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) {
     123             :     assert(node.is());
     124           0 :     if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) {
     125           0 :         return false;
     126             :     }
     127           0 :     switch (node->kind()) {
     128             :     case Node::KIND_LOCALIZED_PROPERTY:
     129             :     case Node::KIND_GROUP:
     130           0 :         for (NodeMap::const_iterator i(node->getMembers().begin());
     131           0 :              i != node->getMembers().end(); ++i)
     132             :         {
     133           0 :             if (!canRemoveFromLayer(layer, i->second)) {
     134           0 :                 return false;
     135             :             }
     136             :         }
     137           0 :         return true;
     138             :     case Node::KIND_SET:
     139           0 :         return node->getMembers().empty();
     140             :     default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE
     141           0 :         return true;
     142             :     }
     143             : }
     144             : 
     145             : }
     146             : 
     147             : class Components::WriteThread: public salhelper::Thread {
     148             : public:
     149             :     WriteThread(
     150             :         rtl::Reference< WriteThread > * reference, Components & components,
     151             :         OUString const & url, Data const & data);
     152             : 
     153           0 :     void flush() { delay_.set(); }
     154             : 
     155             : private:
     156           0 :     virtual ~WriteThread() {}
     157             : 
     158             :     virtual void execute() SAL_OVERRIDE;
     159             : 
     160             :     rtl::Reference< WriteThread > * reference_;
     161             :     Components & components_;
     162             :     OUString url_;
     163             :     Data const & data_;
     164             :     osl::Condition delay_;
     165             :     boost::shared_ptr<osl::Mutex> lock_;
     166             : };
     167             : 
     168           0 : Components::WriteThread::WriteThread(
     169             :     rtl::Reference< WriteThread > * reference, Components & components,
     170             :     OUString const & url, Data const & data):
     171             :     Thread("configmgrWriter"), reference_(reference), components_(components),
     172           0 :     url_(url), data_(data)
     173             : {
     174           0 :     lock_ = lock();
     175             :     assert(reference != 0);
     176           0 : }
     177             : 
     178           0 : void Components::WriteThread::execute() {
     179           0 :     TimeValue t = { 1, 0 }; // 1 sec
     180           0 :     delay_.wait(&t); // must not throw; result_error is harmless and ignored
     181           0 :     osl::MutexGuard g(*lock_); // must not throw
     182             :     try {
     183             :         try {
     184           0 :             writeModFile(components_, url_, data_);
     185           0 :         } catch (css::uno::RuntimeException & e) {
     186             :             // Ignore write errors, instead of aborting:
     187             :             SAL_WARN(
     188             :                 "configmgr",
     189             :                 "error writing modifications: \"" << e.Message << '"');
     190             :         }
     191           0 :     } catch (...) {
     192           0 :         reference_->clear();
     193           0 :         throw;
     194             :     }
     195           0 :     reference_->clear();
     196           0 : }
     197             : 
     198             : class theComponentsSingleton :
     199             :     public rtl::StaticWithArg<
     200             :         Components,
     201             :         css::uno::Reference< css::uno::XComponentContext >,
     202             :         theComponentsSingleton>
     203             : {
     204             : };
     205             : 
     206           0 : Components & Components::getSingleton(
     207             :     css::uno::Reference< css::uno::XComponentContext > const & context)
     208             : {
     209             :     assert(context.is());
     210           0 :     return theComponentsSingleton::get(context);
     211             : }
     212             : 
     213           0 : bool Components::allLocales(OUString const & locale) {
     214           0 :     return locale == "*";
     215             : }
     216             : 
     217           0 : rtl::Reference< Node > Components::resolvePathRepresentation(
     218             :     OUString const & pathRepresentation,
     219             :     OUString * canonicRepresentation, Path * path, int * finalizedLayer)
     220             :     const
     221             : {
     222             :     return data_.resolvePathRepresentation(
     223           0 :         pathRepresentation, canonicRepresentation, path, finalizedLayer);
     224             : }
     225             : 
     226           0 : rtl::Reference< Node > Components::getTemplate(
     227             :     int layer, OUString const & fullName) const
     228             : {
     229           0 :     return data_.getTemplate(layer, fullName);
     230             : }
     231             : 
     232           0 : void Components::addRootAccess(rtl::Reference< RootAccess > const & access) {
     233           0 :     roots_.insert(access.get());
     234           0 : }
     235             : 
     236           0 : void Components::removeRootAccess(RootAccess * access) {
     237           0 :     roots_.erase(access);
     238           0 : }
     239             : 
     240           0 : void Components::initGlobalBroadcaster(
     241             :     Modifications const & modifications,
     242             :     rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster)
     243             : {
     244             :     //TODO: Iterate only over roots w/ listeners:
     245           0 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     246           0 :         rtl::Reference< RootAccess > root;
     247           0 :         if ((*i)->acquireCounting() > 1) {
     248           0 :             root.set(*i); // must not throw
     249             :         }
     250           0 :         (*i)->releaseNondeleting();
     251           0 :         if (root.is()) {
     252           0 :             if (root != exclude) {
     253           0 :                 Path path(root->getAbsolutePath());
     254           0 :                 Modifications::Node const * mods = &modifications.getRoot();
     255           0 :                 for (Path::iterator j(path.begin()); j != path.end(); ++j) {
     256             :                     Modifications::Node::Children::const_iterator k(
     257           0 :                         mods->children.find(*j));
     258           0 :                     if (k == mods->children.end()) {
     259           0 :                         mods = 0;
     260           0 :                         break;
     261             :                     }
     262           0 :                     mods = &k->second;
     263             :                 }
     264             :                 //TODO: If the complete tree of which root is a part is deleted,
     265             :                 // or replaced, mods will be null, but some of the listeners
     266             :                 // from within root should probably fire nonetheless:
     267           0 :                 if (mods != 0) {
     268           0 :                     root->initBroadcaster(*mods, broadcaster);
     269           0 :                 }
     270             :             }
     271             :         }
     272           0 :     }
     273           0 : }
     274             : 
     275           0 : void Components::addModification(Path const & path) {
     276           0 :     data_.modifications.add(path);
     277           0 : }
     278             : 
     279           0 : bool Components::hasModifications() const
     280             : {
     281           0 :     return data_.modifications.getRoot().children.begin() !=
     282           0 :         data_.modifications.getRoot().children.end();
     283             : }
     284             : 
     285           0 : void Components::writeModifications() {
     286             : 
     287           0 :     if (!hasModifications() || modificationFileUrl_.isEmpty())
     288           0 :         return;
     289             : 
     290           0 :     if (!writeThread_.is()) {
     291           0 :         writeThread_ = new WriteThread(
     292           0 :             &writeThread_, *this, modificationFileUrl_, data_);
     293           0 :         writeThread_->launch();
     294             :     }
     295             : }
     296             : 
     297           0 : void Components::flushModifications() {
     298           0 :     rtl::Reference< WriteThread > thread;
     299             :     {
     300           0 :         osl::MutexGuard g(*lock_);
     301           0 :         thread = writeThread_;
     302             :     }
     303           0 :     if (thread.is()) {
     304           0 :         thread->flush();
     305           0 :         thread->join();
     306           0 :     }
     307           0 : }
     308             : 
     309           0 : void Components::insertExtensionXcsFile(
     310             :     bool shared, OUString const & fileUri)
     311             : {
     312           0 :     int layer = getExtensionLayer(shared);
     313             :     try {
     314           0 :         parseXcsFile(fileUri, layer, data_, 0, 0, 0);
     315           0 :     } catch (css::container::NoSuchElementException & e) {
     316             :         throw css::uno::RuntimeException(
     317           0 :             "insertExtensionXcsFile does not exist: " + e.Message,
     318           0 :             css::uno::Reference< css::uno::XInterface >());
     319             :     }
     320           0 : }
     321             : 
     322           0 : void Components::insertExtensionXcuFile(
     323             :     bool shared, OUString const & fileUri, Modifications * modifications)
     324             : {
     325             :     assert(modifications != 0);
     326           0 :     int layer = getExtensionLayer(shared) + 1;
     327           0 :     Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer);
     328             :     try {
     329           0 :         parseXcuFile(fileUri, layer, data_, 0, modifications, adds);
     330           0 :     } catch (css::container::NoSuchElementException & e) {
     331           0 :         data_.removeExtensionXcuAdditions(fileUri);
     332             :         throw css::uno::RuntimeException(
     333           0 :             "insertExtensionXcuFile does not exist: " + 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           0 : css::beans::Optional< css::uno::Any > Components::getExternalValue(
     411             :     OUString const & descriptor)
     412             : {
     413           0 :     sal_Int32 i = descriptor.indexOf(' ');
     414           0 :     if (i <= 0) {
     415             :         throw css::uno::RuntimeException(
     416           0 :             "bad external value descriptor " + descriptor,
     417           0 :             css::uno::Reference< css::uno::XInterface >());
     418             :     }
     419             :     //TODO: Do not make calls with mutex locked:
     420           0 :     OUString name(descriptor.copy(0, i));
     421           0 :     ExternalServices::iterator j(externalServices_.find(name));
     422           0 :     if (j == externalServices_.end()) {
     423           0 :         css::uno::Reference< css::uno::XInterface > service;
     424             :         try {
     425           0 :             service = context_->getServiceManager()->createInstanceWithContext(
     426           0 :                 name, context_);
     427           0 :         } catch (css::uno::RuntimeException &) {
     428             :             // Assuming these exceptions are real errors:
     429           0 :             throw;
     430           0 :         } catch (css::uno::Exception & e) {
     431             :             // Assuming these exceptions indicate that the service is not
     432             :             // installed:
     433             :             SAL_WARN(
     434             :                 "configmgr",
     435             :                 "createInstance(" << name << ") failed with \"" << e.Message
     436             :                     << '"');
     437             :         }
     438           0 :         css::uno::Reference< css::beans::XPropertySet > propset;
     439           0 :         if (service.is()) {
     440           0 :             propset = css::uno::Reference< css::beans::XPropertySet >(
     441           0 :                 service, css::uno::UNO_QUERY_THROW);
     442             :         }
     443             :         j = externalServices_.insert(
     444           0 :             ExternalServices::value_type(name, propset)).first;
     445             :     }
     446           0 :     css::beans::Optional< css::uno::Any > value;
     447           0 :     if (j->second.is()) {
     448             :         try {
     449           0 :             if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>=
     450             :                   value))
     451             :             {
     452             :                 throw css::uno::RuntimeException(
     453           0 :                     "cannot obtain external value through " + descriptor,
     454           0 :                     css::uno::Reference< css::uno::XInterface >());
     455             :             }
     456           0 :         } catch (css::beans::UnknownPropertyException & e) {
     457             :             throw css::uno::RuntimeException(
     458           0 :                 "unknown external value descriptor ID: " + e.Message,
     459           0 :                 css::uno::Reference< css::uno::XInterface >());
     460           0 :         } catch (css::lang::WrappedTargetException & e) {
     461             :             throw css::uno::RuntimeException(
     462           0 :                 "cannot obtain external value: " + e.Message,
     463           0 :                 css::uno::Reference< css::uno::XInterface >());
     464             :         }
     465             :     }
     466           0 :     return value;
     467             : }
     468             : 
     469           0 : Components::Components(
     470             :     css::uno::Reference< css::uno::XComponentContext > const & context):
     471           0 :     context_(context), sharedExtensionLayer_(-1), userExtensionLayer_(-1)
     472             : {
     473             :     assert(context.is());
     474           0 :     lock_ = lock();
     475           0 :     OUString conf(expand("${CONFIGURATION_LAYERS}"));
     476           0 :     int layer = 0;
     477           0 :     for (sal_Int32 i = 0;;) {
     478           0 :         while (i != conf.getLength() && conf[i] == ' ') {
     479           0 :             ++i;
     480             :         }
     481           0 :         if (i == conf.getLength()) {
     482           0 :             break;
     483             :         }
     484           0 :         if (!modificationFileUrl_.isEmpty()) {
     485             :             throw css::uno::RuntimeException(
     486             :                 "CONFIGURATION_LAYERS: \"user\" followed by further layers",
     487           0 :                 css::uno::Reference< css::uno::XInterface >());
     488             :         }
     489           0 :         sal_Int32 c = i;
     490           0 :         for (;; ++c) {
     491           0 :             if (c == conf.getLength() || conf[c] == ' ') {
     492             :                 throw css::uno::RuntimeException(
     493             :                     "CONFIGURATION_LAYERS: missing \":\"",
     494           0 :                     css::uno::Reference< css::uno::XInterface >());
     495             :             }
     496           0 :             if (conf[c] == ':') {
     497           0 :                 break;
     498             :             }
     499             :         }
     500           0 :         sal_Int32 n = conf.indexOf(' ', c + 1);
     501           0 :         if (n == -1) {
     502           0 :             n = conf.getLength();
     503             :         }
     504           0 :         OUString type(conf.copy(i, c - i));
     505           0 :         OUString url(conf.copy(c + 1, n - c - 1));
     506           0 :         if ( type == "xcsxcu" ) {
     507           0 :             parseXcsXcuLayer(layer, url);
     508           0 :             layer += 2; //TODO: overflow
     509           0 :         } else if ( type == "bundledext" )
     510             :         {
     511           0 :             parseXcsXcuIniLayer(layer, url, false);
     512           0 :             layer += 2; //TODO: overflow
     513           0 :         } else if ( type == "sharedext" ) {
     514           0 :             if (sharedExtensionLayer_ != -1) {
     515             :                 throw css::uno::RuntimeException(
     516             :                     "CONFIGURATION_LAYERS: multiple \"sharedext\" layers",
     517           0 :                     css::uno::Reference< css::uno::XInterface >());
     518             :             }
     519           0 :             sharedExtensionLayer_ = layer;
     520           0 :             parseXcsXcuIniLayer(layer, url, true);
     521           0 :             layer += 2; //TODO: overflow
     522           0 :         } else if ( type == "userext" ) {
     523           0 :             if (userExtensionLayer_ != -1) {
     524             :                 throw css::uno::RuntimeException(
     525             :                     "CONFIGURATION_LAYERS: multiple \"userext\" layers",
     526           0 :                     css::uno::Reference< css::uno::XInterface >());
     527             :             }
     528           0 :             userExtensionLayer_ = layer;
     529           0 :             parseXcsXcuIniLayer(layer, url, true);
     530           0 :             layer += 2; //TODO: overflow
     531           0 :         } else if ( type == "module" ) {
     532           0 :             parseModuleLayer(layer, url);
     533           0 :             ++layer; //TODO: overflow
     534           0 :         } else if ( type == "res" ) {
     535           0 :             parseResLayer(layer, url);
     536           0 :             ++layer; //TODO: overflow
     537           0 :         } else if ( type == "user" ) {
     538           0 :             if (url.isEmpty()) {
     539             :                 throw css::uno::RuntimeException(
     540             :                     "CONFIGURATION_LAYERS: empty \"user\" URL",
     541           0 :                     css::uno::Reference< css::uno::XInterface >());
     542             :             }
     543           0 :             modificationFileUrl_ = url;
     544           0 :             parseModificationLayer(url);
     545             :         }
     546             : #ifdef WNT
     547             :         else if ( type == "winreg" )
     548             :         {
     549             :             if (!url.isEmpty()) {
     550             :                 SAL_WARN(
     551             :                     "configmgr",
     552             :                     "winreg URL is not empty, URL handling is not implemented for winreg");
     553             :             }
     554             :             OUString aTempFileURL;
     555             :             if ( dumpWindowsRegistry(&aTempFileURL) )
     556             :             {
     557             :                 parseFileLeniently(&parseXcuFile, aTempFileURL, layer, data_, 0, 0, 0);
     558             :                 layer++;
     559             :                 osl::File::remove(aTempFileURL);
     560             :             }
     561             :         }
     562             : #endif
     563             :         else {
     564             :             throw css::uno::RuntimeException(
     565           0 :                 "CONFIGURATION_LAYERS: unknown layer type \"" + type + "\"",
     566           0 :                 css::uno::Reference< css::uno::XInterface >());
     567             :         }
     568           0 :         i = n;
     569           0 :     }
     570           0 : }
     571             : 
     572           0 : Components::~Components()
     573             : {
     574           0 :     flushModifications();
     575           0 :     for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) {
     576           0 :         (*i)->setAlive(false);
     577             :     }
     578           0 : }
     579             : 
     580           0 : void Components::parseFileLeniently(
     581             :     FileParser * parseFile, OUString const & url, int layer, Data & data,
     582             :     Partial const * partial, Modifications * modifications,
     583             :     Additions * additions)
     584             : {
     585             :     assert(parseFile != 0);
     586             :     try {
     587           0 :         (*parseFile)(url, layer, data, partial, modifications, additions);
     588           0 :     } catch (css::container::NoSuchElementException &) {
     589           0 :         throw;
     590           0 :     } catch (css::uno::Exception & e) { //TODO: more specific exception catching
     591             :         // Ignore invalid XML files, instead of completely preventing OOo from
     592             :         // starting:
     593             :         SAL_WARN(
     594             :             "configmgr",
     595             :             "error reading \"" << url << "\": \"" << e.Message << '"');
     596             :     }
     597           0 : }
     598             : 
     599           0 : void Components::parseFiles(
     600             :     int layer, OUString const & extension, FileParser * parseFile,
     601             :     OUString const & url, bool recursive)
     602             : {
     603           0 :     osl::Directory dir(url);
     604           0 :     switch (dir.open()) {
     605             :     case osl::FileBase::E_None:
     606           0 :         break;
     607             :     case osl::FileBase::E_NOENT:
     608           0 :         if (!recursive) {
     609           0 :             return;
     610             :         }
     611             :         // fall through
     612             :     default:
     613             :         throw css::uno::RuntimeException(
     614           0 :             "cannot open directory " + url,
     615           0 :             css::uno::Reference< css::uno::XInterface >());
     616             :     }
     617             :     for (;;) {
     618           0 :         osl::DirectoryItem i;
     619           0 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     620           0 :         if (rc == osl::FileBase::E_NOENT) {
     621           0 :             break;
     622             :         }
     623           0 :         if (rc != osl::FileBase::E_None) {
     624             :             throw css::uno::RuntimeException(
     625           0 :                 "cannot iterate directory " + url,
     626           0 :                 css::uno::Reference< css::uno::XInterface >());
     627             :         }
     628             :         osl::FileStatus stat(
     629             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     630           0 :             osl_FileStatus_Mask_FileURL);
     631           0 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     632             :             throw css::uno::RuntimeException(
     633           0 :                 "cannot stat in directory " + url,
     634           0 :                 css::uno::Reference< css::uno::XInterface >());
     635             :         }
     636           0 :         if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks
     637           0 :             parseFiles(layer, extension, parseFile, stat.getFileURL(), true);
     638             :         } else {
     639           0 :             OUString file(stat.getFileName());
     640           0 :             if (file.endsWith(extension)) {
     641             :                 try {
     642             :                     parseFileLeniently(
     643           0 :                         parseFile, stat.getFileURL(), layer, data_, 0, 0, 0);
     644           0 :                 } catch (css::container::NoSuchElementException & e) {
     645             :                     throw css::uno::RuntimeException(
     646           0 :                         "stat'ed file does not exist: " + e.Message,
     647           0 :                         css::uno::Reference< css::uno::XInterface >());
     648             :                 }
     649           0 :             }
     650             :         }
     651           0 :     }
     652             : }
     653             : 
     654           0 : void Components::parseFileList(
     655             :     int layer, FileParser * parseFile, OUString const & urls,
     656             :     bool recordAdditions)
     657             : {
     658           0 :     for (sal_Int32 i = 0;;) {
     659           0 :         OUString url(urls.getToken(0, ' ', i));
     660           0 :         if (!url.isEmpty()) {
     661           0 :             Additions * adds = 0;
     662           0 :             if (recordAdditions) {
     663           0 :                 adds = data_.addExtensionXcuAdditions(url, layer);
     664             :             }
     665             :             try {
     666           0 :                 parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds);
     667           0 :             } catch (css::container::NoSuchElementException & e) {
     668             :                 SAL_WARN(
     669             :                     "configmgr", "file does not exist: \"" << e.Message << '"');
     670           0 :                 if (adds != 0) {
     671           0 :                     data_.removeExtensionXcuAdditions(url);
     672             :                 }
     673             :             }
     674             :         }
     675           0 :         if (i == -1) {
     676           0 :             break;
     677             :         }
     678           0 :     }
     679           0 : }
     680             : 
     681           0 : void Components::parseXcdFiles(int layer, OUString const & url) {
     682           0 :     osl::Directory dir(url);
     683           0 :     switch (dir.open()) {
     684             :     case osl::FileBase::E_None:
     685           0 :         break;
     686             :     case osl::FileBase::E_NOENT:
     687           0 :         return;
     688             :     default:
     689             :         throw css::uno::RuntimeException(
     690           0 :             "cannot open directory " + url,
     691           0 :             css::uno::Reference< css::uno::XInterface >());
     692             :     }
     693           0 :     UnresolvedList unres;
     694           0 :     std::set< OUString > existingDeps;
     695           0 :     std::set< OUString > processedDeps;
     696             :     for (;;) {
     697           0 :         osl::DirectoryItem i;
     698           0 :         osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32);
     699           0 :         if (rc == osl::FileBase::E_NOENT) {
     700           0 :             break;
     701             :         }
     702           0 :         if (rc != osl::FileBase::E_None) {
     703             :             throw css::uno::RuntimeException(
     704           0 :                 "cannot iterate directory " + url,
     705           0 :                 css::uno::Reference< css::uno::XInterface >());
     706             :         }
     707             :         osl::FileStatus stat(
     708             :             osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName |
     709           0 :             osl_FileStatus_Mask_FileURL);
     710           0 :         if (i.getFileStatus(stat) != osl::FileBase::E_None) {
     711             :             throw css::uno::RuntimeException(
     712           0 :                 "cannot stat in directory " + url,
     713           0 :                 css::uno::Reference< css::uno::XInterface >());
     714             :         }
     715           0 :         if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks
     716           0 :             OUString file(stat.getFileName());
     717           0 :             OUString name;
     718           0 :             if (file.endsWith(".xcd", &name)) {
     719           0 :                 existingDeps.insert(name);
     720           0 :                 rtl::Reference< ParseManager > manager;
     721             :                 try {
     722           0 :                     manager = new ParseManager(
     723             :                         stat.getFileURL(),
     724           0 :                         new XcdParser(layer, processedDeps, data_));
     725           0 :                 } catch (css::container::NoSuchElementException & e) {
     726             :                     throw css::uno::RuntimeException(
     727           0 :                         "stat'ed file does not exist: " + e.Message,
     728           0 :                         css::uno::Reference< css::uno::XInterface >());
     729             :                 }
     730           0 :                 if (manager->parse(0)) {
     731           0 :                     processedDeps.insert(name);
     732             :                 } else {
     733           0 :                     unres.push_back(UnresolvedListItem(name, manager));
     734           0 :                 }
     735           0 :             }
     736             :         }
     737           0 :     }
     738           0 :     while (!unres.empty()) {
     739           0 :         bool resolved = false;
     740           0 :         for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) {
     741           0 :             if (i->manager->parse(&existingDeps)) {
     742           0 :                 processedDeps.insert(i->name);
     743           0 :                 unres.erase(i++);
     744           0 :                 resolved = true;
     745             :             } else {
     746           0 :                 ++i;
     747             :             }
     748             :         }
     749           0 :         if (!resolved) {
     750             :             throw css::uno::RuntimeException(
     751           0 :                 "xcd: unresolved dependencies in " + url,
     752           0 :                 css::uno::Reference< css::uno::XInterface >());
     753             :         }
     754           0 :     }
     755             : }
     756             : 
     757           0 : void Components::parseXcsXcuLayer(int layer, OUString const & url) {
     758           0 :     parseXcdFiles(layer, url);
     759           0 :     parseFiles(layer, ".xcs", &parseXcsFile, url + "/schema", false);
     760           0 :     parseFiles(layer + 1, ".xcu", &parseXcuFile, url + "/data", false);
     761           0 : }
     762             : 
     763           0 : void Components::parseXcsXcuIniLayer(
     764             :     int layer, OUString const & url, bool recordAdditions)
     765             : {
     766             :     // Check if ini file exists (otherwise .override would still read global
     767             :     // SCHEMA/DATA variables, which could interfere with unrelated environment
     768             :     // variables):
     769           0 :     if (rtl::Bootstrap(url).getHandle() != 0) {
     770           0 :         OUStringBuffer prefix("${.override:");
     771           0 :         for (sal_Int32 i = 0; i != url.getLength(); ++i) {
     772           0 :             sal_Unicode c = url[i];
     773           0 :             switch (c) {
     774             :             case '$':
     775             :             case ':':
     776             :             case '\\':
     777           0 :                 prefix.append('\\');
     778             :                 // fall through
     779             :             default:
     780           0 :                 prefix.append(c);
     781             :             }
     782             :         }
     783           0 :         prefix.append(':');
     784           0 :         OUString urls(prefix.toString() + "SCHEMA}");
     785           0 :         rtl::Bootstrap::expandMacros(urls);
     786           0 :         if (!urls.isEmpty()) {
     787           0 :             parseFileList(layer, &parseXcsFile, urls, false);
     788             :         }
     789           0 :         urls = prefix.makeStringAndClear() + "DATA}";
     790           0 :         rtl::Bootstrap::expandMacros(urls);
     791           0 :         if (!urls.isEmpty()) {
     792           0 :             parseFileList(layer + 1, &parseXcuFile, urls, recordAdditions);
     793           0 :         }
     794             :     }
     795           0 : }
     796             : 
     797           0 : void Components::parseModuleLayer(int layer, OUString const & url) {
     798           0 :     parseFiles(layer, ".xcu", &parseXcuFile, url, false);
     799           0 : }
     800             : 
     801           0 : void Components::parseResLayer(int layer, OUString const & url) {
     802           0 :     OUString resUrl(url + "/res");
     803           0 :     parseXcdFiles(layer, resUrl);
     804           0 :     parseFiles(layer, ".xcu", &parseXcuFile, resUrl, false);
     805           0 : }
     806             : 
     807           0 : void Components::parseModificationLayer(OUString const & url) {
     808             :     try {
     809           0 :         parseFileLeniently(&parseXcuFile, url, Data::NO_LAYER, data_, 0, 0, 0);
     810           0 :     } catch (css::container::NoSuchElementException &) {
     811             :         SAL_INFO(
     812             :             "configmgr", "user registrymodifications.xcu does not (yet) exist");
     813             :         // Migrate old user layer data (can be removed once migration is no
     814             :         // longer relevant, probably OOo 4; also see hack for xsi namespace in
     815             :         // xmlreader::XmlReader::registerNamespaceIri):
     816             :         parseFiles(
     817             :             Data::NO_LAYER, ".xcu", &parseXcuFile,
     818             :             expand(
     819             :                 "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap")
     820             :                 ":UserInstallation}/user/registry/data"),
     821           0 :             false);
     822             :     }
     823           0 : }
     824             : 
     825           0 : int Components::getExtensionLayer(bool shared) {
     826           0 :     int layer = shared ? sharedExtensionLayer_ : userExtensionLayer_;
     827           0 :     if (layer == -1) {
     828             :         throw css::uno::RuntimeException(
     829             :             "insert extension xcs/xcu file into undefined layer",
     830           0 :             css::uno::Reference< css::uno::XInterface >());
     831             :     }
     832           0 :     return layer;
     833             : }
     834             : 
     835             : }
     836             : 
     837             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10