diff options
-rw-r--r-- | RepositoryExternal.mk | 5 | ||||
-rw-r--r-- | config_host.mk.in | 3 | ||||
-rw-r--r-- | config_host/config_dconf.h.in | 17 | ||||
-rw-r--r-- | configmgr/CppunitTest_configmgr_unit.mk | 1 | ||||
-rw-r--r-- | configmgr/Library_configmgr.mk | 8 | ||||
-rw-r--r-- | configmgr/source/components.cxx | 14 | ||||
-rw-r--r-- | configmgr/source/readdconflayer.cxx | 931 | ||||
-rw-r--r-- | configmgr/source/readdconflayer.hxx | 25 | ||||
-rw-r--r-- | configure.ac | 29 | ||||
-rw-r--r-- | distro-configs/LibreOfficeLinux.conf | 1 | ||||
-rw-r--r-- | include/sal/log-areas.dox | 1 | ||||
-rw-r--r-- | instsetoo_native/CustomTarget_setup.mk | 2 | ||||
-rw-r--r-- | scp2/source/ooo/common_brand.scp | 19 |
13 files changed, 1048 insertions, 8 deletions
diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index a0a0d611413b..75f033f4a193 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -3584,6 +3584,11 @@ endif # ENABLE_COLLADA endif # ENABLE_GLTF +define gb_LinkTarget__use_dconf +$(call gb_LinkTarget_add_defs,$(1),$(DCONF_CFLAGS)) +$(call gb_LinkTarget_add_libs,$(1),$(DCONF_LIBS)) +endef + ### Jars ############################################################ ifneq ($(SYSTEM_HSQLDB),) diff --git a/config_host.mk.in b/config_host.mk.in index 1d0702b4f728..2a20b8bfdd51 100644 --- a/config_host.mk.in +++ b/config_host.mk.in @@ -91,6 +91,8 @@ export DBUSMENUGTK_CFLAGS=$(gb_SPACE)@DBUSMENUGTK_CFLAGS@ export DBUSMENUGTK_LIBS=$(gb_SPACE)@DBUSMENUGTK_LIBS@ export DBUS_CFLAGS=$(gb_SPACE)@DBUS_CFLAGS@ export DBUS_LIBS=$(gb_SPACE)@DBUS_LIBS@ +export DCONF_CFLAGS=@DCONF_CFLAGS@ +export DCONF_LIBS=@DCONF_LIBS@ export DEFAULT_BRAND_IMAGES=@DEFAULT_BRAND_IMAGES@ export DIAGRAM_EXTENSION_PACK=@DIAGRAM_EXTENSION_PACK@ export DICT_SYSTEM_DIR=@DICT_SYSTEM_DIR@ @@ -122,6 +124,7 @@ export ENABLE_CUPS=@ENABLE_CUPS@ export ENABLE_CURL=@ENABLE_CURL@ export ENABLE_DBGUTIL=@ENABLE_DBGUTIL@ export ENABLE_DBUS=@ENABLE_DBUS@ +export ENABLE_DCONF=@ENABLE_DCONF@ export ENABLE_DEBUG=@ENABLE_DEBUG@ export ENABLE_DEBUGINFO_FOR=@ENABLE_DEBUGINFO_FOR@ export ENABLE_DIRECTX=@ENABLE_DIRECTX@ diff --git a/config_host/config_dconf.h.in b/config_host/config_dconf.h.in new file mode 100644 index 000000000000..09608c4299aa --- /dev/null +++ b/config_host/config_dconf.h.in @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_CONFIG_DCONF_H +#define INCLUDED_CONFIG_DCONF_H + +#define ENABLE_DCONF 0 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/configmgr/CppunitTest_configmgr_unit.mk b/configmgr/CppunitTest_configmgr_unit.mk index 1672c9f42556..e8bddc24bee8 100644 --- a/configmgr/CppunitTest_configmgr_unit.mk +++ b/configmgr/CppunitTest_configmgr_unit.mk @@ -49,5 +49,6 @@ $(eval $(call gb_CppunitTest_use_components,configmgr_unit,\ $(eval $(call gb_CppunitTest_use_externals,configmgr_unit,\ boost_headers \ + dconf \ icu_headers \ )) diff --git a/configmgr/Library_configmgr.mk b/configmgr/Library_configmgr.mk index 528b15091ac2..36c316a6b28e 100644 --- a/configmgr/Library_configmgr.mk +++ b/configmgr/Library_configmgr.mk @@ -38,15 +38,19 @@ $(eval $(call gb_Library_add_exception_objects,configmgr, \ configmgr/source/type \ configmgr/source/update \ configmgr/source/valueparser \ - $(if $(filter $(OS),WNT), configmgr/source/winreg ) \ configmgr/source/writemodfile \ configmgr/source/xcdparser \ configmgr/source/xcsparser \ configmgr/source/xcuparser \ configmgr/source/xmldata \ + $(if $(ENABLE_DCONF),configmgr/source/readdconflayer) \ + $(if $(filter $(OS),WNT),configmgr/source/winreg) \ )) -$(eval $(call gb_Library_use_external,configmgr,boost_headers)) +$(eval $(call gb_Library_use_externals,configmgr, \ + boost_headers \ + dconf \ +)) $(eval $(call gb_Library_use_sdk_api,configmgr)) diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx index dc0c4be5a4e7..4b1eaeabfeaf 100644 --- a/configmgr/source/components.cxx +++ b/configmgr/source/components.cxx @@ -36,6 +36,7 @@ #include <com/sun/star/uno/RuntimeException.hpp> #include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/uno/XInterface.hpp> +#include <config_dconf.h> #include <config_folders.h> #include <osl/conditn.hxx> #include <osl/file.hxx> @@ -64,6 +65,10 @@ #include "xcuparser.hxx" #include "xcsparser.hxx" +#if ENABLE_DCONF +#include <readdconflayer.hxx> +#endif + #if defined WNT #include "winreg.hxx" #endif @@ -522,6 +527,15 @@ Components::Components( parseResLayer(layer, url); SAL_INFO("configmgr", "parseResLayer() took " << (osl_getGlobalTimer() - nStartTime) << " ms"); ++layer; //TODO: overflow +#if ENABLE_DCONF + } else if (type == "dconf") { + if (!url.isEmpty()) { + throw css::uno::RuntimeException( + "CONFIGURATION_LAYERS: non-empty \"dconf\" URL"); + } + readDconfLayer(data_, layer); + ++layer; //TODO: overflow +#endif #if defined WNT } else if (type == "winreg") { if (!url.isEmpty()) { diff --git a/configmgr/source/readdconflayer.cxx b/configmgr/source/readdconflayer.cxx new file mode 100644 index 000000000000..62e6a65912a6 --- /dev/null +++ b/configmgr/source/readdconflayer.cxx @@ -0,0 +1,931 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <cassert> +#include <cstddef> +#include <cstring> +#include <limits> +#include <type_traits> + +#include <dconf/dconf.h> + +#include <com/sun/star/uno/Sequence.hxx> + +#include <data.hxx> +#include <groupnode.hxx> +#include <localizedpropertynode.hxx> +#include <localizedvaluenode.hxx> +#include <nodemap.hxx> +#include <propertynode.hxx> +#include <readdconflayer.hxx> +#include <setnode.hxx> + +// component-data is encoded in dconf as follows: +// +// * The node hierarchy (starting at component nodes with names like +// "org.openoffice.Setup") maps to dconf paths underneath +// "/org/libreoffice/registry/". +// +// * Component, group, set, and localized property nodes map to dconf dirs +// (except for removal of set elements, see below), while property and +// localized value nodes map to dconf keys. +// +// * The names of nodes that are not set elements are used directly as dconf +// path segments. (The syntax for node names is any non-empty sequences of +// any Unicode scalar values except U+0000--0008, U+000B--000C, U+000E--001F, +// U+002F SOLIDUS, and U+FFFE--FFFF. TODO: "<aruiz> sberg, in general I think +// it'd be nice if you used path separators instead of dots though, they have +// meaning in dconf/gvdb world :-)"?) +// +// * Set element "fuse" and "replace" operations are encoded as dconf path +// segments as concatenations +// +// N ; T ; O +// +// where ";" represents U+003B SEMICOLON; N is an encoding of the node name, +// where each occurrence of U+003B SEMICOLON is replaced by the three +// characters "\3B" and each ocurrence of U+005C REVERSE SOLIDUS is replaced +// by the three characters "\5C"; T is an encoding of the full template name, +// where each occurrence of U+002F SOLIDUS is replaced by the three characters +// "\2F", each occurrence of U+003B SEMICOLON is replaced by the three +// characters "\3B", and each ocurrence of U+005C REVERSE SOLIDUS is replaced +// by the three characters "\5C"; and O is "fuse" or "replace", respectively. +// +// * Set element and property "remove" operations are encoded as dconf key path +// segments directly using the node name, and the associated value being a +// GVariant of empty tuple type. +// +// * Property and localized property value "fuse" operations map to GVariant +// instances as follows: +// +// ** Non-nillable boolean values map to GVariant boolean instances. +// +// ** Non-nillable short values map to GVariant int16 instances. +// +// ** Non-nillable int values map to GVariant int32 instances. +// +// ** Non-nillable long values map to GVariant int64 instances. +// +// ** Non-nillable double values map to GVariant double instances. +// +// ** Non-nillable string values map to GVariant string instances, with the +// following encoding: each occurrence of U+0000 NULL is replace by the three +// characters "\00" and each occurrence of U+005C REVERSE SOLIDUS is replaced +// by the three characters "\5C". +// +// ** Non-nillable hexbinary values map to GVariant byte array instances. +// +// ** Non-nillable list values recursively map to GVariant array instances. +// +// ** Nillable values recursively map to GVariant maybe instances. +// +// TODO: support "finalized", "mandatory", and "external"? + +namespace configmgr { + +namespace { + +template<typename T> class GObjectHolder { +public: + explicit GObjectHolder(T * object): object_(object) {} + + ~GObjectHolder() { + if (object_ != nullptr) { + g_object_unref(object_); + } + } + + T * get() const { return object_; } + +private: + GObjectHolder(GObjectHolder &) = delete; + void operator =(GObjectHolder) = delete; + + T * object_; +}; + +class GVariantHolder { +public: + explicit GVariantHolder(GVariant * variant): variant_(variant) {} + + ~GVariantHolder() { unref(); } + + void reset(GVariant * variant) { + unref(); + variant_ = variant; + } + + GVariant * get() const { return variant_; } + +private: + GVariantHolder(GVariantHolder &) = delete; + void operator =(GVariantHolder) = delete; + + void unref() { + if (variant_ != nullptr) { + g_variant_unref(variant_); + } + } + + GVariant * variant_; +}; + +class StringArrayHolder { +public: + explicit StringArrayHolder(gchar ** array): array_(array) {} + + ~StringArrayHolder() { g_strfreev(array_); } + + gchar ** get() const { return array_; } + +private: + StringArrayHolder(StringArrayHolder &) = delete; + void operator =(StringArrayHolder) = delete; + + gchar ** array_; +}; + +bool decode(OUString * string, bool nul, bool slash, bool semicolon) { + for (sal_Int32 i = 0;; ++i) { + i = string->indexOf('\\', i); + if (i == -1) { + return true; + } + if (nul && string->match("00", i + 1)) { + *string = string->replaceAt(i, 3, OUString(sal_Unicode(0))); + } else if (slash && string->match("2F", i + 1)) { + *string = string->replaceAt(i, 3, "/"); + } else if (semicolon && string->match("3B", i + 1)) { + *string = string->replaceAt(i, 3, ";"); + } else if (string->match("5C", i + 1)) { + *string = string->replaceAt(i + 1, 2, ""); + } else { + SAL_WARN("configmgr.dconf", "bad escape in " << *string); + return false; + } + } +} + +bool getBoolean( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_BOOLEAN)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match boolean property"); + return false; + } + *value <<= bool(g_variant_get_boolean(variant.get())); + return true; +} + +bool getShort( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT16)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match short property"); + return false; + } + *value <<= sal_Int16(g_variant_get_int16(variant.get())); + return true; +} + +bool getInt( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT32)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match int property"); + return false; + } + *value <<= sal_Int32(g_variant_get_int32(variant.get())); + return true; +} + +bool getLong( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT64)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match long property"); + return false; + } + *value <<= sal_Int64(g_variant_get_int64(variant.get())); + return true; +} + +bool getDouble( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_DOUBLE)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match double property"); + return false; + } + *value <<= double(g_variant_get_double(variant.get())); + return true; +} + +bool getStringValue( + OString const & key, GVariantHolder const & variant, OUString * value) +{ + assert(value != nullptr); + if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_STRING)) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match string property"); + return false; + } + gsize n; + char const * p = g_variant_get_string(variant.get(), &n); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long string value for key " << key); + return false; + } + if (!rtl_convertStringToUString( + &value->pData, p, static_cast<sal_Int32>(n), RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + SAL_WARN("configmgr.dconf", "non--UTF-8 string value for key " << key); + return false; + } + return decode(value, true, false, false); +} + +bool getString( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + OUString v; + if (!getStringValue(key, variant, &v)) { + return false; + } + *value <<= v; + return true; +} + +bool getHexbinaryValue( + OString const & key, GVariantHolder const & variant, + css::uno::Sequence<sal_Int8> * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "ay") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match hexbinary property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (guchar)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long hexbinary value for key " << key); + return false; + } + value->realloc(static_cast<sal_Int32>(n)); + static_assert(sizeof (sal_Int8) == sizeof (guchar), "size mismatch"); + std::memcpy(value->getArray(), p, n * sizeof (guchar)); + // assuming that n * sizeof (guchar) is small enough for std::size_t + return true; +} + +bool getHexbinary( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + css::uno::Sequence<sal_Int8> v; + if (!getHexbinaryValue(key, variant, &v)) { + return false; + } + *value <<= v; + return true; +} + +bool getBooleanList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "ab") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match boolean list property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (guchar)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long boolean list for key " << key); + return false; + } + css::uno::Sequence<sal_Bool> v(static_cast<sal_Int32>(n)); + static_assert(sizeof (sal_Bool) == sizeof (guchar), "size mismatch"); + std::memcpy(v.getArray(), p, n * sizeof (guchar)); + // assuming that n * sizeof (guchar) is small enough for std::size_t + *value <<= v; + return true; +} + +bool getShortList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "an") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match short list property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (gint16)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long short list for key " << key); + return false; + } + css::uno::Sequence<sal_Int16> v(static_cast<sal_Int32>(n)); + static_assert(sizeof (sal_Int16) == sizeof (gint16), "size mismatch"); + std::memcpy(v.getArray(), p, n * sizeof (gint16)); + // assuming that n * sizeof (gint16) is small enough for std::size_t + *value <<= v; + return true; +} + +bool getIntList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "ai") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match int list property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (gint32)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long int list for key " << key); + return false; + } + css::uno::Sequence<sal_Int32> v(static_cast<sal_Int32>(n)); + static_assert(sizeof (sal_Int32) == sizeof (gint32), "size mismatch"); + std::memcpy(v.getArray(), p, n * sizeof (gint32)); + // assuming that n * sizeof (gint32) is small enough for std::size_t + *value <<= v; + return true; +} + +bool getLongList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "ax") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match long list property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (gint64)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long long list for key " << key); + return false; + } + css::uno::Sequence<sal_Int64> v(static_cast<sal_Int32>(n)); + static_assert(sizeof (sal_Int64) == sizeof (gint64), "size mismatch"); + std::memcpy(v.getArray(), p, n * sizeof (gint64)); + // assuming that n * sizeof (gint64) is small enough for std::size_t + *value <<= v; + return true; +} + +bool getDoubleList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "ad") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match double list property"); + return false; + } + gsize n; + gconstpointer p = g_variant_get_fixed_array( + variant.get(), &n, sizeof (gdouble)); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long double list for key " << key); + return false; + } + css::uno::Sequence<double> v(static_cast<sal_Int32>(n)); + static_assert(std::is_same<double, gdouble>::value, "type mismatch"); + std::memcpy(v.getArray(), p, n * sizeof (gdouble)); + // assuming that n * sizeof (gdouble) is small enough for std::size_t + *value <<= v; + return true; +} + +bool getStringList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "as") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match string list property"); + return false; + } + gsize n = g_variant_n_children(variant.get()); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long string list for key " << key); + return false; + } + css::uno::Sequence<OUString> v(static_cast<sal_Int32>(n)); + for (gsize i = 0; i != n; ++i) { + GVariantHolder c(g_variant_get_child_value(variant.get(), i)); + if (!getStringValue(key, c, v.getArray() + i)) { + return false; + } + } + *value <<= v; + return true; +} + +bool getHexbinaryList( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + assert(value != nullptr); + if (std::strcmp(g_variant_get_type_string(variant.get()), "aay") != 0) { + SAL_WARN( + "configmgr.dconf", + "bad key " << key << " does not match hexbinary list property"); + return false; + } + gsize n = g_variant_n_children(variant.get()); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long hexbinary list for key " << key); + return false; + } + css::uno::Sequence<css::uno::Sequence<sal_Int8>> v( + static_cast<sal_Int32>(n)); + for (gsize i = 0; i != n; ++i) { + GVariantHolder c(g_variant_get_child_value(variant.get(), i)); + if (!getHexbinaryValue(key, c, v.getArray() + i)) { + return false; + } + } + *value <<= v; + return true; +} + +bool getAny( + OString const & key, GVariantHolder const & variant, css::uno::Any * value) +{ + char const * t = g_variant_get_type_string(variant.get()); + if (std::strcmp(t, "b") == 0) { + return getBoolean(key, variant, value); + } + if (std::strcmp(t, "n") == 0) { + return getShort(key, variant, value); + } + if (std::strcmp(t, "i") == 0) { + return getInt(key, variant, value); + } + if (std::strcmp(t, "x") == 0) { + return getLong(key, variant, value); + } + if (std::strcmp(t, "d") == 0) { + return getDouble(key, variant, value); + } + if (std::strcmp(t, "s") == 0) { + return getString(key, variant, value); + } + if (std::strcmp(t, "ay") == 0) { + return getHexbinary(key, variant, value); + } + if (std::strcmp(t, "ab") == 0) { + return getBooleanList(key, variant, value); + } + if (std::strcmp(t, "an") == 0) { + return getShortList(key, variant, value); + } + if (std::strcmp(t, "ai") == 0) { + return getIntList(key, variant, value); + } + if (std::strcmp(t, "ax") == 0) { + return getLongList(key, variant, value); + } + if (std::strcmp(t, "ad") == 0) { + return getDoubleList(key, variant, value); + } + if (std::strcmp(t, "as") == 0) { + return getStringList(key, variant, value); + } + if (std::strcmp(t, "aay") == 0) { + return getHexbinaryList(key, variant, value); + } + SAL_WARN( + "configmgr.dconf", "bad key " << key << " does not match any property"); + return false; +} + +enum class ReadValue { Error, Value, Remove }; + +ReadValue readValue( + GObjectHolder<DConfClient> const & client, OString const & path, Type type, + bool nillable, bool removable, css::uno::Any * value) +{ + assert(value != nullptr); + assert(!value->hasValue()); + assert(!path.endsWith("/")); + GVariantHolder v(dconf_client_read(client.get(), path.getStr())); + if (v.get() == nullptr) { + SAL_WARN("configmgr.dconf", "cannot read key " << path); + return ReadValue::Error; + } + if (removable && std::strcmp(g_variant_get_type_string(v.get()), "()") == 0) + { + return ReadValue::Remove; + } + bool nil; + if (nillable) { + if (g_variant_classify(v.get()) != G_VARIANT_CLASS_MAYBE) { + SAL_WARN( + "configmgr.dconf", + "bad key " << path << " does not match nillable property"); + } + v.reset(g_variant_get_maybe(v.get())); + nil = v.get() == nullptr; + } else { + nil = false; + } + if (!nil) { + switch (type) { + case TYPE_ANY: + if (!getAny(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_BOOLEAN: + if (!getBoolean(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_SHORT: + if (!getShort(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_INT: + if (!getInt(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_LONG: + if (!getLong(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_DOUBLE: + if (!getDouble(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_STRING: + if (!getString(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_HEXBINARY: + if (!getHexbinary(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_BOOLEAN_LIST: + if (!getBooleanList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_SHORT_LIST: + if (!getShortList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_INT_LIST: + if (!getIntList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_LONG_LIST: + if (!getLongList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_DOUBLE_LIST: + if (!getDoubleList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_STRING_LIST: + if (!getStringList(path, v, value)) { + return ReadValue::Error; + } + break; + case TYPE_HEXBINARY_LIST: + if (!getHexbinaryList(path, v, value)) { + return ReadValue::Error; + } + break; + default: + assert(false); // cannot happen + } + } + return ReadValue::Value; +} + +void readDir( + Data & data, int layer, rtl::Reference<Node> const & node, + NodeMap & members, GObjectHolder<DConfClient> const & client, + OString const & dir) +{ + StringArrayHolder a(dconf_client_list(client.get(), dir.getStr(), nullptr)); + for (char const * const * p = a.get(); *p != nullptr; ++p) { + std::size_t n = std::strlen(*p); + if (n > static_cast<typename std::make_unsigned<sal_Int32>::type>( + std::numeric_limits<sal_Int32>::max())) + { + SAL_WARN("configmgr.dconf", "too long dir/key in dir " << dir); + continue; + } + OString s(*p, static_cast<sal_Int32>(n)); + OString path(dir + s); + OUString seg; + if (!rtl_convertStringToUString( + &seg.pData, s.getStr(), s.getLength(), RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + SAL_WARN("configmgr.dconf", "non--UTF-8 dir/key in dir " << dir); + continue; + } + bool isDir = seg.endsWith("/", &seg); + bool remove; + OUString name; + OUString templ; + bool replace; + if (node.is() && node->kind() == Node::KIND_SET) { + if (isDir) { + remove = false; + sal_Int32 i1 = seg.indexOf(';'); + if (i1 == -1) { + SAL_WARN( + "configmgr.dconf", "bad set element syntax " << path); + continue; + } + name = seg.copy(0, i1); + if (!decode(&name, false, false, true)) { + continue; + } + ++i1; + sal_Int32 i2 = seg.indexOf(';', i1); + if (i2 == -1) { + SAL_WARN( + "configmgr.dconf", "bad set element syntax " << path); + continue; + } + templ = seg.copy(i1, i2 - i1); + if (!decode(&templ, false, true, true)) { + continue; + } + ++i2; + if (rtl_ustr_asciil_reverseCompare_WithLength( + seg.getStr() + i2, seg.getLength() - i2, "fuse", + std::strlen("fuse")) + == 0) + { + replace = false; + } else if (rtl_ustr_asciil_reverseCompare_WithLength( + seg.getStr() + i2, seg.getLength() - i2, + "replace", std::strlen("replace")) + == 0) + { + replace = true; + } else { + SAL_WARN( + "configmgr.dconf", "bad set element syntax " << path); + continue; + } + rtl::Reference<SetNode> set(static_cast<SetNode *>(node.get())); + if (!set->isValidTemplate(templ)) { + SAL_WARN( + "configmgr.dconf", + "bad " << path + << " denotes unsupported set element template"); + continue; + } + } else { + remove = true; + name = seg; + replace = false; + assert(!path.endsWith("/")); + GVariantHolder v( + dconf_client_read(client.get(), path.getStr())); + if (v.get() == nullptr) { + SAL_WARN("configmgr.dconf", "cannot read key " << path); + continue; + } + if (std::strcmp(g_variant_get_type_string(v.get()), "()") != 0) + { + SAL_WARN( + "configmgr.dconf", + "bad " << path + << " does not denote set element removal"); + continue; + } + } + } else { + remove = false; + name = seg; + replace = false; + } + rtl::Reference<Node> member(members.findNode(layer, name)); + bool insert = !member.is(); + if (!remove && (replace || insert)) { + if (!node.is()) { + SAL_WARN("configmgr.dconf", "bad unmatched " << path); + continue; + } + switch (node->kind()) { + case Node::KIND_LOCALIZED_PROPERTY: + member.set(new LocalizedValueNode(layer)); + break; + case Node::KIND_GROUP: + if (!static_cast<GroupNode *>(node.get())->isExtensible()) { + SAL_WARN("configmgr.dconf", "bad unmatched " << path); + continue; + } + member.set( + new PropertyNode( + layer, TYPE_ANY, true, css::uno::Any(), true)); + break; + case Node::KIND_SET: + assert(!templ.isEmpty()); + member = data.getTemplate(layer, templ); + if (!member.is()) { + SAL_WARN( + "configmgr.dconf", + "bad " << path << " denoting undefined template " + << templ); + continue; + } + break; + default: + assert(false); // cannot happen + } + } else if (!(templ.isEmpty() + || (node.is() && templ == node->getTemplateName()))) + { + SAL_WARN( + "configmgr.dconf", + "bad " << path + << " denoting set element of non-matching template " + << node->getTemplateName()); + continue; + } + if (member->getFinalized() < layer) { + continue; + } + switch (member->kind()) { + case Node::KIND_PROPERTY: + { + if (isDir) { + SAL_WARN( + "configmgr.dconf", + "bad dir " << path << " does not match property"); + continue; + } + rtl::Reference<PropertyNode> prop( + static_cast<PropertyNode *>(member.get())); + css::uno::Any value; + switch (readValue( + client, path, prop->getStaticType(), + prop->isNillable(), prop->isExtension(), &value)) + { + case ReadValue::Error: + continue; + case ReadValue::Value: + prop->setValue(layer, value); + break; + case ReadValue::Remove: + remove = true; + break; + } + break; + } + case Node::KIND_LOCALIZED_VALUE: + { + if (isDir) { + SAL_WARN( + "configmgr.dconf", + "bad dir " << path + << " does not match localized value"); + continue; + } + assert( + node.is() && node->kind() == Node::KIND_LOCALIZED_PROPERTY); + rtl::Reference<LocalizedPropertyNode> locProp( + static_cast<LocalizedPropertyNode *>(node.get())); + css::uno::Any value; + if (readValue( + client, path, locProp->getStaticType(), + locProp->isNillable(), false, &value) + == ReadValue::Error) + { + continue; + } + static_cast<LocalizedValueNode *>(member.get())->setValue( + layer, value); + break; + } + case Node::KIND_LOCALIZED_PROPERTY: + case Node::KIND_GROUP: + case Node::KIND_SET: + if (!isDir) { + SAL_WARN( + "configmgr.dconf", + "bad key " << path + << " does not match localized property, group, or set," + " respectively"); + continue; + } + assert(path.endsWith("/")); + readDir(data, layer, member, member->getMembers(), client, path); + break; + default: + assert(false); // cannot happen + } + if (remove) { + if (!member->getMandatory()) { + members.erase(name); + } + } else if (replace) { + members.erase(name); + members.insert(NodeMap::value_type(name, member)); + } else if (insert) { + members.insert(NodeMap::value_type(name, member)); + } + } +} + +} + +void readDconfLayer(Data & data, int layer) { + GObjectHolder<DConfClient> client(dconf_client_new()); + readDir( + data, layer, rtl::Reference<Node>(), data.getComponents(), client, + "/org/libreoffice/registry/"); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/configmgr/source/readdconflayer.hxx b/configmgr/source/readdconflayer.hxx new file mode 100644 index 000000000000..63a4698fbce4 --- /dev/null +++ b/configmgr/source/readdconflayer.hxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_CONFIGMGR_SOURCE_READDCONFLAYER_HXX +#define INCLUDED_CONFIGMGR_SOURCE_READDCONFLAYER_HXX + +#include <sal/config.h> + +namespace configmgr { struct Data; } + +namespace configmgr { + +void readDconfLayer(Data & data, int layer); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/configure.ac b/configure.ac index d061912a6dfe..aaf1d6a6085c 100644 --- a/configure.ac +++ b/configure.ac @@ -1475,6 +1475,11 @@ AC_ARG_ENABLE(collada, AS_HELP_STRING([--disable-collada], [Disable collada support (Rendering 3D models stored in *.dae and *.kmz format).])) +AC_ARG_ENABLE(dconf, + AS_HELP_STRING([--disable-dconf], + [Disable the dconf configuration backend (enabled by default where + available).])) + dnl =================================================================== dnl Optional Packages (--with/without-) dnl =================================================================== @@ -10493,6 +10498,29 @@ AC_SUBST([COLLADA2GLTF_CFLAGS]) AC_SUBST([COLLADA2GLTF_LIBS]) AC_SUBST([SYSTEM_COLLADA2GLTF]) +if test "$enable_dconf" != no; then + PKG_CHECK_MODULES([DCONF], [dconf], [], [ + if test "$enable_dconf" = yes; then + AC_MSG_ERROR([dconf not found]) + else + enable_dconf=no + fi]) +fi +AC_MSG_CHECKING([whether to enable dconf]) +if test "$enable_dconf" = no; then + DCONF_CFLAGS= + DCONF_LIBS= + ENABLE_DCONF= + AC_MSG_RESULT([no]) +else + ENABLE_DCONF=TRUE + AC_DEFINE(ENABLE_DCONF) + AC_MSG_RESULT([yes]) +fi +AC_SUBST([DCONF_CFLAGS]) +AC_SUBST([DCONF_LIBS]) +AC_SUBST([ENABLE_DCONF]) + # pdf import? AC_MSG_CHECKING([whether to build the PDF import feature]) ENABLE_PDFIMPORT= @@ -13112,6 +13140,7 @@ AC_CONFIG_FILES([config_host.mk ios/lo.xcconfig]) AC_CONFIG_HEADERS([config_host/config_buildid.h]) AC_CONFIG_HEADERS([config_host/config_clang.h]) +AC_CONFIG_HEADERS([config_host/config_dconf.h]) AC_CONFIG_HEADERS([config_host/config_eot.h]) AC_CONFIG_HEADERS([config_host/config_extension_update.h]) AC_CONFIG_HEADERS([config_host/config_cairo_canvas.h]) diff --git a/distro-configs/LibreOfficeLinux.conf b/distro-configs/LibreOfficeLinux.conf index 7c21ce777d48..2824fb66df0f 100644 --- a/distro-configs/LibreOfficeLinux.conf +++ b/distro-configs/LibreOfficeLinux.conf @@ -33,6 +33,7 @@ --enable-epm --enable-python=internal --enable-online-update +--disable-dconf --disable-gio --disable-randr-link --disable-kde4 diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox index d734876a8a75..70f3456f262c 100644 --- a/include/sal/log-areas.dox +++ b/include/sal/log-areas.dox @@ -491,6 +491,7 @@ certain functionality. @li @c basebmp @li @c binaryurp @li @c configmgr +@li @c configmgr.dconf @li @c cppcanvas @li @c cppcanvas.emf @li @c drawinglayer diff --git a/instsetoo_native/CustomTarget_setup.mk b/instsetoo_native/CustomTarget_setup.mk index 4217424d4ff3..dd331af9ec30 100644 --- a/instsetoo_native/CustomTarget_setup.mk +++ b/instsetoo_native/CustomTarget_setup.mk @@ -48,7 +48,7 @@ $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_ && echo 'BRAND_BASE_DIR=$${ORIGIN}/..' \ && echo 'BRAND_INI_DIR=$${ORIGIN}' \ && echo 'BRAND_SHARE_SUBDIR=$(LIBO_SHARE_FOLDER)' \ - && echo 'CONFIGURATION_LAYERS=xcsxcu:$${BRAND_BASE_DIR}/$(LIBO_SHARE_FOLDER)/registry res:$${BRAND_BASE_DIR}/$(LIBO_SHARE_FOLDER)/registry $(if $(filter WNT,$(OS)),winreg: )bundledext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini sharedext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini userext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini user:$${$$BRAND_BASE_DIR/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,bootstrap):UserInstallation}/user/registrymodifications.xcu' \ + && echo 'CONFIGURATION_LAYERS=xcsxcu:$${BRAND_BASE_DIR}/$(LIBO_SHARE_FOLDER)/registry res:$${BRAND_BASE_DIR}/$(LIBO_SHARE_FOLDER)/registry $(if $(ENABLE_DCONF),dconf: )$(if $(filter WNT,$(OS)),winreg: )bundledext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini sharedext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini userext:$${$${BRAND_BASE_DIR}/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,louno):UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini user:$${$$BRAND_BASE_DIR/$(LIBO_ETC_FOLDER)/$(call gb_Helper_get_rcfile,bootstrap):UserInstallation}/user/registrymodifications.xcu' \ && echo 'LO_JAVA_DIR=$${BRAND_BASE_DIR}/$(LIBO_SHARE_JAVA_FOLDER)' \ && echo 'LO_LIB_DIR=$${BRAND_BASE_DIR}/$(LIBO_LIB_FOLDER)' \ && echo 'BAK_EXTENSIONS=$${$$ORIGIN/$(call gb_Helper_get_rcfile,louno):TMP_EXTENSIONS}' \ diff --git a/scp2/source/ooo/common_brand.scp b/scp2/source/ooo/common_brand.scp index e79dab7fedb5..6bf7b30b8179 100644 --- a/scp2/source/ooo/common_brand.scp +++ b/scp2/source/ooo/common_brand.scp @@ -29,6 +29,7 @@ #include "AutoInstall/brand" +#include "config_dconf.h" #include "config_folders.h" Module gid_Module_Root_Brand @@ -1117,17 +1118,25 @@ ProfileItem gid_Brand_Profileitem_Fundamental_Ure_Bin_Dir Value = "${BRAND_BASE_DIR}/" LIBO_URE_BIN_FOLDER; End +#if ENABLE_DCONF +#define CONFIGURATION_LAYERS_DCONF " dconf:" +#else +#define CONFIGURATION_LAYERS_DCONF +#endif +#if defined WNT +#define CONFIGURATION_LAYERS_WINREG " winreg:" +#else +#define CONFIGURATION_LAYERS_WINREG +#endif ProfileItem gid_Brand_Profileitem_Fundamental_Configuration_Layers ProfileID = gid_Brand_Profile_Fundamental_Ini; ModuleID = gid_Module_Root_Brand; Section = "Bootstrap"; Key = "CONFIGURATION_LAYERS"; -#if defined WNT - Value = "xcsxcu:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry res:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry winreg: bundledext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini sharedext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini userext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini user:${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" PROFILENAME(bootstrap) ":UserInstallation}/user/registrymodifications.xcu"; -#else - Value = "xcsxcu:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry res:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry bundledext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini sharedext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini userext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini user:${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" PROFILENAME(bootstrap) ":UserInstallation}/user/registrymodifications.xcu"; -#endif + Value = "xcsxcu:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry res:${BRAND_BASE_DIR}/" LIBO_SHARE_FOLDER "/registry" CONFIGURATION_LAYERS_WINREG " bundledext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":BUNDLED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini sharedext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":SHARED_EXTENSIONS_USER}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini userext:${${BRAND_BASE_DIR}/" LIBO_ETC_FOLDER "/" PROFILENAME(louno) ":UNO_USER_PACKAGES_CACHE}/registry/com.sun.star.comp.deployment.configuration.PackageRegistryBackend/configmgr.ini user:${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" PROFILENAME(bootstrap) ":UserInstallation}/user/registrymodifications.xcu"; End +#undef CONFIGURATION_LAYERS_DCONF +#undef CONFIGURATION_LAYERS_WINREG #if !defined MACOSX ProfileItem gid_Brand_Profileitem_Redirect_Ure_Bootstrap |