lok: getSlideShowInfo: interactions: check that properties are available
[LibreOffice.git] / configmgr / source / dconf.cxx
blobc12f4a2814fd600f8aae8bd1c5c5dbde3250a176
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <sal/config.h>
12 #include <cassert>
13 #include <cstddef>
14 #include <cstring>
15 #include <forward_list>
16 #include <limits>
17 #include <vector>
19 #include <dconf/dconf.h>
21 #include <com/sun/star/uno/Sequence.hxx>
22 #include <o3tl/safeint.hxx>
23 #include <rtl/ustrbuf.hxx>
24 #include <sal/log.hxx>
26 #include "data.hxx"
27 #include "dconf.hxx"
28 #include "groupnode.hxx"
29 #include "localizedpropertynode.hxx"
30 #include "localizedvaluenode.hxx"
31 #include "nodemap.hxx"
32 #include "propertynode.hxx"
33 #include "setnode.hxx"
35 // component-data is encoded in dconf as follows:
37 // * The node hierarchy (starting at component nodes with names like
38 // "org.openoffice.Setup") maps to dconf paths underneath
39 // "/org/libreoffice/registry/".
41 // * Component, group, set, and localized property nodes map to dconf dirs,
42 // while property and localized value nodes map to dconf keys.
44 // * The names of nodes that are not set elements are used directly as dconf
45 // path segments. (The syntax for node names is any non-empty sequences of
46 // any Unicode scalar values except U+0000--0008, U+000B--000C, U+000E--001F,
47 // U+002F SOLIDUS, and U+FFFE--FFFF. TODO: "<aruiz> sberg, in general I think
48 // it'd be nice if you used path separators instead of dots though, they have
49 // meaning in dconf/gvdb world :-)"?)
51 // * The names of set element nodes are encoded as dconf path segments as
52 // follows: each occurrence of U+0000 NULL is replace by the three characters
53 // "\00", each occurrence of U+002F SOLIDUS is replaced by the three
54 // characters "\2F", and each occurrence of U+005C REVERSE SOLIDUS is replaced
55 // by the three characters "\5C".
57 // * Set elements (which must themselves be either sets or groups) map to
58 // "indirection" dconf dirs as follows:
60 // ** The dir must contain a key named "op" of string type, with a value of
61 // "fuse", "replace", or "remove".
63 // ** If "op" is "fuse" or "replace", the dir must contain exactly the following
64 // further keys and dirs:
66 // *** The dir must contain a key named "template" of string type, containing
67 // the full template name, encoded as follows: each occurrence of U+0000
68 // NULL is replace by the three characters "\00" and each occurrence of
69 // U+005C REVERSE SOLIDUS is replaced by the three characters "\5C".
71 // *** The dir must contain a dir named "content" that contains the set
72 // element's (i.e., set or group node's) real content.
74 // ** If "op" is "remove", the dir must contain no further keys or dirs.
76 // * Property and localized property value "fuse" operations map to GVariant
77 // instances as follows:
79 // ** Non-nillable boolean values map to GVariant boolean instances.
81 // ** Non-nillable short values map to GVariant int16 instances.
83 // ** Non-nillable int values map to GVariant int32 instances.
85 // ** Non-nillable long values map to GVariant int64 instances.
87 // ** Non-nillable double values map to GVariant double instances.
89 // ** Non-nillable string values map to GVariant string instances, with the
90 // following encoding: each occurrence of U+0000 NULL is replace by the three
91 // characters "\00" and each occurrence of U+005C REVERSE SOLIDUS is replaced
92 // by the three characters "\5C".
94 // ** Non-nillable hexbinary values map to GVariant byte array instances.
96 // ** Non-nillable list values recursively map to GVariant array instances.
98 // ** Nillable values recursively map to GVariant maybe instances.
100 // * Property "remove" operations map to GVariant instances of empty tuple type.
102 // Finalization: The component-update.dtd allows for finalization of
103 // oor:component-data, node, and prop elements, while dconf allows for locking
104 // of individual keys. That does not match, but just mark the individual Node
105 // instances that correspond to individual dconf keys as finalized for
106 // non-writable dconf keys.
108 // TODO: support "mandatory" and "external"?
110 namespace configmgr::dconf {
112 namespace {
114 template<typename T> class GObjectHolder {
115 public:
116 explicit GObjectHolder(T * object): object_(object) {}
118 ~GObjectHolder() {
119 if (object_ != nullptr) {
120 g_object_unref(object_);
124 T * get() const { return object_; }
126 private:
127 GObjectHolder(GObjectHolder const &) = delete;
128 GObjectHolder& operator =(GObjectHolder const &) = delete;
130 T * object_;
133 class GVariantHolder {
134 public:
135 explicit GVariantHolder(GVariant * variant = nullptr): variant_(variant) {}
137 ~GVariantHolder() { unref(); }
139 void reset(GVariant * variant) {
140 unref();
141 variant_ = variant;
144 void release() { variant_ = nullptr; }
146 GVariant * get() const { return variant_; }
148 private:
149 GVariantHolder(GVariantHolder const &) = delete;
150 GVariantHolder& operator =(GVariantHolder const &) = delete;
152 void unref() {
153 if (variant_ != nullptr) {
154 g_variant_unref(variant_);
158 GVariant * variant_;
161 class GVariantTypeHolder {
162 public:
163 explicit GVariantTypeHolder(GVariantType * type): type_(type) {}
165 ~GVariantTypeHolder() {
166 if (type_ != nullptr) {
167 g_variant_type_free(type_);
171 GVariantType * get() const { return type_; }
173 private:
174 GVariantTypeHolder(GVariantTypeHolder const &) = delete;
175 GVariantTypeHolder& operator =(GVariantTypeHolder const &) = delete;
177 GVariantType * type_;
180 class StringArrayHolder {
181 public:
182 explicit StringArrayHolder(gchar ** array): array_(array) {}
184 ~StringArrayHolder() { g_strfreev(array_); }
186 gchar ** get() const { return array_; }
188 private:
189 StringArrayHolder(StringArrayHolder const &) = delete;
190 StringArrayHolder& operator =(StringArrayHolder const &) = delete;
192 gchar ** array_;
195 class ChangesetHolder {
196 public:
197 explicit ChangesetHolder(DConfChangeset * changeset):
198 changeset_(changeset)
201 ~ChangesetHolder() {
202 if (changeset_ != nullptr) {
203 dconf_changeset_unref(changeset_);
207 DConfChangeset * get() const { return changeset_; }
209 private:
210 ChangesetHolder(ChangesetHolder const &) = delete;
211 ChangesetHolder& operator =(ChangesetHolder const &) = delete;
213 DConfChangeset * changeset_;
216 OString getRoot() {
217 return "/org/libreoffice/registry"_ostr;
220 bool decode(OUString * string, bool slash) {
221 for (sal_Int32 i = 0;; ++i) {
222 i = string->indexOf('\\', i);
223 if (i == -1) {
224 return true;
226 if (string->match("00", i + 1)) {
227 *string = string->replaceAt(i, 3, OUStringChar(u'\0'));
228 } else if (slash && string->match("2F", i + 1)) {
229 *string = string->replaceAt(i, 3, u"/");
230 } else if (string->match("5C", i + 1)) {
231 *string = string->replaceAt(i + 1, 2, u"");
232 } else {
233 SAL_WARN("configmgr.dconf", "bad escape in " << *string);
234 return false;
239 bool getBoolean(
240 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
242 assert(value != nullptr);
243 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_BOOLEAN)) {
244 SAL_WARN(
245 "configmgr.dconf",
246 "bad key " << key << " does not match boolean property");
247 return false;
249 *value <<= bool(g_variant_get_boolean(variant.get()));
250 return true;
253 bool getShort(
254 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
256 assert(value != nullptr);
257 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT16)) {
258 SAL_WARN(
259 "configmgr.dconf",
260 "bad key " << key << " does not match short property");
261 return false;
263 *value <<= sal_Int16(g_variant_get_int16(variant.get()));
264 return true;
267 bool getInt(
268 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
270 assert(value != nullptr);
271 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT32)) {
272 SAL_WARN(
273 "configmgr.dconf",
274 "bad key " << key << " does not match int property");
275 return false;
277 *value <<= sal_Int32(g_variant_get_int32(variant.get()));
278 return true;
281 bool getLong(
282 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
284 assert(value != nullptr);
285 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT64)) {
286 SAL_WARN(
287 "configmgr.dconf",
288 "bad key " << key << " does not match long property");
289 return false;
291 *value <<= sal_Int64(g_variant_get_int64(variant.get()));
292 return true;
295 bool getDouble(
296 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
298 assert(value != nullptr);
299 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_DOUBLE)) {
300 SAL_WARN(
301 "configmgr.dconf",
302 "bad key " << key << " does not match double property");
303 return false;
305 *value <<= double(g_variant_get_double(variant.get()));
306 return true;
309 bool getStringValue(
310 OString const & key, GVariantHolder const & variant, OUString * value)
312 assert(value != nullptr);
313 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_STRING)) {
314 SAL_WARN(
315 "configmgr.dconf",
316 "bad key " << key << " does not match string property");
317 return false;
319 gsize n;
320 char const * p = g_variant_get_string(variant.get(), &n);
321 if (n > o3tl::make_unsigned(
322 std::numeric_limits<sal_Int32>::max()))
324 SAL_WARN("configmgr.dconf", "too long string value for key " << key);
325 return false;
327 if (!rtl_convertStringToUString(
328 &value->pData, p, static_cast<sal_Int32>(n), RTL_TEXTENCODING_UTF8,
329 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
330 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
331 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
333 SAL_WARN("configmgr.dconf", "non--UTF-8 string value for key " << key);
334 return false;
336 return decode(value, false);
339 bool getString(
340 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
342 assert(value != nullptr);
343 OUString v;
344 if (!getStringValue(key, variant, &v)) {
345 return false;
347 *value <<= v;
348 return true;
351 bool getHexbinaryValue(
352 OString const & key, GVariantHolder const & variant,
353 css::uno::Sequence<sal_Int8> * value)
355 assert(value != nullptr);
356 if (std::strcmp(g_variant_get_type_string(variant.get()), "ay") != 0) {
357 SAL_WARN(
358 "configmgr.dconf",
359 "bad key " << key << " does not match hexbinary property");
360 return false;
362 gsize n;
363 gconstpointer p = g_variant_get_fixed_array(
364 variant.get(), &n, sizeof (guchar));
365 if (n > o3tl::make_unsigned(
366 std::numeric_limits<sal_Int32>::max()))
368 SAL_WARN("configmgr.dconf", "too long hexbinary value for key " << key);
369 return false;
371 value->realloc(static_cast<sal_Int32>(n));
372 static_assert(sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
373 std::memcpy(value->getArray(), p, n * sizeof (guchar));
374 // assuming that n * sizeof (guchar) is small enough for std::size_t
375 return true;
378 bool getHexbinary(
379 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
381 assert(value != nullptr);
382 css::uno::Sequence<sal_Int8> v;
383 if (!getHexbinaryValue(key, variant, &v)) {
384 return false;
386 *value <<= v;
387 return true;
390 bool getBooleanList(
391 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
393 assert(value != nullptr);
394 if (std::strcmp(g_variant_get_type_string(variant.get()), "ab") != 0) {
395 SAL_WARN(
396 "configmgr.dconf",
397 "bad key " << key << " does not match boolean list property");
398 return false;
400 gsize n;
401 gconstpointer p = g_variant_get_fixed_array(
402 variant.get(), &n, sizeof (guchar));
403 if (n > o3tl::make_unsigned(
404 std::numeric_limits<sal_Int32>::max()))
406 SAL_WARN("configmgr.dconf", "too long boolean list for key " << key);
407 return false;
409 css::uno::Sequence<sal_Bool> v(static_cast<sal_Int32>(n));
410 static_assert(sizeof (sal_Bool) == sizeof (guchar), "size mismatch");
411 std::memcpy(v.getArray(), p, n * sizeof (guchar));
412 // assuming that n * sizeof (guchar) is small enough for std::size_t
413 *value <<= v;
414 return true;
417 bool getShortList(
418 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
420 assert(value != nullptr);
421 if (std::strcmp(g_variant_get_type_string(variant.get()), "an") != 0) {
422 SAL_WARN(
423 "configmgr.dconf",
424 "bad key " << key << " does not match short list property");
425 return false;
427 gsize n;
428 gconstpointer p = g_variant_get_fixed_array(
429 variant.get(), &n, sizeof (gint16));
430 if (n > o3tl::make_unsigned(
431 std::numeric_limits<sal_Int32>::max()))
433 SAL_WARN("configmgr.dconf", "too long short list for key " << key);
434 return false;
436 css::uno::Sequence<sal_Int16> v(static_cast<sal_Int32>(n));
437 static_assert(sizeof (sal_Int16) == sizeof (gint16), "size mismatch");
438 std::memcpy(v.getArray(), p, n * sizeof (gint16));
439 // assuming that n * sizeof (gint16) is small enough for std::size_t
440 *value <<= v;
441 return true;
444 bool getIntList(
445 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
447 assert(value != nullptr);
448 if (std::strcmp(g_variant_get_type_string(variant.get()), "ai") != 0) {
449 SAL_WARN(
450 "configmgr.dconf",
451 "bad key " << key << " does not match int list property");
452 return false;
454 gsize n;
455 gconstpointer p = g_variant_get_fixed_array(
456 variant.get(), &n, sizeof (gint32));
457 if (n > o3tl::make_unsigned(
458 std::numeric_limits<sal_Int32>::max()))
460 SAL_WARN("configmgr.dconf", "too long int list for key " << key);
461 return false;
463 css::uno::Sequence<sal_Int32> v(static_cast<sal_Int32>(n));
464 static_assert(sizeof (sal_Int32) == sizeof (gint32), "size mismatch");
465 std::memcpy(v.getArray(), p, n * sizeof (gint32));
466 // assuming that n * sizeof (gint32) is small enough for std::size_t
467 *value <<= v;
468 return true;
471 bool getLongList(
472 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
474 assert(value != nullptr);
475 if (std::strcmp(g_variant_get_type_string(variant.get()), "ax") != 0) {
476 SAL_WARN(
477 "configmgr.dconf",
478 "bad key " << key << " does not match long list property");
479 return false;
481 gsize n;
482 gconstpointer p = g_variant_get_fixed_array(
483 variant.get(), &n, sizeof (gint64));
484 if (n > o3tl::make_unsigned(
485 std::numeric_limits<sal_Int32>::max()))
487 SAL_WARN("configmgr.dconf", "too long long list for key " << key);
488 return false;
490 css::uno::Sequence<sal_Int64> v(static_cast<sal_Int32>(n));
491 static_assert(sizeof (sal_Int64) == sizeof (gint64), "size mismatch");
492 std::memcpy(v.getArray(), p, n * sizeof (gint64));
493 // assuming that n * sizeof (gint64) is small enough for std::size_t
494 *value <<= v;
495 return true;
498 bool getDoubleList(
499 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
501 assert(value != nullptr);
502 if (std::strcmp(g_variant_get_type_string(variant.get()), "ad") != 0) {
503 SAL_WARN(
504 "configmgr.dconf",
505 "bad key " << key << " does not match double list property");
506 return false;
508 gsize n;
509 gconstpointer p = g_variant_get_fixed_array(
510 variant.get(), &n, sizeof (gdouble));
511 if (n > o3tl::make_unsigned(
512 std::numeric_limits<sal_Int32>::max()))
514 SAL_WARN("configmgr.dconf", "too long double list for key " << key);
515 return false;
517 css::uno::Sequence<double> v(static_cast<sal_Int32>(n));
518 static_assert(std::is_same<double, gdouble>::value, "type mismatch");
519 std::memcpy(v.getArray(), p, n * sizeof (gdouble));
520 // assuming that n * sizeof (gdouble) is small enough for std::size_t
521 *value <<= v;
522 return true;
525 bool getStringList(
526 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
528 assert(value != nullptr);
529 if (std::strcmp(g_variant_get_type_string(variant.get()), "as") != 0) {
530 SAL_WARN(
531 "configmgr.dconf",
532 "bad key " << key << " does not match string list property");
533 return false;
535 gsize n = g_variant_n_children(variant.get());
536 if (n > o3tl::make_unsigned(
537 std::numeric_limits<sal_Int32>::max()))
539 SAL_WARN("configmgr.dconf", "too long string list for key " << key);
540 return false;
542 css::uno::Sequence<OUString> v(static_cast<sal_Int32>(n));
543 for (gsize i = 0; i != n; ++i) {
544 GVariantHolder c(g_variant_get_child_value(variant.get(), i));
545 if (!getStringValue(key, c, v.getArray() + i)) {
546 return false;
549 *value <<= v;
550 return true;
553 bool getHexbinaryList(
554 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
556 assert(value != nullptr);
557 if (std::strcmp(g_variant_get_type_string(variant.get()), "aay") != 0) {
558 SAL_WARN(
559 "configmgr.dconf",
560 "bad key " << key << " does not match hexbinary list property");
561 return false;
563 gsize n = g_variant_n_children(variant.get());
564 if (n > o3tl::make_unsigned(
565 std::numeric_limits<sal_Int32>::max()))
567 SAL_WARN("configmgr.dconf", "too long hexbinary list for key " << key);
568 return false;
570 css::uno::Sequence<css::uno::Sequence<sal_Int8>> v(
571 static_cast<sal_Int32>(n));
572 for (gsize i = 0; i != n; ++i) {
573 GVariantHolder c(g_variant_get_child_value(variant.get(), i));
574 if (!getHexbinaryValue(key, c, v.getArray() + i)) {
575 return false;
578 *value <<= v;
579 return true;
582 bool getAny(
583 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
585 char const * t = g_variant_get_type_string(variant.get());
586 if (std::strcmp(t, "b") == 0) {
587 return getBoolean(key, variant, value);
589 if (std::strcmp(t, "n") == 0) {
590 return getShort(key, variant, value);
592 if (std::strcmp(t, "i") == 0) {
593 return getInt(key, variant, value);
595 if (std::strcmp(t, "x") == 0) {
596 return getLong(key, variant, value);
598 if (std::strcmp(t, "d") == 0) {
599 return getDouble(key, variant, value);
601 if (std::strcmp(t, "s") == 0) {
602 return getString(key, variant, value);
604 if (std::strcmp(t, "ay") == 0) {
605 return getHexbinary(key, variant, value);
607 if (std::strcmp(t, "ab") == 0) {
608 return getBooleanList(key, variant, value);
610 if (std::strcmp(t, "an") == 0) {
611 return getShortList(key, variant, value);
613 if (std::strcmp(t, "ai") == 0) {
614 return getIntList(key, variant, value);
616 if (std::strcmp(t, "ax") == 0) {
617 return getLongList(key, variant, value);
619 if (std::strcmp(t, "ad") == 0) {
620 return getDoubleList(key, variant, value);
622 if (std::strcmp(t, "as") == 0) {
623 return getStringList(key, variant, value);
625 if (std::strcmp(t, "aay") == 0) {
626 return getHexbinaryList(key, variant, value);
628 SAL_WARN(
629 "configmgr.dconf", "bad key " << key << " does not match any property");
630 return false;
633 enum class ReadValue { Error, Value, Remove };
635 ReadValue readValue(
636 GObjectHolder<DConfClient> const & client, OString const & path, Type type,
637 bool nillable, bool removable, css::uno::Any * value)
639 assert(value != nullptr);
640 assert(!value->hasValue());
641 assert(!path.endsWith("/"));
642 GVariantHolder v(dconf_client_read(client.get(), path.getStr()));
643 if (v.get() == nullptr) {
644 SAL_WARN("configmgr.dconf", "cannot read key " << path);
645 return ReadValue::Error;
647 if (removable && std::strcmp(g_variant_get_type_string(v.get()), "()") == 0)
649 return ReadValue::Remove;
651 bool nil;
652 if (nillable) {
653 if (g_variant_classify(v.get()) != G_VARIANT_CLASS_MAYBE) {
654 SAL_WARN(
655 "configmgr.dconf",
656 "bad key " << path << " does not match nillable property");
658 v.reset(g_variant_get_maybe(v.get()));
659 nil = v.get() == nullptr;
660 } else {
661 nil = false;
663 if (!nil) {
664 switch (type) {
665 case TYPE_ANY:
666 if (!getAny(path, v, value)) {
667 return ReadValue::Error;
669 break;
670 case TYPE_BOOLEAN:
671 if (!getBoolean(path, v, value)) {
672 return ReadValue::Error;
674 break;
675 case TYPE_SHORT:
676 if (!getShort(path, v, value)) {
677 return ReadValue::Error;
679 break;
680 case TYPE_INT:
681 if (!getInt(path, v, value)) {
682 return ReadValue::Error;
684 break;
685 case TYPE_LONG:
686 if (!getLong(path, v, value)) {
687 return ReadValue::Error;
689 break;
690 case TYPE_DOUBLE:
691 if (!getDouble(path, v, value)) {
692 return ReadValue::Error;
694 break;
695 case TYPE_STRING:
696 if (!getString(path, v, value)) {
697 return ReadValue::Error;
699 break;
700 case TYPE_HEXBINARY:
701 if (!getHexbinary(path, v, value)) {
702 return ReadValue::Error;
704 break;
705 case TYPE_BOOLEAN_LIST:
706 if (!getBooleanList(path, v, value)) {
707 return ReadValue::Error;
709 break;
710 case TYPE_SHORT_LIST:
711 if (!getShortList(path, v, value)) {
712 return ReadValue::Error;
714 break;
715 case TYPE_INT_LIST:
716 if (!getIntList(path, v, value)) {
717 return ReadValue::Error;
719 break;
720 case TYPE_LONG_LIST:
721 if (!getLongList(path, v, value)) {
722 return ReadValue::Error;
724 break;
725 case TYPE_DOUBLE_LIST:
726 if (!getDoubleList(path, v, value)) {
727 return ReadValue::Error;
729 break;
730 case TYPE_STRING_LIST:
731 if (!getStringList(path, v, value)) {
732 return ReadValue::Error;
734 break;
735 case TYPE_HEXBINARY_LIST:
736 if (!getHexbinaryList(path, v, value)) {
737 return ReadValue::Error;
739 break;
740 default:
741 assert(false); // cannot happen
744 return ReadValue::Value;
747 void finalize(
748 GObjectHolder<DConfClient> const & client, OString const & path,
749 rtl::Reference<Node> const & node, int layer)
751 if (!dconf_client_is_writable(client.get(), path.getStr())) {
752 node->setFinalized(layer);
756 void readDir(
757 Data & data, int layer, rtl::Reference<Node> const & node,
758 NodeMap & members, GObjectHolder<DConfClient> const & client,
759 OString const & dir)
761 StringArrayHolder a(dconf_client_list(client.get(), dir.getStr(), nullptr));
762 for (char const * const * p = a.get(); *p != nullptr; ++p) {
763 std::size_t n = std::strlen(*p);
764 if (n > o3tl::make_unsigned(
765 std::numeric_limits<sal_Int32>::max()))
767 SAL_WARN("configmgr.dconf", "too long dir/key in dir " << dir);
768 continue;
770 OString s(*p, static_cast<sal_Int32>(n));
771 OString path(dir + s);
772 OUString name;
773 if (!rtl_convertStringToUString(
774 &name.pData, s.getStr(), s.getLength(), RTL_TEXTENCODING_UTF8,
775 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
776 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
777 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
779 SAL_WARN("configmgr.dconf", "non--UTF-8 dir/key in dir " << dir);
780 continue;
782 bool isDir = name.endsWith("/", &name);
783 OUString templ;
784 bool remove;
785 bool replace;
786 if (node.is() && node->kind() == Node::KIND_SET) {
787 if (!isDir) {
788 SAL_WARN(
789 "configmgr.dconf",
790 "bad key " << path << " does not match set element");
791 continue;
793 if (!decode(&name, true)) {
794 continue;
796 enum class Op { None, Fuse, Replace, Remove };
797 Op op = Op::None;
798 bool content = false;
799 bool bad = false;
800 StringArrayHolder a2(
801 dconf_client_list(client.get(), path.getStr(), nullptr));
802 for (char const * const * p2 = a2.get(); *p2 != nullptr; ++p2) {
803 if (std::strcmp(*p2, "op") == 0) {
804 OString path2(path + "op");
805 GVariantHolder v(
806 dconf_client_read(client.get(), path2.getStr()));
807 if (v.get() == nullptr) {
808 SAL_WARN(
809 "configmgr.dconf", "cannot read key " << path2);
810 bad = true;
811 break;
813 OUString ops;
814 if (!getStringValue(path2, v, &ops)) {
815 bad = true;
816 break;
818 if (ops == "fuse") {
819 op = Op::Fuse;
820 } else if (ops == "replace") {
821 op = Op::Replace;
822 } else if (ops == "remove") {
823 op = Op::Remove;
824 } else {
825 SAL_WARN(
826 "configmgr.dconf",
827 "bad key " << path2 << " value " << ops);
828 bad = true;
829 break;
831 } else if (std::strcmp(*p2, "template") == 0) {
832 OString path2(path + "template");
833 GVariantHolder v(
834 dconf_client_read(client.get(), path2.getStr()));
835 if (v.get() == nullptr) {
836 SAL_WARN(
837 "configmgr.dconf", "cannot read key " << path2);
838 bad = true;
839 break;
841 if (!getStringValue(path2, v, &templ)) {
842 bad = true;
843 break;
845 if (!static_cast<SetNode *>(node.get())->
846 isValidTemplate(templ))
848 SAL_WARN(
849 "configmgr.dconf",
850 "bad key " << path2 << " value " << templ
851 << " denotes unsupported set element template");
852 bad = true;
853 break;
855 } else if (std::strcmp(*p2, "content/") == 0) {
856 content = true;
857 } else {
858 SAL_WARN(
859 "configmgr.dconf",
860 "bad dir/key " << p2
861 << " in set element indirection dir " << path);
862 bad = true;
863 break;
866 if (bad) {
867 continue;
869 switch (op) {
870 default: // case Op::None:
871 SAL_WARN(
872 "configmgr.dconf",
873 "bad set element indirection dir " << path
874 << " missing \"op\" key");
875 continue;
876 case Op::Fuse:
877 case Op::Replace:
878 if (templ.isEmpty() || !content) {
879 SAL_WARN(
880 "configmgr.dconf",
881 "missing \"content\" and/or \"template\" dir/key in "
882 "\"op\" = \"fuse\"/\"remove\" set element"
883 " indirection dir " << path);
884 continue;
886 path += "content/";
887 remove = false;
888 replace = op == Op::Replace;
889 break;
890 case Op::Remove:
891 if (!templ.isEmpty() || content) {
892 SAL_WARN(
893 "configmgr.dconf",
894 "bad \"content\" and/or \"template\" dir/key in \"op\" "
895 "= \"remove\" set element indirection dir "
896 << path);
897 continue;
899 remove = true;
900 replace = false;
901 break;
903 } else {
904 remove = false;
905 replace = false;
907 rtl::Reference<Node> member(members.findNode(layer, name));
908 bool insert = !member.is();
909 if (!remove) {
910 if (replace || insert) {
911 if (!node.is()) {
912 SAL_WARN("configmgr.dconf", "bad unmatched " << path);
913 continue;
915 switch (node->kind()) {
916 case Node::KIND_LOCALIZED_PROPERTY:
917 member.set(new LocalizedValueNode(layer));
918 break;
919 case Node::KIND_GROUP:
920 if (!static_cast<GroupNode *>(node.get())->isExtensible()) {
921 SAL_WARN("configmgr.dconf", "bad unmatched " << path);
922 continue;
924 member.set(
925 new PropertyNode(
926 layer, TYPE_ANY, true, css::uno::Any(), true));
927 break;
928 case Node::KIND_SET:
929 assert(!templ.isEmpty());
930 member = data.getTemplate(layer, templ);
931 if (!member.is()) {
932 SAL_WARN(
933 "configmgr.dconf",
934 "bad " << path << " denoting undefined template "
935 << templ);
936 continue;
938 member = member->clone(true);
939 break;
940 default:
941 assert(false); // cannot happen
943 } else if (!templ.isEmpty() && templ != member->getTemplateName()) {
944 SAL_WARN(
945 "configmgr.dconf",
946 "bad " << path
947 << " denoting set element of non-matching template "
948 << member->getTemplateName());
949 continue;
952 if (member.is()) {
953 if (member->getFinalized() < layer) {
954 continue;
956 switch (member->kind()) {
957 case Node::KIND_PROPERTY:
959 if (isDir) {
960 SAL_WARN(
961 "configmgr.dconf",
962 "bad dir " << path << " does not match property");
963 continue;
965 rtl::Reference<PropertyNode> prop(
966 static_cast<PropertyNode *>(member.get()));
967 css::uno::Any value;
968 switch (readValue(
969 client, path, prop->getStaticType(),
970 prop->isNillable(), prop->isExtension(),
971 &value))
973 case ReadValue::Error:
974 continue;
975 case ReadValue::Value:
976 prop->setValue(layer, value, false);
977 finalize(client, path, member, layer);
978 break;
979 case ReadValue::Remove:
980 remove = true;
981 break;
983 break;
985 case Node::KIND_LOCALIZED_VALUE:
987 if (isDir) {
988 SAL_WARN(
989 "configmgr.dconf",
990 "bad dir " << path
991 << " does not match localized value");
992 continue;
994 assert(
995 node.is()
996 && node->kind() == Node::KIND_LOCALIZED_PROPERTY);
997 rtl::Reference<LocalizedPropertyNode> locProp(
998 static_cast<LocalizedPropertyNode *>(node.get()));
999 css::uno::Any value;
1000 if (readValue(
1001 client, path, locProp->getStaticType(),
1002 locProp->isNillable(), false, &value)
1003 == ReadValue::Error)
1005 continue;
1007 static_cast<LocalizedValueNode *>(member.get())->setValue(
1008 layer, value, false);
1009 finalize(client, path, member, layer);
1010 break;
1012 case Node::KIND_LOCALIZED_PROPERTY:
1013 case Node::KIND_GROUP:
1014 case Node::KIND_SET:
1015 if (!isDir) {
1016 SAL_WARN(
1017 "configmgr.dconf",
1018 "bad key " << path
1019 << " does not match localized property, group, or"
1020 " set, respectively");
1021 continue;
1023 assert(path.endsWith("/"));
1024 readDir(
1025 data, layer, member, member->getMembers(), client, path);
1026 break;
1027 default:
1028 assert(false); // cannot happen
1031 if (remove) {
1032 if (!(member.is() && member->getMandatory())) {
1033 members.erase(name);
1035 } else if (replace) {
1036 members.erase(name);
1037 members.insert(NodeMap::value_type(name, member));
1038 } else if (insert) {
1039 members.insert(NodeMap::value_type(name, member));
1044 OString encodeSegment(OUString const & name, bool setElement) {
1045 if (!setElement) {
1046 return name.toUtf8();
1048 OUStringBuffer buf;
1049 for (sal_Int32 i = 0; i != name.getLength(); ++i) {
1050 sal_Unicode c = name[i];
1051 switch (c) {
1052 case '\0':
1053 buf.append("\\00");
1054 break;
1055 case '/':
1056 buf.append("\\2F");
1057 break;
1058 case '\\':
1059 buf.append("\\5C");
1060 break;
1061 default:
1062 buf.append(c);
1065 return buf.makeStringAndClear().toUtf8();
1068 OString encodeString(OUString const & value) {
1069 OUStringBuffer buf;
1070 for (sal_Int32 i = 0; i != value.getLength(); ++i) {
1071 sal_Unicode c = value[i];
1072 switch (c) {
1073 case '\0':
1074 buf.append("\\00");
1075 break;
1076 case '\\':
1077 buf.append("\\5C");
1078 break;
1079 default:
1080 buf.append(c);
1083 return buf.makeStringAndClear().toUtf8();
1086 bool addProperty(
1087 ChangesetHolder const & changeset, OString const & pathRepresentation,
1088 Type type, bool nillable, css::uno::Any const & value)
1090 Type dynType = getDynamicType(value);
1091 assert(dynType != TYPE_ERROR);
1092 if (type == TYPE_ANY) {
1093 type = dynType;
1095 GVariantHolder v;
1096 std::forward_list<GVariantHolder> children;
1097 if (dynType == TYPE_NIL) {
1098 switch (type) {
1099 case TYPE_BOOLEAN:
1100 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_BOOLEAN, nullptr));
1101 break;
1102 case TYPE_SHORT:
1103 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT16, nullptr));
1104 break;
1105 case TYPE_INT:
1106 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT32, nullptr));
1107 break;
1108 case TYPE_LONG:
1109 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT64, nullptr));
1110 break;
1111 case TYPE_DOUBLE:
1112 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_DOUBLE, nullptr));
1113 break;
1114 case TYPE_STRING:
1115 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_STRING, nullptr));
1116 break;
1117 case TYPE_HEXBINARY:
1118 case TYPE_BOOLEAN_LIST:
1119 case TYPE_SHORT_LIST:
1120 case TYPE_INT_LIST:
1121 case TYPE_LONG_LIST:
1122 case TYPE_DOUBLE_LIST:
1123 case TYPE_STRING_LIST:
1124 case TYPE_HEXBINARY_LIST:
1126 static char const * const typeString[
1127 TYPE_HEXBINARY_LIST - TYPE_HEXBINARY + 1]
1128 = { "ay", "ab", "an", "ai", "ax", "ad", "as", "aay" };
1129 GVariantTypeHolder ty(
1130 g_variant_type_new(typeString[type - TYPE_HEXBINARY]));
1131 if (ty.get() == nullptr) {
1132 SAL_WARN("configmgr.dconf", "g_variant_type_new failed");
1133 return false;
1135 v.reset(g_variant_new_maybe(ty.get(), nullptr));
1136 break;
1138 default:
1139 assert(false); // this cannot happen
1140 break;
1142 if (v.get() == nullptr) {
1143 SAL_WARN("configmgr.dconf", "g_variant_new_maybe failed");
1144 return false;
1146 } else {
1147 switch (type) {
1148 case TYPE_BOOLEAN:
1149 v.reset(g_variant_new_boolean(value.get<bool>()));
1150 break;
1151 case TYPE_SHORT:
1152 v.reset(g_variant_new_int16(value.get<sal_Int16>()));
1153 break;
1154 case TYPE_INT:
1155 v.reset(g_variant_new_int32(value.get<sal_Int32>()));
1156 break;
1157 case TYPE_LONG:
1158 v.reset(g_variant_new_int64(value.get<sal_Int64>()));
1159 break;
1160 case TYPE_DOUBLE:
1161 v.reset(g_variant_new_double(value.get<double>()));
1162 break;
1163 case TYPE_STRING:
1164 v.reset(
1165 g_variant_new_string(
1166 encodeString(value.get<OUString>()).getStr()));
1167 break;
1168 case TYPE_HEXBINARY:
1170 css::uno::Sequence<sal_Int8> seq(
1171 value.get<css::uno::Sequence<sal_Int8>>());
1172 static_assert(
1173 sizeof(sal_Int32) <= sizeof(gsize),
1174 "G_MAXSIZE too small");
1175 static_assert(
1176 sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
1177 v.reset(
1178 g_variant_new_fixed_array(
1179 G_VARIANT_TYPE_BYTE, seq.getConstArray(),
1180 seq.getLength(), sizeof (sal_Int8)));
1181 break;
1183 case TYPE_BOOLEAN_LIST:
1185 css::uno::Sequence<sal_Bool> seq(
1186 value.get<css::uno::Sequence<sal_Bool>>());
1187 static_assert(
1188 sizeof(sal_Int32) <= sizeof(gsize),
1189 "G_MAXSIZE too small");
1190 static_assert(sizeof (sal_Bool) == 1, "size mismatch");
1191 v.reset(
1192 g_variant_new_fixed_array(
1193 G_VARIANT_TYPE_BOOLEAN, seq.getConstArray(),
1194 seq.getLength(), sizeof (sal_Bool)));
1195 break;
1197 case TYPE_SHORT_LIST:
1199 css::uno::Sequence<sal_Int16> seq(
1200 value.get<css::uno::Sequence<sal_Int16>>());
1201 static_assert(
1202 sizeof(sal_Int32) <= sizeof(gsize),
1203 "G_MAXSIZE too small");
1204 static_assert(
1205 sizeof (sal_Int16) == sizeof (gint16), "size mismatch");
1206 v.reset(
1207 g_variant_new_fixed_array(
1208 G_VARIANT_TYPE_INT16, seq.getConstArray(),
1209 seq.getLength(), sizeof (sal_Int16)));
1210 //TODO: endian-ness?
1211 break;
1213 case TYPE_INT_LIST:
1215 css::uno::Sequence<sal_Int32> seq(
1216 value.get<css::uno::Sequence<sal_Int32>>());
1217 static_assert(
1218 sizeof(sal_Int32) <= sizeof(gsize),
1219 "G_MAXSIZE too small");
1220 static_assert(
1221 sizeof (sal_Int32) == sizeof (gint32), "size mismatch");
1222 v.reset(
1223 g_variant_new_fixed_array(
1224 G_VARIANT_TYPE_INT32, seq.getConstArray(),
1225 seq.getLength(), sizeof (sal_Int32)));
1226 //TODO: endian-ness?
1227 break;
1229 case TYPE_LONG_LIST:
1231 css::uno::Sequence<sal_Int64> seq(
1232 value.get<css::uno::Sequence<sal_Int64>>());
1233 static_assert(
1234 sizeof(sal_Int32) <= sizeof(gsize),
1235 "G_MAXSIZE too small");
1236 static_assert(
1237 sizeof (sal_Int64) == sizeof (gint64), "size mismatch");
1238 v.reset(
1239 g_variant_new_fixed_array(
1240 G_VARIANT_TYPE_INT64, seq.getConstArray(),
1241 seq.getLength(), sizeof (sal_Int64)));
1242 //TODO: endian-ness?
1243 break;
1245 case TYPE_DOUBLE_LIST:
1247 css::uno::Sequence<double> seq(
1248 value.get<css::uno::Sequence<double>>());
1249 static_assert(
1250 sizeof(sal_Int32) <= sizeof(gsize),
1251 "G_MAXSIZE too small");
1252 static_assert(
1253 sizeof (double) == sizeof (gdouble), "size mismatch");
1254 v.reset(
1255 g_variant_new_fixed_array(
1256 G_VARIANT_TYPE_DOUBLE, seq.getConstArray(),
1257 seq.getLength(), sizeof (double)));
1258 //TODO: endian-ness?
1259 break;
1261 case TYPE_STRING_LIST:
1263 const css::uno::Sequence<OUString> seq(
1264 value.get<css::uno::Sequence<OUString>>());
1265 std::vector<GVariant *> vs;
1266 for (OUString const & s : seq) {
1267 children.emplace_front(
1268 g_variant_new_string(encodeString(s).getStr()));
1269 if (children.front().get() == nullptr) {
1270 SAL_WARN(
1271 "configmgr.dconf", "g_variant_new_string failed");
1272 return false;
1274 vs.push_back(children.front().get());
1276 static_assert(
1277 sizeof(sal_Int32) <= sizeof(gsize),
1278 "G_MAXSIZE too small");
1279 v.reset(
1280 g_variant_new_array(
1281 G_VARIANT_TYPE_STRING, vs.data(), seq.getLength()));
1282 break;
1284 case TYPE_HEXBINARY_LIST:
1286 const css::uno::Sequence<css::uno::Sequence<sal_Int8>> seqSeq(
1287 value.get<
1288 css::uno::Sequence<css::uno::Sequence<sal_Int8>>>());
1289 std::vector<GVariant *> vs;
1290 for (css::uno::Sequence<sal_Int8> const & seq : seqSeq) {
1291 static_assert(
1292 sizeof(sal_Int32) <= sizeof(gsize),
1293 "G_MAXSIZE too small");
1294 static_assert(
1295 sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
1296 children.emplace_front(
1297 g_variant_new_fixed_array(
1298 G_VARIANT_TYPE_BYTE, seq.getConstArray(),
1299 seq.getLength(), sizeof (sal_Int8)));
1300 if (children.front().get() == nullptr) {
1301 SAL_WARN(
1302 "configmgr.dconf",
1303 "g_variant_new_fixed_array failed");
1304 return false;
1306 vs.push_back(children.front().get());
1308 GVariantTypeHolder ty(g_variant_type_new("aay"));
1309 if (ty.get() == nullptr) {
1310 SAL_WARN("configmgr.dconf", "g_variant_type_new failed");
1311 return false;
1313 static_assert(
1314 sizeof(sal_Int32) <= sizeof(gsize),
1315 "G_MAXSIZE too small");
1316 v.reset(
1317 g_variant_new_array(ty.get(), vs.data(), seqSeq.getLength()));
1318 break;
1320 default:
1321 assert(false); // this cannot happen
1322 break;
1324 if (v.get() == nullptr) {
1325 SAL_WARN("configmgr.dconf", "GVariant creation failed");
1326 return false;
1328 if (nillable) {
1329 GVariantHolder v1(g_variant_new_maybe(nullptr, v.get()));
1330 if (v1.get() == nullptr) {
1331 SAL_WARN("configmgr.dconf", "g_variant_new_maybe failed");
1332 return false;
1334 v.release();
1335 v.reset(v1.get());
1336 v1.release();
1339 dconf_changeset_set(
1340 changeset.get(), pathRepresentation.getStr(), v.get());
1341 for (auto & i: children) {
1342 i.release();
1344 v.release();
1345 return true;
1348 bool addNode(
1349 Components & components, ChangesetHolder const & changeset,
1350 rtl::Reference<Node> const & parent, OString const & pathRepresentation,
1351 rtl::Reference<Node> const & node)
1353 switch (node->kind()) {
1354 case Node::KIND_PROPERTY:
1356 PropertyNode * prop = static_cast<PropertyNode *>(node.get());
1357 if (!addProperty(
1358 changeset, pathRepresentation, prop->getStaticType(),
1359 prop->isNillable(), prop->getValue(components)))
1361 return false;
1363 break;
1365 case Node::KIND_LOCALIZED_VALUE:
1367 //TODO: name.isEmpty()?
1368 LocalizedPropertyNode * locprop
1369 = static_cast<LocalizedPropertyNode *>(parent.get());
1370 if (!addProperty(
1371 changeset, pathRepresentation,
1372 locprop->getStaticType(), locprop->isNillable(),
1373 static_cast<LocalizedValueNode *>(node.get())->getValue()))
1375 return false;
1377 break;
1379 case Node::KIND_LOCALIZED_PROPERTY:
1380 case Node::KIND_GROUP:
1381 case Node::KIND_SET:
1382 for (auto const & i: node->getMembers()) {
1383 OUString templ(i.second->getTemplateName());
1384 OString path(
1385 pathRepresentation + "/"
1386 + encodeSegment(i.first, !templ.isEmpty()));
1387 if (!templ.isEmpty()) {
1388 path += "/";
1389 GVariantHolder v(g_variant_new_string("replace"));
1390 if (v.get() == nullptr) {
1391 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1392 return false;
1394 dconf_changeset_set(
1395 changeset.get(), OString(path + "op").getStr(), v.get());
1396 v.release();
1397 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1398 if (v.get() == nullptr) {
1399 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1400 return false;
1402 dconf_changeset_set(
1403 changeset.get(), OString(path + "template").getStr(),
1404 v.get());
1405 v.release();
1406 path += "content";
1408 if (!addNode(components, changeset, parent, path, i.second)) {
1409 return false;
1412 break;
1413 case Node::KIND_ROOT:
1414 assert(false); // this cannot happen
1415 break;
1417 return true;
1420 bool addModifications(
1421 Components & components, ChangesetHolder const & changeset,
1422 OString const & parentPathRepresentation,
1423 rtl::Reference<Node> const & parent, OUString const & nodeName,
1424 rtl::Reference<Node> const & node,
1425 Modifications::Node const & modifications)
1427 // It is never necessary to write oor:finalized or oor:mandatory attributes,
1428 // as they cannot be set via the UNO API.
1429 if (modifications.children.empty()) {
1430 assert(parent.is());
1431 // components themselves have no parent but must have children
1432 if (node.is()) {
1433 OUString templ(node->getTemplateName());
1434 OString path(
1435 parentPathRepresentation + "/"
1436 + encodeSegment(nodeName, !templ.isEmpty()));
1437 if (!templ.isEmpty()) {
1438 path += "/";
1439 GVariantHolder v(g_variant_new_string("replace"));
1440 if (v.get() == nullptr) {
1441 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1442 return false;
1444 dconf_changeset_set(
1445 changeset.get(), OString(path + "op").getStr(), v.get());
1446 v.release();
1447 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1448 if (v.get() == nullptr) {
1449 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1450 return false;
1452 dconf_changeset_set(
1453 changeset.get(), OString(path + "template").getStr(),
1454 v.get());
1455 v.release();
1456 path += "content";
1458 if (!addNode(components, changeset, parent, path, node)) {
1459 return false;
1461 } else {
1462 switch (parent->kind()) {
1463 case Node::KIND_LOCALIZED_PROPERTY:
1464 case Node::KIND_GROUP:
1466 GVariantHolder v(g_variant_new_tuple(nullptr, 0));
1467 if (v.get() == nullptr) {
1468 SAL_WARN(
1469 "configmgr.dconf", "g_variant_new_tuple failed");
1470 return false;
1472 OString path(parentPathRepresentation);
1473 if (!nodeName.isEmpty()) { // KIND_LOCALIZED_PROPERTY
1474 path += "/" + encodeSegment(nodeName, false);
1476 dconf_changeset_set(
1477 changeset.get(), path.getStr(), v.get());
1478 v.release();
1479 break;
1481 case Node::KIND_SET:
1483 OString path(
1484 parentPathRepresentation + "/"
1485 + encodeSegment(nodeName, true) + "/");
1486 GVariantHolder v(g_variant_new_string("remove"));
1487 if (v.get() == nullptr) {
1488 SAL_WARN(
1489 "configmgr.dconf", "g_variant_new_string failed");
1490 return false;
1492 dconf_changeset_set(
1493 changeset.get(), OString(path + "op").getStr(),
1494 v.get());
1495 v.release();
1496 dconf_changeset_set(
1497 changeset.get(), OString(path + "template").getStr(),
1498 nullptr);
1499 dconf_changeset_set(
1500 changeset.get(), OString(path + "content/").getStr(),
1501 nullptr);
1502 break;
1504 default:
1505 assert(false); // this cannot happen
1506 break;
1509 } else {
1510 assert(node.is());
1511 OUString templ(node->getTemplateName());
1512 OString path(
1513 parentPathRepresentation + "/"
1514 + encodeSegment(nodeName, !templ.isEmpty()));
1515 if (!templ.isEmpty()) {
1516 path += "/";
1517 GVariantHolder v(g_variant_new_string("fuse"));
1518 if (v.get() == nullptr) {
1519 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1520 return false;
1522 dconf_changeset_set(
1523 changeset.get(), OString(path + "op").getStr(), v.get());
1524 v.release();
1525 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1526 if (v.get() == nullptr) {
1527 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1528 return false;
1530 dconf_changeset_set(
1531 changeset.get(), OString(path + "template").getStr(), v.get());
1532 v.release();
1533 path += "content";
1535 for (auto const & i: modifications.children) {
1536 if (!addModifications(
1537 components, changeset, path, node, i.first,
1538 node->getMember(i.first), i.second))
1540 return false;
1544 return true;
1549 void readLayer(Data & data, int layer) {
1550 GObjectHolder<DConfClient> client(dconf_client_new());
1551 if (client.get() == nullptr) {
1552 SAL_WARN("configmgr.dconf", "dconf_client_new failed");
1553 return;
1555 readDir(
1556 data, layer, rtl::Reference<Node>(), data.getComponents(), client,
1557 getRoot() + "/");
1560 void writeModifications(Components & components, Data & data) {
1561 GObjectHolder<DConfClient> client(dconf_client_new());
1562 if (client.get() == nullptr) {
1563 SAL_WARN("configmgr.dconf", "dconf_client_new failed");
1565 ChangesetHolder cs(dconf_changeset_new());
1566 if (cs.get() == nullptr) {
1567 SAL_WARN("configmgr.dconf", "dconf_changeset_new failed");
1568 return;
1570 for (auto const & i: data.modifications.getRoot().children) {
1571 if (!addModifications(
1572 components, cs, getRoot(), rtl::Reference<Node>(), i.first,
1573 data.getComponents().findNode(Data::NO_LAYER, i.first),
1574 i.second))
1576 return;
1579 if (!dconf_client_change_sync(
1580 client.get(), cs.get(), nullptr, nullptr, nullptr))
1582 //TODO: GError
1583 SAL_WARN("configmgr.dconf", "dconf_client_change_sync failed");
1584 return;
1586 data.modifications.clear();
1591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */