768 lines
28 KiB
C++
768 lines
28 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
#include "precompiled_configmgr.hxx"
|
|
#include "sal/config.h"
|
|
|
|
#include <algorithm>
|
|
#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/diagnose.h"
|
|
#include "osl/file.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 "additions.hxx"
|
|
#include "components.hxx"
|
|
#include "data.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;
|
|
|
|
}
|
|
|
|
void Components::initSingleton(
|
|
css::uno::Reference< css::uno::XComponentContext > const & context)
|
|
{
|
|
OSL_ASSERT(context.is());
|
|
if (!singletonCreated) {
|
|
singletonCreated = true;
|
|
static Components theSingleton(context);
|
|
singleton = &theSingleton;
|
|
}
|
|
}
|
|
|
|
Components & Components::getSingleton() {
|
|
OSL_ASSERT(singletonCreated);
|
|
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() {
|
|
writeModFile(*this, getModificationFileUrl(), data_);
|
|
}
|
|
|
|
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);
|
|
try {
|
|
Partial part(includedPaths, excludedPaths);
|
|
parseXcuFile(fileUri, Data::NO_LAYER, data_, &part, modifications, 0);
|
|
} catch (css::uno::Exception & e) { //TODO: more specific exception catching
|
|
OSL_TRACE(
|
|
"configmgr error inserting %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"))));
|
|
parseXcsXcuLayer(
|
|
4,
|
|
expand(
|
|
rtl::OUString(
|
|
RTL_CONSTASCII_USTRINGPARAM(
|
|
"$BRAND_BASE_DIR/share/registry"))));
|
|
parseModuleLayer(
|
|
6,
|
|
expand(
|
|
rtl::OUString(
|
|
RTL_CONSTASCII_USTRINGPARAM(
|
|
"$BRAND_BASE_DIR/share/registry/modules"))));
|
|
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);
|
|
try {
|
|
parseModificationLayer();
|
|
} catch (css::uno::Exception & e) { //TODO: more specific exception catching
|
|
// Silently ignore unreadable parts of a corrupted user modification
|
|
// layer, instead of completely preventing OOo from starting:
|
|
OSL_TRACE(
|
|
"configmgr error reading user modification layer: %s",
|
|
rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
|
|
}
|
|
RTL_LOGFILE_TRACE_AUTHOR("configmgr", "sb", "end parsing");
|
|
}
|
|
|
|
Components::~Components() {}
|
|
|
|
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 {
|
|
(*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 {
|
|
(*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(
|
|
"${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
|
|
":UserInstallation}/user/registrymodifications.xcu")));
|
|
}
|
|
|
|
void Components::parseModificationLayer() {
|
|
try {
|
|
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 constructor):
|
|
parseFiles(
|
|
Data::NO_LAYER, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".xcu")),
|
|
&parseXcuFile,
|
|
expand(
|
|
rtl::OUString(
|
|
RTL_CONSTASCII_USTRINGPARAM(
|
|
"${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE("bootstrap")
|
|
":UserInstallation}/user/registry/data"))),
|
|
false);
|
|
}
|
|
}
|
|
|
|
}
|