| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "precompiled_configmgr.hxx" |
| #include "sal/config.h" |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <list> |
| |
| #include "com/sun/star/beans/Optional.hpp" |
| #include "com/sun/star/beans/UnknownPropertyException.hpp" |
| #include "com/sun/star/beans/XPropertySet.hpp" |
| #include "com/sun/star/container/NoSuchElementException.hpp" |
| #include "com/sun/star/lang/WrappedTargetException.hpp" |
| #include "com/sun/star/lang/XMultiComponentFactory.hpp" |
| #include "com/sun/star/uno/Any.hxx" |
| #include "com/sun/star/uno/Exception.hpp" |
| #include "com/sun/star/uno/Reference.hxx" |
| #include "com/sun/star/uno/RuntimeException.hpp" |
| #include "com/sun/star/uno/XComponentContext.hpp" |
| #include "com/sun/star/uno/XInterface.hpp" |
| #include "osl/conditn.hxx" |
| #include "osl/diagnose.h" |
| #include "osl/file.hxx" |
| #include "osl/mutex.hxx" |
| #include "osl/thread.hxx" |
| #include "rtl/bootstrap.hxx" |
| #include "rtl/logfile.h" |
| #include "rtl/ref.hxx" |
| #include "rtl/string.h" |
| #include "rtl/textenc.h" |
| #include "rtl/ustring.h" |
| #include "rtl/ustring.hxx" |
| #include "sal/types.h" |
| #include "salhelper/simplereferenceobject.hxx" |
| |
| #include "additions.hxx" |
| #include "components.hxx" |
| #include "data.hxx" |
| #include "lock.hxx" |
| #include "modifications.hxx" |
| #include "node.hxx" |
| #include "nodemap.hxx" |
| #include "parsemanager.hxx" |
| #include "partial.hxx" |
| #include "rootaccess.hxx" |
| #include "writemodfile.hxx" |
| #include "xcdparser.hxx" |
| #include "xcuparser.hxx" |
| #include "xcsparser.hxx" |
| |
| namespace configmgr { |
| |
| namespace { |
| |
| namespace css = com::sun::star; |
| |
| struct UnresolvedListItem { |
| rtl::OUString name; |
| rtl::Reference< ParseManager > manager; |
| |
| UnresolvedListItem( |
| rtl::OUString const & theName, |
| rtl::Reference< ParseManager > theManager): |
| name(theName), manager(theManager) {} |
| }; |
| |
| typedef std::list< UnresolvedListItem > UnresolvedList; |
| |
| void parseXcsFile( |
| rtl::OUString const & url, int layer, Data & data, Partial const * partial, |
| Modifications * modifications, Additions * additions) |
| SAL_THROW(( |
| css::container::NoSuchElementException, css::uno::RuntimeException)) |
| { |
| OSL_ASSERT(partial == 0 && modifications == 0 && additions == 0); |
| (void) partial; (void) modifications; (void) additions; |
| OSL_VERIFY( |
| rtl::Reference< ParseManager >( |
| new ParseManager(url, new XcsParser(layer, data)))->parse()); |
| } |
| |
| void parseXcuFile( |
| rtl::OUString const & url, int layer, Data & data, Partial const * partial, |
| Modifications * modifications, Additions * additions) |
| SAL_THROW(( |
| css::container::NoSuchElementException, css::uno::RuntimeException)) |
| { |
| OSL_VERIFY( |
| rtl::Reference< ParseManager >( |
| new ParseManager( |
| url, |
| new XcuParser( |
| layer, data, partial, modifications, additions)))-> |
| parse()); |
| } |
| |
| rtl::OUString expand(rtl::OUString const & str) { |
| rtl::OUString s(str); |
| rtl::Bootstrap::expandMacros(s); //TODO: detect failure |
| return s; |
| } |
| |
| bool canRemoveFromLayer(int layer, rtl::Reference< Node > const & node) { |
| OSL_ASSERT(node.is()); |
| if (node->getLayer() > layer && node->getLayer() < Data::NO_LAYER) { |
| return false; |
| } |
| switch (node->kind()) { |
| case Node::KIND_LOCALIZED_PROPERTY: |
| case Node::KIND_GROUP: |
| for (NodeMap::iterator i(node->getMembers().begin()); |
| i != node->getMembers().end(); ++i) |
| { |
| if (!canRemoveFromLayer(layer, i->second)) { |
| return false; |
| } |
| } |
| return true; |
| case Node::KIND_SET: |
| return node->getMembers().empty(); |
| default: // Node::KIND_PROPERTY, Node::KIND_LOCALIZED_VALUE |
| return true; |
| } |
| } |
| |
| static bool singletonCreated = false; |
| static Components * singleton = 0; |
| |
| } |
| |
| class Components::WriteThread: |
| public osl::Thread, public salhelper::SimpleReferenceObject |
| { |
| public: |
| static void * operator new(std::size_t size) |
| { return Thread::operator new(size); } |
| |
| static void operator delete(void * pointer) |
| { Thread::operator delete(pointer); } |
| |
| WriteThread( |
| rtl::Reference< WriteThread > * reference, Components & components, |
| rtl::OUString const & url, Data const & data); |
| |
| void flush() { delay_.set(); } |
| |
| private: |
| virtual ~WriteThread() {} |
| |
| virtual void SAL_CALL run(); |
| |
| virtual void SAL_CALL onTerminated() { release(); } |
| |
| rtl::Reference< WriteThread > * reference_; |
| Components & components_; |
| rtl::OUString url_; |
| Data const & data_; |
| osl::Condition delay_; |
| }; |
| |
| Components::WriteThread::WriteThread( |
| rtl::Reference< WriteThread > * reference, Components & components, |
| rtl::OUString const & url, Data const & data): |
| reference_(reference), components_(components), url_(url), data_(data) |
| { |
| OSL_ASSERT(reference != 0); |
| acquire(); |
| } |
| |
| void Components::WriteThread::run() { |
| TimeValue t = { 1, 0 }; // 1 sec |
| delay_.wait(&t); // must not throw; result_error is harmless and ignored |
| osl::MutexGuard g(lock); // must not throw |
| try { |
| try { |
| writeModFile(components_, url_, data_); |
| } catch (css::uno::RuntimeException & e) { |
| // Silently ignore write errors, instead of aborting: |
| OSL_TRACE( |
| "configmgr error writing modifications: %s", |
| rtl::OUStringToOString( |
| e.Message, RTL_TEXTENCODING_UTF8).getStr()); |
| } |
| } catch (...) { |
| reference_->clear(); |
| throw; |
| } |
| reference_->clear(); |
| } |
| |
| Components & Components::getSingleton( |
| css::uno::Reference< css::uno::XComponentContext > const & context) |
| { |
| OSL_ASSERT(context.is()); |
| if (!singletonCreated) { |
| singletonCreated = true; |
| static Components theSingleton(context); |
| singleton = &theSingleton; |
| } |
| if (singleton == 0) { |
| throw css::uno::RuntimeException( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "configmgr no Components singleton")), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| return *singleton; |
| } |
| |
| bool Components::allLocales(rtl::OUString const & locale) { |
| return locale.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("*")); |
| } |
| |
| rtl::Reference< Node > Components::resolvePathRepresentation( |
| rtl::OUString const & pathRepresentation, |
| rtl::OUString * canonicRepresentation, Path * path, int * finalizedLayer) |
| const |
| { |
| return data_.resolvePathRepresentation( |
| pathRepresentation, canonicRepresentation, path, finalizedLayer); |
| } |
| |
| rtl::Reference< Node > Components::getTemplate( |
| int layer, rtl::OUString const & fullName) const |
| { |
| return data_.getTemplate(layer, fullName); |
| } |
| |
| void Components::addRootAccess(rtl::Reference< RootAccess > const & access) { |
| roots_.insert(access.get()); |
| } |
| |
| void Components::removeRootAccess(RootAccess * access) { |
| roots_.erase(access); |
| } |
| |
| void Components::initGlobalBroadcaster( |
| Modifications const & modifications, |
| rtl::Reference< RootAccess > const & exclude, Broadcaster * broadcaster) |
| { |
| //TODO: Iterate only over roots w/ listeners: |
| for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) { |
| rtl::Reference< RootAccess > root; |
| if ((*i)->acquireCounting() > 1) { |
| root.set(*i); // must not throw |
| } |
| (*i)->releaseNondeleting(); |
| if (root.is()) { |
| if (root != exclude) { |
| Path path(root->getAbsolutePath()); |
| Modifications::Node const * mods = &modifications.getRoot(); |
| for (Path::iterator j(path.begin()); j != path.end(); ++j) { |
| Modifications::Node::Children::const_iterator k( |
| mods->children.find(*j)); |
| if (k == mods->children.end()) { |
| mods = 0; |
| break; |
| } |
| mods = &k->second; |
| } |
| //TODO: If the complete tree of which root is a part is deleted, |
| // or replaced, mods will be null, but some of the listeners |
| // from within root should probably fire nonetheless: |
| if (mods != 0) { |
| root->initBroadcaster(*mods, broadcaster); |
| } |
| } |
| } |
| } |
| } |
| |
| void Components::addModification(Path const & path) { |
| data_.modifications.add(path); |
| } |
| |
| void Components::writeModifications() { |
| if (!writeThread_.is()) { |
| writeThread_ = new WriteThread( |
| &writeThread_, *this, getModificationFileUrl(), data_); |
| writeThread_->create(); |
| } |
| } |
| |
| void Components::flushModifications() { |
| rtl::Reference< WriteThread > thread; |
| { |
| osl::MutexGuard g(lock); |
| thread = writeThread_; |
| } |
| if (thread.is()) { |
| thread->flush(); |
| thread->join(); |
| } |
| } |
| |
| void Components::insertExtensionXcsFile( |
| bool shared, rtl::OUString const & fileUri) |
| { |
| try { |
| parseXcsFile(fileUri, shared ? 9 : 13, data_, 0, 0, 0); |
| } catch (css::container::NoSuchElementException & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "insertExtensionXcsFile does not exist: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } |
| |
| void Components::insertExtensionXcuFile( |
| bool shared, rtl::OUString const & fileUri, Modifications * modifications) |
| { |
| OSL_ASSERT(modifications != 0); |
| int layer = shared ? 10 : 14; |
| Additions * adds = data_.addExtensionXcuAdditions(fileUri, layer); |
| try { |
| parseXcuFile(fileUri, layer, data_, 0, modifications, adds); |
| } catch (css::container::NoSuchElementException & e) { |
| data_.removeExtensionXcuAdditions(fileUri); |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "insertExtensionXcuFile does not exist: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } |
| |
| void Components::removeExtensionXcuFile( |
| rtl::OUString const & fileUri, Modifications * modifications) |
| { |
| //TODO: Ideally, exactly the data coming from the specified xcu file would |
| // be removed. However, not enough information is recorded in the in-memory |
| // data structures to do so. So, as a workaround, all those set elements |
| // that were freshly added by the xcu and have afterwards been left |
| // unchanged or have only had their properties changed in the user layer are |
| // removed (and nothing else). The heuristic to determine |
| // whether a node has been left unchanged is to check the layer ID (as |
| // usual) and additionally to check that the node does not recursively |
| // contain any non-empty sets (multiple extension xcu files are merged into |
| // one layer, so checking layer ID alone is not enough). Since |
| // item->additions records all additions of set members in textual order, |
| // the latter check works well when iterating through item->additions in |
| // reverse order. |
| OSL_ASSERT(modifications != 0); |
| rtl::Reference< Data::ExtensionXcu > item( |
| data_.removeExtensionXcuAdditions(fileUri)); |
| if (item.is()) { |
| for (Additions::reverse_iterator i(item->additions.rbegin()); |
| i != item->additions.rend(); ++i) |
| { |
| rtl::Reference< Node > parent; |
| NodeMap const * map = &data_.components; |
| rtl::Reference< Node > node; |
| for (Path::const_iterator j(i->begin()); j != i->end(); ++j) { |
| parent = node; |
| node = Data::findNode(Data::NO_LAYER, *map, *j); |
| if (!node.is()) { |
| break; |
| } |
| map = &node->getMembers(); |
| } |
| if (node.is()) { |
| OSL_ASSERT(parent.is()); |
| if (parent->kind() == Node::KIND_SET) { |
| OSL_ASSERT( |
| node->kind() == Node::KIND_GROUP || |
| node->kind() == Node::KIND_SET); |
| if (canRemoveFromLayer(item->layer, node)) { |
| parent->getMembers().erase(i->back()); |
| data_.modifications.remove(*i); |
| modifications->add(*i); |
| } |
| } |
| } |
| } |
| writeModifications(); |
| } |
| } |
| |
| void Components::insertModificationXcuFile( |
| rtl::OUString const & fileUri, |
| std::set< rtl::OUString > const & includedPaths, |
| std::set< rtl::OUString > const & excludedPaths, |
| Modifications * modifications) |
| { |
| OSL_ASSERT(modifications != 0); |
| Partial part(includedPaths, excludedPaths); |
| try { |
| parseFileLeniently( |
| &parseXcuFile, fileUri, Data::NO_LAYER, data_, &part, modifications, |
| 0); |
| } catch (css::container::NoSuchElementException & e) { |
| OSL_TRACE( |
| "configmgr error inserting non-existing %s: %s", |
| rtl::OUStringToOString(fileUri, RTL_TEXTENCODING_UTF8).getStr(), |
| rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); |
| } |
| } |
| |
| css::beans::Optional< css::uno::Any > Components::getExternalValue( |
| rtl::OUString const & descriptor) |
| { |
| sal_Int32 i = descriptor.indexOf(' '); |
| if (i <= 0) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("bad external value descriptor ")) + |
| descriptor), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| //TODO: Do not make calls with mutex locked: |
| rtl::OUString name(descriptor.copy(0, i)); |
| ExternalServices::iterator j(externalServices_.find(name)); |
| if (j == externalServices_.end()) { |
| css::uno::Reference< css::uno::XInterface > service; |
| try { |
| service = css::uno::Reference< css::lang::XMultiComponentFactory >( |
| context_->getServiceManager(), css::uno::UNO_SET_THROW)-> |
| createInstanceWithContext(name, context_); |
| } catch (css::uno::RuntimeException &) { |
| // Assuming these exceptions are real errors: |
| throw; |
| } catch (css::uno::Exception & e) { |
| // Assuming these exceptions indicate that the service is not |
| // installed: |
| OSL_TRACE( |
| "createInstance(%s) failed with %s", |
| rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr(), |
| rtl::OUStringToOString( |
| e.Message, RTL_TEXTENCODING_UTF8).getStr()); |
| } |
| css::uno::Reference< css::beans::XPropertySet > propset; |
| if (service.is()) { |
| propset = css::uno::Reference< css::beans::XPropertySet >( |
| service, css::uno::UNO_QUERY_THROW); |
| } |
| j = externalServices_.insert( |
| ExternalServices::value_type(name, propset)).first; |
| } |
| css::beans::Optional< css::uno::Any > value; |
| if (j->second.is()) { |
| try { |
| if (!(j->second->getPropertyValue(descriptor.copy(i + 1)) >>= |
| value)) |
| { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "cannot obtain external value through ")) + |
| descriptor), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } catch (css::beans::UnknownPropertyException & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "unknwon external value descriptor ID: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } catch (css::lang::WrappedTargetException & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "cannot obtain external value: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } |
| return value; |
| } |
| |
| Components::Components( |
| css::uno::Reference< css::uno::XComponentContext > const & context): |
| context_(context) |
| { |
| OSL_ASSERT(context.is()); |
| RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "begin parsing"); |
| parseXcsXcuLayer( |
| 0, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry")))); |
| parseModuleLayer( |
| 2, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "$OOO_BASE_DIR/share/registry/modules")))); |
| parseResLayer( |
| 3, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/share/registry")))); |
| parseXcsXcuIniLayer( |
| 7, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") |
| ":BUNDLED_EXTENSIONS_USER}/registry/" |
| "com.sun.star.comp.deployment.configuration." |
| "PackageRegistryBackend/configmgr.ini"))), |
| false); |
| parseXcsXcuIniLayer( |
| 9, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") |
| ":SHARED_EXTENSIONS_USER}/registry/" |
| "com.sun.star.comp.deployment.configuration." |
| "PackageRegistryBackend/configmgr.ini"))), |
| true); |
| parseXcsXcuLayer( |
| 11, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") |
| ":UNO_USER_PACKAGES_CACHE}/registry/" |
| "com.sun.star.comp.deployment.configuration." |
| "PackageRegistryBackend/registry")))); |
| // can be dropped once old UserInstallation format can no longer exist |
| // (probably OOo 4) |
| parseXcsXcuIniLayer( |
| 13, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("uno") |
| ":UNO_USER_PACKAGES_CACHE}/registry/" |
| "com.sun.star.comp.deployment.configuration." |
| "PackageRegistryBackend/configmgr.ini"))), |
| true); |
| parseModificationLayer(); |
| RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "end parsing"); |
| } |
| |
| Components::~Components() {} |
| |
| void Components::parseFileLeniently( |
| FileParser * parseFile, rtl::OUString const & url, int layer, Data & data, |
| Partial const * partial, Modifications * modifications, |
| Additions * additions) |
| { |
| OSL_ASSERT(parseFile != 0); |
| try { |
| (*parseFile)(url, layer, data, partial, modifications, additions); |
| } catch (css::container::NoSuchElementException &) { |
| throw; |
| } catch (css::uno::Exception & e) { //TODO: more specific exception catching |
| // Silently ignore invalid XML files, instead of completely preventing |
| // OOo from starting: |
| OSL_TRACE( |
| "configmgr error reading %s: %s", |
| rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8).getStr(), |
| rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); |
| } |
| } |
| |
| void Components::parseFiles( |
| int layer, rtl::OUString const & extension, FileParser * parseFile, |
| rtl::OUString const & url, bool recursive) |
| { |
| osl::Directory dir(url); |
| switch (dir.open()) { |
| case osl::FileBase::E_None: |
| break; |
| case osl::FileBase::E_NOENT: |
| if (!recursive) { |
| return; |
| } |
| // fall through |
| default: |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| for (;;) { |
| osl::DirectoryItem i; |
| osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); |
| if (rc == osl::FileBase::E_NOENT) { |
| break; |
| } |
| if (rc != osl::FileBase::E_None) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| osl::FileStatus stat( |
| FileStatusMask_Type | FileStatusMask_FileName | |
| FileStatusMask_FileURL); |
| if (i.getFileStatus(stat) != osl::FileBase::E_None) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| if (stat.getFileType() == osl::FileStatus::Directory) { //TODO: symlinks |
| parseFiles(layer, extension, parseFile, stat.getFileURL(), true); |
| } else { |
| rtl::OUString file(stat.getFileName()); |
| if (file.getLength() >= extension.getLength() && |
| file.match(extension, file.getLength() - extension.getLength())) |
| { |
| try { |
| parseFileLeniently( |
| parseFile, stat.getFileURL(), layer, data_, 0, 0, 0); |
| } catch (css::container::NoSuchElementException & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "stat'ed file does not exist: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } |
| } |
| } |
| } |
| |
| void Components::parseFileList( |
| int layer, FileParser * parseFile, rtl::OUString const & urls, |
| rtl::Bootstrap const & ini, bool recordAdditions) |
| { |
| for (sal_Int32 i = 0;;) { |
| rtl::OUString url(urls.getToken(0, ' ', i)); |
| if (url.getLength() != 0) { |
| ini.expandMacrosFrom(url); //TODO: detect failure |
| Additions * adds = 0; |
| if (recordAdditions) { |
| adds = data_.addExtensionXcuAdditions(url, layer); |
| } |
| try { |
| parseFileLeniently(parseFile, url, layer, data_, 0, 0, adds); |
| } catch (css::container::NoSuchElementException & e) { |
| OSL_TRACE( |
| "configmgr file does not exist: %s", |
| rtl::OUStringToOString( |
| e.Message, RTL_TEXTENCODING_UTF8).getStr()); |
| if (adds != 0) { |
| data_.removeExtensionXcuAdditions(url); |
| } |
| } |
| } |
| if (i == -1) { |
| break; |
| } |
| } |
| } |
| |
| void Components::parseXcdFiles(int layer, rtl::OUString const & url) { |
| osl::Directory dir(url); |
| switch (dir.open()) { |
| case osl::FileBase::E_None: |
| break; |
| case osl::FileBase::E_NOENT: |
| return; |
| default: |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot open directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| UnresolvedList unres; |
| XcdParser::Dependencies deps; |
| for (;;) { |
| osl::DirectoryItem i; |
| osl::FileBase::RC rc = dir.getNextItem(i, SAL_MAX_UINT32); |
| if (rc == osl::FileBase::E_NOENT) { |
| break; |
| } |
| if (rc != osl::FileBase::E_None) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot iterate directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| osl::FileStatus stat( |
| FileStatusMask_Type | FileStatusMask_FileName | |
| FileStatusMask_FileURL); |
| if (i.getFileStatus(stat) != osl::FileBase::E_None) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("cannot stat in directory ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks |
| rtl::OUString file(stat.getFileName()); |
| if (file.getLength() >= RTL_CONSTASCII_LENGTH(".xcd") && |
| file.matchAsciiL( |
| RTL_CONSTASCII_STRINGPARAM(".xcd"), |
| file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))) |
| { |
| rtl::OUString name( |
| file.copy( |
| 0, file.getLength() - RTL_CONSTASCII_LENGTH(".xcd"))); |
| rtl::Reference< ParseManager > manager; |
| try { |
| manager = new ParseManager( |
| stat.getFileURL(), new XcdParser(layer, deps, data_)); |
| } catch (css::container::NoSuchElementException & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "stat'ed file does not exist: ")) + |
| e.Message), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| if (manager->parse()) { |
| deps.insert(name); |
| } else { |
| unres.push_back(UnresolvedListItem(name, manager)); |
| } |
| } |
| } |
| } |
| while (!unres.empty()) { |
| bool resolved = false; |
| for (UnresolvedList::iterator i(unres.begin()); i != unres.end();) { |
| if (i->manager->parse()) { |
| deps.insert(i->name); |
| unres.erase(i++); |
| resolved = true; |
| } else { |
| ++i; |
| } |
| } |
| if (!resolved) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "xcd: unresolved dependencies in ")) + |
| url), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| } |
| } |
| |
| void Components::parseXcsXcuLayer(int layer, rtl::OUString const & url) { |
| parseXcdFiles(layer, url); |
| parseFiles( |
| layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcs")), |
| &parseXcsFile, |
| url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/schema")), false); |
| parseFiles( |
| layer + 1, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), |
| &parseXcuFile, |
| url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/data")), false); |
| } |
| |
| void Components::parseXcsXcuIniLayer( |
| int layer, rtl::OUString const & url, bool recordAdditions) |
| { |
| //TODO: rtl::Bootstrap::getFrom "first trie[s] to retrieve the value via the |
| // global function" |
| rtl::Bootstrap ini(url); |
| rtl::OUString urls; |
| if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("SCHEMA")), urls)) |
| { |
| parseFileList(layer, &parseXcsFile, urls, ini, false); |
| } |
| if (ini.getFrom(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DATA")), urls)) |
| { |
| parseFileList(layer + 1, &parseXcuFile, urls, ini, recordAdditions); |
| } |
| } |
| |
| void Components::parseModuleLayer(int layer, rtl::OUString const & url) { |
| parseFiles( |
| layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), |
| &parseXcuFile, url, false); |
| } |
| |
| void Components::parseResLayer(int layer, rtl::OUString const & url) { |
| rtl::OUString resUrl( |
| url + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/res"))); |
| parseXcdFiles(layer, resUrl); |
| parseFiles( |
| layer, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), |
| &parseXcuFile, resUrl, false); |
| } |
| |
| rtl::OUString Components::getModificationFileUrl() const { |
| return expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") |
| ":UserInstallation}/user/registrymodifications.xcu"))); |
| } |
| |
| void Components::parseModificationLayer() { |
| try { |
| parseFileLeniently( |
| &parseXcuFile, getModificationFileUrl(), Data::NO_LAYER, data_, 0, |
| 0, 0); |
| } catch (css::container::NoSuchElementException &) { |
| OSL_TRACE( |
| "configmgr user registrymodifications.xcu does not (yet) exist"); |
| // Migrate old user layer data (can be removed once migration is no |
| // longer relevant, probably OOo 4; also see hack for xsi namespace in |
| // xmlreader::XmlReader::registerNamespaceIri): |
| parseFiles( |
| Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")), |
| &parseXcuFile, |
| expand( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap") |
| ":UserInstallation}/user/registry/data"))), |
| false); |
| } |
| } |
| |
| } |