summaryrefslogtreecommitdiff
path: root/configmgr
diff options
context:
space:
mode:
Diffstat (limited to 'configmgr')
-rw-r--r--configmgr/source/dconf.cxx232
1 files changed, 136 insertions, 96 deletions
diff --git a/configmgr/source/dconf.cxx b/configmgr/source/dconf.cxx
index ca94a9b94f78..331545a8900f 100644
--- a/configmgr/source/dconf.cxx
+++ b/configmgr/source/dconf.cxx
@@ -34,9 +34,8 @@
// "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.
+// * Component, group, set, and localized property nodes map to dconf dirs,
+// 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
@@ -45,31 +44,30 @@
// 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
+// * The names of set element nodes are encoded as dconf path segments as
+// follows: each occurrence of U+0000 NULL is replace by the three characters
+// "\00", each occurrence of U+002F SOLIDUS is replaced by the three
+// characters "\2F", and each ocurrence of U+005C REVERSE SOLIDUS is replaced
+// by the three characters "\5C".
//
-// N ; T ; O
+// * Set elements (which must themselves be either sets or groups) map to
+// "indirection" dconf dirs as follows:
//
-// where ";" represents U+003B SEMICOLON; N is an encoding of the node name,
-// where each occurrence of U+0000 NULL is replace by the three characters
-// "\00", 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"; 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.
+// ** The dir must contain a key named "op" of string type, with a value of
+// "fuse", "replace", or "remove".
+//
+// ** If "op" is "fuse" or "replace", the dir must contain exactly the following
+// further keys and dirs:
+//
+// *** The dir must contain a key named "template" of string type, containing
+// the full template name, encoded as follows: 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".
+//
+// *** The dir must contain a dir named "content" that contains the set
+// element's (i.e., set or group node's) real content.
//
-// * Set element and property "remove" operations are encoded as dconf key path
-// segments as follows, and the associated value being a GVariant of empty
-// tuple type. For set elements, the dconf key path segment consists of an
-// encoding of the node name, where each occurrence of U+0000 NULL is replace
-// by the three characters "\00", each occurrence of U+002F SOLIDUS is
-// replaced by the three characters "\2F", and each ocurrence of U+005C
-// REVERSE SOLIDUS is replaced by the three characters "\5C". For properties,
-// the dconf key path segment directly uses the node name.
+// ** If "op" is "remove", the dir must contain no further keys or dirs.
//
// * Property and localized property value "fuse" operations map to GVariant
// instances as follows:
@@ -95,6 +93,8 @@
//
// ** Nillable values recursively map to GVariant maybe instances.
//
+// * Property "remove" operations map to GVariant instances of empty tuple type.
+//
// Finalization: The component-update.dtd allows for finalization of
// oor:component-data, node, and prop elements, while dconf allows for locking
// of individual keys. That does not match, but just mark the individual Node
@@ -167,18 +167,16 @@ private:
gchar ** array_;
};
-bool decode(OUString * string, bool nul, bool slash, bool semicolon) {
+bool decode(OUString * string, bool slash) {
for (sal_Int32 i = 0;; ++i) {
i = string->indexOf('\\', i);
if (i == -1) {
return true;
}
- if (nul && string->match("00", i + 1)) {
+ if (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 {
@@ -285,7 +283,7 @@ bool getStringValue(
SAL_WARN("configmgr.dconf", "non--UTF-8 string value for key " << key);
return false;
}
- return decode(value, true, false, false);
+ return decode(value, false);
}
bool getString(
@@ -721,9 +719,9 @@ void readDir(
}
OString s(*p, static_cast<sal_Int32>(n));
OString path(dir + s);
- OUString seg;
+ OUString name;
if (!rtl_convertStringToUString(
- &seg.pData, s.getStr(), s.getLength(), RTL_TEXTENCODING_UTF8,
+ &name.pData, s.getStr(), s.getLength(), RTL_TEXTENCODING_UTF8,
(RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
| RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
@@ -731,87 +729,129 @@ void readDir(
SAL_WARN("configmgr.dconf", "non--UTF-8 dir/key in dir " << dir);
continue;
}
- bool isDir = seg.endsWith("/", &seg);
- bool remove;
- OUString name;
+ bool isDir = name.endsWith("/", &name);
OUString templ;
+ bool remove;
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, true, true, 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;
+ if (!isDir) {
+ SAL_WARN(
+ "configmgr.dconf",
+ "bad key " << path << " does not match set element");
+ continue;
+ }
+ if (!decode(&name, true)) {
+ continue;
+ }
+ enum class Op { None, Fuse, Replace, Remove };
+ Op op = Op::None;
+ bool content = false;
+ bool bad = false;
+ StringArrayHolder a2(
+ dconf_client_list(client.get(), path.getStr(), nullptr));
+ for (char const * const * p2 = a2.get(); *p2 != nullptr; ++p2) {
+ if (std::strcmp(*p2, "op") == 0) {
+ OString path2(path + "op");
+ GVariantHolder v(
+ dconf_client_read(client.get(), path2.getStr()));
+ if (v.get() == nullptr) {
+ SAL_WARN(
+ "configmgr.dconf", "cannot read key " << path2);
+ bad = true;
+ break;
+ }
+ OUString ops;
+ if (!getStringValue(path2, v, &ops)) {
+ bad = true;
+ break;
+ }
+ if (ops == "fuse") {
+ op = Op::Fuse;
+ } else if (ops == "replace") {
+ op = Op::Replace;
+ } else if (ops == "remove") {
+ op = Op::Remove;
+ } else {
+ SAL_WARN(
+ "configmgr.dconf",
+ "bad key " << path2 << " value " << ops);
+ bad = true;
+ break;
+ }
+ } else if (std::strcmp(*p2, "template") == 0) {
+ OString path2(path + "template");
+ GVariantHolder v(
+ dconf_client_read(client.get(), path2.getStr()));
+ if (v.get() == nullptr) {
+ SAL_WARN(
+ "configmgr.dconf", "cannot read key " << path2);
+ bad = true;
+ break;
+ }
+ if (!getStringValue(path2, v, &templ)) {
+ bad = true;
+ break;
+ }
+ if (!static_cast<SetNode *>(node.get())->
+ isValidTemplate(templ))
+ {
+ SAL_WARN(
+ "configmgr.dconf",
+ "bad key " << path2 << " value " << templ
+ << " denotes unsupported set element template");
+ bad = true;
+ break;
+ }
+ } else if (std::strcmp(*p2, "content/") == 0) {
+ content = true;
} else {
SAL_WARN(
- "configmgr.dconf", "bad set element syntax " << path);
- continue;
+ "configmgr.dconf",
+ "bad dir/key " << p2
+ << " in set element indirection dir " << path);
+ bad = true;
+ break;
}
- rtl::Reference<SetNode> set(static_cast<SetNode *>(node.get()));
- if (!set->isValidTemplate(templ)) {
+ }
+ if (bad) {
+ continue;
+ }
+ switch (op) {
+ case Op::None:
+ SAL_WARN(
+ "configmgr.dconf",
+ "bad set element indirection dir " << path
+ << " missing \"op\" key");
+ continue;
+ case Op::Fuse:
+ case Op::Replace:
+ if (templ.isEmpty() || !content) {
SAL_WARN(
"configmgr.dconf",
- "bad " << path
- << " denotes unsupported set element template");
+ "missing \"content\" and/or \"template\" dir/key in "
+ "\"op\" = \"fuse\"/\"remove\" set element"
+ " indirection dir " << path);
continue;
}
- } else {
- remove = true;
- name = seg;
- if (!decode(&name, true, true, false)) {
- continue;
- }
- 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)
- {
+ path += "content/";
+ remove = false;
+ replace = op == Op::Replace;
+ break;
+ case Op::Remove:
+ if (!templ.isEmpty() || content) {
SAL_WARN(
"configmgr.dconf",
- "bad " << path
- << " does not denote set element removal");
+ "bad \"content\" and/or \"template\" dir/key in \"op\" "
+ "= \"remove\" set element indirection dir "
+ << path);
continue;
}
+ remove = true;
+ replace = false;
+ break;
}
} else {
remove = false;
- name = seg;
replace = false;
}
rtl::Reference<Node> member(members.findNode(layer, name));