LibreOffice Module configmgr (master) 1
dconf.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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 */
9
10#include <sal/config.h>
11
12#include <cassert>
13#include <cstddef>
14#include <cstring>
15#include <forward_list>
16#include <limits>
17#include <vector>
18
19extern "C" {
20 //TODO: <https://bugzilla.gnome.org/show_bug.cgi?id=754245>
21 // "common/dconf-changeset.h etc. lack extern "C" wrapper for C++", fixed on current dconf
22 // master (towards 0.40?) now with
23 // <https://gitlab.gnome.org/GNOME/dconf/-/commit/db3d4df6d1a763698f27b013dc42da8d4ae02639>
24 // "Merge branch 'wip/issue-23' into 'master'"
25#include <dconf/dconf.h>
26}
27
28#include <com/sun/star/uno/Sequence.hxx>
29#include <o3tl/safeint.hxx>
30#include <rtl/ustrbuf.hxx>
31#include <sal/log.hxx>
32
33#include "data.hxx"
34#include "dconf.hxx"
35#include "groupnode.hxx"
38#include "nodemap.hxx"
39#include "propertynode.hxx"
40#include "setnode.hxx"
41
42// component-data is encoded in dconf as follows:
43//
44// * The node hierarchy (starting at component nodes with names like
45// "org.openoffice.Setup") maps to dconf paths underneath
46// "/org/libreoffice/registry/".
47//
48// * Component, group, set, and localized property nodes map to dconf dirs,
49// while property and localized value nodes map to dconf keys.
50//
51// * The names of nodes that are not set elements are used directly as dconf
52// path segments. (The syntax for node names is any non-empty sequences of
53// any Unicode scalar values except U+0000--0008, U+000B--000C, U+000E--001F,
54// U+002F SOLIDUS, and U+FFFE--FFFF. TODO: "<aruiz> sberg, in general I think
55// it'd be nice if you used path separators instead of dots though, they have
56// meaning in dconf/gvdb world :-)"?)
57//
58// * The names of set element nodes are encoded as dconf path segments as
59// follows: each occurrence of U+0000 NULL is replace by the three characters
60// "\00", each occurrence of U+002F SOLIDUS is replaced by the three
61// characters "\2F", and each occurrence of U+005C REVERSE SOLIDUS is replaced
62// by the three characters "\5C".
63//
64// * Set elements (which must themselves be either sets or groups) map to
65// "indirection" dconf dirs as follows:
66//
67// ** The dir must contain a key named "op" of string type, with a value of
68// "fuse", "replace", or "remove".
69//
70// ** If "op" is "fuse" or "replace", the dir must contain exactly the following
71// further keys and dirs:
72//
73// *** The dir must contain a key named "template" of string type, containing
74// the full template name, encoded as follows: each occurrence of U+0000
75// NULL is replace by the three characters "\00" and each occurrence of
76// U+005C REVERSE SOLIDUS is replaced by the three characters "\5C".
77//
78// *** The dir must contain a dir named "content" that contains the set
79// element's (i.e., set or group node's) real content.
80//
81// ** If "op" is "remove", the dir must contain no further keys or dirs.
82//
83// * Property and localized property value "fuse" operations map to GVariant
84// instances as follows:
85//
86// ** Non-nillable boolean values map to GVariant boolean instances.
87//
88// ** Non-nillable short values map to GVariant int16 instances.
89//
90// ** Non-nillable int values map to GVariant int32 instances.
91//
92// ** Non-nillable long values map to GVariant int64 instances.
93//
94// ** Non-nillable double values map to GVariant double instances.
95//
96// ** Non-nillable string values map to GVariant string instances, with the
97// following encoding: each occurrence of U+0000 NULL is replace by the three
98// characters "\00" and each occurrence of U+005C REVERSE SOLIDUS is replaced
99// by the three characters "\5C".
100//
101// ** Non-nillable hexbinary values map to GVariant byte array instances.
102//
103// ** Non-nillable list values recursively map to GVariant array instances.
104//
105// ** Nillable values recursively map to GVariant maybe instances.
106//
107// * Property "remove" operations map to GVariant instances of empty tuple type.
108//
109// Finalization: The component-update.dtd allows for finalization of
110// oor:component-data, node, and prop elements, while dconf allows for locking
111// of individual keys. That does not match, but just mark the individual Node
112// instances that correspond to individual dconf keys as finalized for
113// non-writable dconf keys.
114//
115// TODO: support "mandatory" and "external"?
116
118
119namespace {
120
121template<typename T> class GObjectHolder {
122public:
123 explicit GObjectHolder(T * object): object_(object) {}
124
125 ~GObjectHolder() {
126 if (object_ != nullptr) {
127 g_object_unref(object_);
128 }
129 }
130
131 T * get() const { return object_; }
132
133private:
134 GObjectHolder(GObjectHolder const &) = delete;
135 GObjectHolder& operator =(GObjectHolder const &) = delete;
136
138};
139
140class GVariantHolder {
141public:
142 explicit GVariantHolder(GVariant * variant = nullptr): variant_(variant) {}
143
144 ~GVariantHolder() { unref(); }
145
146 void reset(GVariant * variant) {
147 unref();
148 variant_ = variant;
149 }
150
151 void release() { variant_ = nullptr; }
152
153 GVariant * get() const { return variant_; }
154
155private:
156 GVariantHolder(GVariantHolder const &) = delete;
157 GVariantHolder& operator =(GVariantHolder const &) = delete;
158
159 void unref() {
160 if (variant_ != nullptr) {
161 g_variant_unref(variant_);
162 }
163 }
164
165 GVariant * variant_;
166};
167
168class GVariantTypeHolder {
169public:
170 explicit GVariantTypeHolder(GVariantType * type): type_(type) {}
171
172 ~GVariantTypeHolder() {
173 if (type_ != nullptr) {
174 g_variant_type_free(type_);
175 }
176 }
177
178 GVariantType * get() const { return type_; }
179
180private:
181 GVariantTypeHolder(GVariantTypeHolder const &) = delete;
182 GVariantTypeHolder& operator =(GVariantTypeHolder const &) = delete;
183
184 GVariantType * type_;
185};
186
187class StringArrayHolder {
188public:
189 explicit StringArrayHolder(gchar ** array): array_(array) {}
190
191 ~StringArrayHolder() { g_strfreev(array_); }
192
193 gchar ** get() const { return array_; }
194
195private:
196 StringArrayHolder(StringArrayHolder const &) = delete;
197 StringArrayHolder& operator =(StringArrayHolder const &) = delete;
198
199 gchar ** array_;
200};
201
202class ChangesetHolder {
203public:
204 explicit ChangesetHolder(DConfChangeset * changeset):
205 changeset_(changeset)
206 {}
207
208 ~ChangesetHolder() {
209 if (changeset_ != nullptr) {
210 dconf_changeset_unref(changeset_);
211 }
212 }
213
214 DConfChangeset * get() const { return changeset_; }
215
216private:
217 ChangesetHolder(ChangesetHolder const &) = delete;
218 ChangesetHolder& operator =(ChangesetHolder const &) = delete;
219
220 DConfChangeset * changeset_;
221};
222
223OString getRoot() {
224 return "/org/libreoffice/registry";
225}
226
227bool decode(OUString * string, bool slash) {
228 for (sal_Int32 i = 0;; ++i) {
229 i = string->indexOf('\\', i);
230 if (i == -1) {
231 return true;
232 }
233 if (string->match("00", i + 1)) {
234 *string = string->replaceAt(i, 3, OUStringChar(u'\0'));
235 } else if (slash && string->match("2F", i + 1)) {
236 *string = string->replaceAt(i, 3, u"/");
237 } else if (string->match("5C", i + 1)) {
238 *string = string->replaceAt(i + 1, 2, u"");
239 } else {
240 SAL_WARN("configmgr.dconf", "bad escape in " << *string);
241 return false;
242 }
243 }
244}
245
246bool getBoolean(
247 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
248{
249 assert(value != nullptr);
250 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_BOOLEAN)) {
251 SAL_WARN(
252 "configmgr.dconf",
253 "bad key " << key << " does not match boolean property");
254 return false;
255 }
256 *value <<= bool(g_variant_get_boolean(variant.get()));
257 return true;
258}
259
260bool getShort(
261 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
262{
263 assert(value != nullptr);
264 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT16)) {
265 SAL_WARN(
266 "configmgr.dconf",
267 "bad key " << key << " does not match short property");
268 return false;
269 }
270 *value <<= sal_Int16(g_variant_get_int16(variant.get()));
271 return true;
272}
273
274bool getInt(
275 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
276{
277 assert(value != nullptr);
278 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT32)) {
279 SAL_WARN(
280 "configmgr.dconf",
281 "bad key " << key << " does not match int property");
282 return false;
283 }
284 *value <<= sal_Int32(g_variant_get_int32(variant.get()));
285 return true;
286}
287
288bool getLong(
289 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
290{
291 assert(value != nullptr);
292 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_INT64)) {
293 SAL_WARN(
294 "configmgr.dconf",
295 "bad key " << key << " does not match long property");
296 return false;
297 }
298 *value <<= sal_Int64(g_variant_get_int64(variant.get()));
299 return true;
300}
301
302bool getDouble(
303 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
304{
305 assert(value != nullptr);
306 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_DOUBLE)) {
307 SAL_WARN(
308 "configmgr.dconf",
309 "bad key " << key << " does not match double property");
310 return false;
311 }
312 *value <<= double(g_variant_get_double(variant.get()));
313 return true;
314}
315
316bool getStringValue(
317 OString const & key, GVariantHolder const & variant, OUString * value)
318{
319 assert(value != nullptr);
320 if (!g_variant_is_of_type(variant.get(), G_VARIANT_TYPE_STRING)) {
321 SAL_WARN(
322 "configmgr.dconf",
323 "bad key " << key << " does not match string property");
324 return false;
325 }
326 gsize n;
327 char const * p = g_variant_get_string(variant.get(), &n);
328 if (n > o3tl::make_unsigned(
329 std::numeric_limits<sal_Int32>::max()))
330 {
331 SAL_WARN("configmgr.dconf", "too long string value for key " << key);
332 return false;
333 }
334 if (!rtl_convertStringToUString(
335 &value->pData, p, static_cast<sal_Int32>(n), RTL_TEXTENCODING_UTF8,
336 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
337 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
338 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
339 {
340 SAL_WARN("configmgr.dconf", "non--UTF-8 string value for key " << key);
341 return false;
342 }
343 return decode(value, false);
344}
345
346bool getString(
347 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
348{
349 assert(value != nullptr);
350 OUString v;
351 if (!getStringValue(key, variant, &v)) {
352 return false;
353 }
354 *value <<= v;
355 return true;
356}
357
358bool getHexbinaryValue(
359 OString const & key, GVariantHolder const & variant,
360 css::uno::Sequence<sal_Int8> * value)
361{
362 assert(value != nullptr);
363 if (std::strcmp(g_variant_get_type_string(variant.get()), "ay") != 0) {
364 SAL_WARN(
365 "configmgr.dconf",
366 "bad key " << key << " does not match hexbinary property");
367 return false;
368 }
369 gsize n;
370 gconstpointer p = g_variant_get_fixed_array(
371 variant.get(), &n, sizeof (guchar));
372 if (n > o3tl::make_unsigned(
373 std::numeric_limits<sal_Int32>::max()))
374 {
375 SAL_WARN("configmgr.dconf", "too long hexbinary value for key " << key);
376 return false;
377 }
378 value->realloc(static_cast<sal_Int32>(n));
379 static_assert(sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
380 std::memcpy(value->getArray(), p, n * sizeof (guchar));
381 // assuming that n * sizeof (guchar) is small enough for std::size_t
382 return true;
383}
384
385bool getHexbinary(
386 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
387{
388 assert(value != nullptr);
389 css::uno::Sequence<sal_Int8> v;
390 if (!getHexbinaryValue(key, variant, &v)) {
391 return false;
392 }
393 *value <<= v;
394 return true;
395}
396
397bool getBooleanList(
398 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
399{
400 assert(value != nullptr);
401 if (std::strcmp(g_variant_get_type_string(variant.get()), "ab") != 0) {
402 SAL_WARN(
403 "configmgr.dconf",
404 "bad key " << key << " does not match boolean list property");
405 return false;
406 }
407 gsize n;
408 gconstpointer p = g_variant_get_fixed_array(
409 variant.get(), &n, sizeof (guchar));
410 if (n > o3tl::make_unsigned(
411 std::numeric_limits<sal_Int32>::max()))
412 {
413 SAL_WARN("configmgr.dconf", "too long boolean list for key " << key);
414 return false;
415 }
416 css::uno::Sequence<sal_Bool> v(static_cast<sal_Int32>(n));
417 static_assert(sizeof (sal_Bool) == sizeof (guchar), "size mismatch");
418 std::memcpy(v.getArray(), p, n * sizeof (guchar));
419 // assuming that n * sizeof (guchar) is small enough for std::size_t
420 *value <<= v;
421 return true;
422}
423
424bool getShortList(
425 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
426{
427 assert(value != nullptr);
428 if (std::strcmp(g_variant_get_type_string(variant.get()), "an") != 0) {
429 SAL_WARN(
430 "configmgr.dconf",
431 "bad key " << key << " does not match short list property");
432 return false;
433 }
434 gsize n;
435 gconstpointer p = g_variant_get_fixed_array(
436 variant.get(), &n, sizeof (gint16));
437 if (n > o3tl::make_unsigned(
438 std::numeric_limits<sal_Int32>::max()))
439 {
440 SAL_WARN("configmgr.dconf", "too long short list for key " << key);
441 return false;
442 }
443 css::uno::Sequence<sal_Int16> v(static_cast<sal_Int32>(n));
444 static_assert(sizeof (sal_Int16) == sizeof (gint16), "size mismatch");
445 std::memcpy(v.getArray(), p, n * sizeof (gint16));
446 // assuming that n * sizeof (gint16) is small enough for std::size_t
447 *value <<= v;
448 return true;
449}
450
451bool getIntList(
452 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
453{
454 assert(value != nullptr);
455 if (std::strcmp(g_variant_get_type_string(variant.get()), "ai") != 0) {
456 SAL_WARN(
457 "configmgr.dconf",
458 "bad key " << key << " does not match int list property");
459 return false;
460 }
461 gsize n;
462 gconstpointer p = g_variant_get_fixed_array(
463 variant.get(), &n, sizeof (gint32));
464 if (n > o3tl::make_unsigned(
465 std::numeric_limits<sal_Int32>::max()))
466 {
467 SAL_WARN("configmgr.dconf", "too long int list for key " << key);
468 return false;
469 }
470 css::uno::Sequence<sal_Int32> v(static_cast<sal_Int32>(n));
471 static_assert(sizeof (sal_Int32) == sizeof (gint32), "size mismatch");
472 std::memcpy(v.getArray(), p, n * sizeof (gint32));
473 // assuming that n * sizeof (gint32) is small enough for std::size_t
474 *value <<= v;
475 return true;
476}
477
478bool getLongList(
479 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
480{
481 assert(value != nullptr);
482 if (std::strcmp(g_variant_get_type_string(variant.get()), "ax") != 0) {
483 SAL_WARN(
484 "configmgr.dconf",
485 "bad key " << key << " does not match long list property");
486 return false;
487 }
488 gsize n;
489 gconstpointer p = g_variant_get_fixed_array(
490 variant.get(), &n, sizeof (gint64));
491 if (n > o3tl::make_unsigned(
492 std::numeric_limits<sal_Int32>::max()))
493 {
494 SAL_WARN("configmgr.dconf", "too long long list for key " << key);
495 return false;
496 }
497 css::uno::Sequence<sal_Int64> v(static_cast<sal_Int32>(n));
498 static_assert(sizeof (sal_Int64) == sizeof (gint64), "size mismatch");
499 std::memcpy(v.getArray(), p, n * sizeof (gint64));
500 // assuming that n * sizeof (gint64) is small enough for std::size_t
501 *value <<= v;
502 return true;
503}
504
505bool getDoubleList(
506 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
507{
508 assert(value != nullptr);
509 if (std::strcmp(g_variant_get_type_string(variant.get()), "ad") != 0) {
510 SAL_WARN(
511 "configmgr.dconf",
512 "bad key " << key << " does not match double list property");
513 return false;
514 }
515 gsize n;
516 gconstpointer p = g_variant_get_fixed_array(
517 variant.get(), &n, sizeof (gdouble));
518 if (n > o3tl::make_unsigned(
519 std::numeric_limits<sal_Int32>::max()))
520 {
521 SAL_WARN("configmgr.dconf", "too long double list for key " << key);
522 return false;
523 }
524 css::uno::Sequence<double> v(static_cast<sal_Int32>(n));
525 static_assert(std::is_same<double, gdouble>::value, "type mismatch");
526 std::memcpy(v.getArray(), p, n * sizeof (gdouble));
527 // assuming that n * sizeof (gdouble) is small enough for std::size_t
528 *value <<= v;
529 return true;
530}
531
532bool getStringList(
533 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
534{
535 assert(value != nullptr);
536 if (std::strcmp(g_variant_get_type_string(variant.get()), "as") != 0) {
537 SAL_WARN(
538 "configmgr.dconf",
539 "bad key " << key << " does not match string list property");
540 return false;
541 }
542 gsize n = g_variant_n_children(variant.get());
543 if (n > o3tl::make_unsigned(
544 std::numeric_limits<sal_Int32>::max()))
545 {
546 SAL_WARN("configmgr.dconf", "too long string list for key " << key);
547 return false;
548 }
549 css::uno::Sequence<OUString> v(static_cast<sal_Int32>(n));
550 for (gsize i = 0; i != n; ++i) {
551 GVariantHolder c(g_variant_get_child_value(variant.get(), i));
552 if (!getStringValue(key, c, v.getArray() + i)) {
553 return false;
554 }
555 }
556 *value <<= v;
557 return true;
558}
559
560bool getHexbinaryList(
561 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
562{
563 assert(value != nullptr);
564 if (std::strcmp(g_variant_get_type_string(variant.get()), "aay") != 0) {
565 SAL_WARN(
566 "configmgr.dconf",
567 "bad key " << key << " does not match hexbinary list property");
568 return false;
569 }
570 gsize n = g_variant_n_children(variant.get());
571 if (n > o3tl::make_unsigned(
572 std::numeric_limits<sal_Int32>::max()))
573 {
574 SAL_WARN("configmgr.dconf", "too long hexbinary list for key " << key);
575 return false;
576 }
577 css::uno::Sequence<css::uno::Sequence<sal_Int8>> v(
578 static_cast<sal_Int32>(n));
579 for (gsize i = 0; i != n; ++i) {
580 GVariantHolder c(g_variant_get_child_value(variant.get(), i));
581 if (!getHexbinaryValue(key, c, v.getArray() + i)) {
582 return false;
583 }
584 }
585 *value <<= v;
586 return true;
587}
588
589bool getAny(
590 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
591{
592 char const * t = g_variant_get_type_string(variant.get());
593 if (std::strcmp(t, "b") == 0) {
594 return getBoolean(key, variant, value);
595 }
596 if (std::strcmp(t, "n") == 0) {
597 return getShort(key, variant, value);
598 }
599 if (std::strcmp(t, "i") == 0) {
600 return getInt(key, variant, value);
601 }
602 if (std::strcmp(t, "x") == 0) {
603 return getLong(key, variant, value);
604 }
605 if (std::strcmp(t, "d") == 0) {
606 return getDouble(key, variant, value);
607 }
608 if (std::strcmp(t, "s") == 0) {
609 return getString(key, variant, value);
610 }
611 if (std::strcmp(t, "ay") == 0) {
612 return getHexbinary(key, variant, value);
613 }
614 if (std::strcmp(t, "ab") == 0) {
615 return getBooleanList(key, variant, value);
616 }
617 if (std::strcmp(t, "an") == 0) {
618 return getShortList(key, variant, value);
619 }
620 if (std::strcmp(t, "ai") == 0) {
621 return getIntList(key, variant, value);
622 }
623 if (std::strcmp(t, "ax") == 0) {
624 return getLongList(key, variant, value);
625 }
626 if (std::strcmp(t, "ad") == 0) {
627 return getDoubleList(key, variant, value);
628 }
629 if (std::strcmp(t, "as") == 0) {
630 return getStringList(key, variant, value);
631 }
632 if (std::strcmp(t, "aay") == 0) {
633 return getHexbinaryList(key, variant, value);
634 }
635 SAL_WARN(
636 "configmgr.dconf", "bad key " << key << " does not match any property");
637 return false;
638}
639
640enum class ReadValue { Error, Value, Remove };
641
642ReadValue readValue(
643 GObjectHolder<DConfClient> const & client, OString const & path, Type type,
644 bool nillable, bool removable, css::uno::Any * value)
645{
646 assert(value != nullptr);
647 assert(!value->hasValue());
648 assert(!path.endsWith("/"));
649 GVariantHolder v(dconf_client_read(client.get(), path.getStr()));
650 if (v.get() == nullptr) {
651 SAL_WARN("configmgr.dconf", "cannot read key " << path);
652 return ReadValue::Error;
653 }
654 if (removable && std::strcmp(g_variant_get_type_string(v.get()), "()") == 0)
655 {
656 return ReadValue::Remove;
657 }
658 bool nil;
659 if (nillable) {
660 if (g_variant_classify(v.get()) != G_VARIANT_CLASS_MAYBE) {
661 SAL_WARN(
662 "configmgr.dconf",
663 "bad key " << path << " does not match nillable property");
664 }
665 v.reset(g_variant_get_maybe(v.get()));
666 nil = v.get() == nullptr;
667 } else {
668 nil = false;
669 }
670 if (!nil) {
671 switch (type) {
672 case TYPE_ANY:
673 if (!getAny(path, v, value)) {
674 return ReadValue::Error;
675 }
676 break;
677 case TYPE_BOOLEAN:
678 if (!getBoolean(path, v, value)) {
679 return ReadValue::Error;
680 }
681 break;
682 case TYPE_SHORT:
683 if (!getShort(path, v, value)) {
684 return ReadValue::Error;
685 }
686 break;
687 case TYPE_INT:
688 if (!getInt(path, v, value)) {
689 return ReadValue::Error;
690 }
691 break;
692 case TYPE_LONG:
693 if (!getLong(path, v, value)) {
694 return ReadValue::Error;
695 }
696 break;
697 case TYPE_DOUBLE:
698 if (!getDouble(path, v, value)) {
699 return ReadValue::Error;
700 }
701 break;
702 case TYPE_STRING:
703 if (!getString(path, v, value)) {
704 return ReadValue::Error;
705 }
706 break;
707 case TYPE_HEXBINARY:
708 if (!getHexbinary(path, v, value)) {
709 return ReadValue::Error;
710 }
711 break;
713 if (!getBooleanList(path, v, value)) {
714 return ReadValue::Error;
715 }
716 break;
717 case TYPE_SHORT_LIST:
718 if (!getShortList(path, v, value)) {
719 return ReadValue::Error;
720 }
721 break;
722 case TYPE_INT_LIST:
723 if (!getIntList(path, v, value)) {
724 return ReadValue::Error;
725 }
726 break;
727 case TYPE_LONG_LIST:
728 if (!getLongList(path, v, value)) {
729 return ReadValue::Error;
730 }
731 break;
732 case TYPE_DOUBLE_LIST:
733 if (!getDoubleList(path, v, value)) {
734 return ReadValue::Error;
735 }
736 break;
737 case TYPE_STRING_LIST:
738 if (!getStringList(path, v, value)) {
739 return ReadValue::Error;
740 }
741 break;
743 if (!getHexbinaryList(path, v, value)) {
744 return ReadValue::Error;
745 }
746 break;
747 default:
748 assert(false); // cannot happen
749 }
750 }
751 return ReadValue::Value;
752}
753
754void finalize(
755 GObjectHolder<DConfClient> const & client, OString const & path,
756 rtl::Reference<Node> const & node, int layer)
757{
758 if (!dconf_client_is_writable(client.get(), path.getStr())) {
759 node->setFinalized(layer);
760 }
761}
762
763void readDir(
764 Data & data, int layer, rtl::Reference<Node> const & node,
765 NodeMap & members, GObjectHolder<DConfClient> const & client,
766 OString const & dir)
767{
768 StringArrayHolder a(dconf_client_list(client.get(), dir.getStr(), nullptr));
769 for (char const * const * p = a.get(); *p != nullptr; ++p) {
770 std::size_t n = std::strlen(*p);
771 if (n > o3tl::make_unsigned(
772 std::numeric_limits<sal_Int32>::max()))
773 {
774 SAL_WARN("configmgr.dconf", "too long dir/key in dir " << dir);
775 continue;
776 }
777 OString s(*p, static_cast<sal_Int32>(n));
778 OString path(dir + s);
779 OUString name;
780 if (!rtl_convertStringToUString(
781 &name.pData, s.getStr(), s.getLength(), RTL_TEXTENCODING_UTF8,
782 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
783 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
784 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
785 {
786 SAL_WARN("configmgr.dconf", "non--UTF-8 dir/key in dir " << dir);
787 continue;
788 }
789 bool isDir = name.endsWith("/", &name);
790 OUString templ;
791 bool remove;
792 bool replace;
793 if (node.is() && node->kind() == Node::KIND_SET) {
794 if (!isDir) {
795 SAL_WARN(
796 "configmgr.dconf",
797 "bad key " << path << " does not match set element");
798 continue;
799 }
800 if (!decode(&name, true)) {
801 continue;
802 }
803 enum class Op { None, Fuse, Replace, Remove };
804 Op op = Op::None;
805 bool content = false;
806 bool bad = false;
807 StringArrayHolder a2(
808 dconf_client_list(client.get(), path.getStr(), nullptr));
809 for (char const * const * p2 = a2.get(); *p2 != nullptr; ++p2) {
810 if (std::strcmp(*p2, "op") == 0) {
811 OString path2(path + "op");
812 GVariantHolder v(
813 dconf_client_read(client.get(), path2.getStr()));
814 if (v.get() == nullptr) {
815 SAL_WARN(
816 "configmgr.dconf", "cannot read key " << path2);
817 bad = true;
818 break;
819 }
820 OUString ops;
821 if (!getStringValue(path2, v, &ops)) {
822 bad = true;
823 break;
824 }
825 if (ops == "fuse") {
826 op = Op::Fuse;
827 } else if (ops == "replace") {
828 op = Op::Replace;
829 } else if (ops == "remove") {
830 op = Op::Remove;
831 } else {
832 SAL_WARN(
833 "configmgr.dconf",
834 "bad key " << path2 << " value " << ops);
835 bad = true;
836 break;
837 }
838 } else if (std::strcmp(*p2, "template") == 0) {
839 OString path2(path + "template");
840 GVariantHolder v(
841 dconf_client_read(client.get(), path2.getStr()));
842 if (v.get() == nullptr) {
843 SAL_WARN(
844 "configmgr.dconf", "cannot read key " << path2);
845 bad = true;
846 break;
847 }
848 if (!getStringValue(path2, v, &templ)) {
849 bad = true;
850 break;
851 }
852 if (!static_cast<SetNode *>(node.get())->
853 isValidTemplate(templ))
854 {
855 SAL_WARN(
856 "configmgr.dconf",
857 "bad key " << path2 << " value " << templ
858 << " denotes unsupported set element template");
859 bad = true;
860 break;
861 }
862 } else if (std::strcmp(*p2, "content/") == 0) {
863 content = true;
864 } else {
865 SAL_WARN(
866 "configmgr.dconf",
867 "bad dir/key " << p2
868 << " in set element indirection dir " << path);
869 bad = true;
870 break;
871 }
872 }
873 if (bad) {
874 continue;
875 }
876 switch (op) {
877 default: // case Op::None:
878 SAL_WARN(
879 "configmgr.dconf",
880 "bad set element indirection dir " << path
881 << " missing \"op\" key");
882 continue;
883 case Op::Fuse:
884 case Op::Replace:
885 if (templ.isEmpty() || !content) {
886 SAL_WARN(
887 "configmgr.dconf",
888 "missing \"content\" and/or \"template\" dir/key in "
889 "\"op\" = \"fuse\"/\"remove\" set element"
890 " indirection dir " << path);
891 continue;
892 }
893 path += "content/";
894 remove = false;
895 replace = op == Op::Replace;
896 break;
897 case Op::Remove:
898 if (!templ.isEmpty() || content) {
899 SAL_WARN(
900 "configmgr.dconf",
901 "bad \"content\" and/or \"template\" dir/key in \"op\" "
902 "= \"remove\" set element indirection dir "
903 << path);
904 continue;
905 }
906 remove = true;
907 replace = false;
908 break;
909 }
910 } else {
911 remove = false;
912 replace = false;
913 }
914 rtl::Reference<Node> member(members.findNode(layer, name));
915 bool insert = !member.is();
916 if (!remove) {
917 if (replace || insert) {
918 if (!node.is()) {
919 SAL_WARN("configmgr.dconf", "bad unmatched " << path);
920 continue;
921 }
922 switch (node->kind()) {
924 member.set(new LocalizedValueNode(layer));
925 break;
926 case Node::KIND_GROUP:
927 if (!static_cast<GroupNode *>(node.get())->isExtensible()) {
928 SAL_WARN("configmgr.dconf", "bad unmatched " << path);
929 continue;
930 }
931 member.set(
932 new PropertyNode(
933 layer, TYPE_ANY, true, css::uno::Any(), true));
934 break;
935 case Node::KIND_SET:
936 assert(!templ.isEmpty());
937 member = data.getTemplate(layer, templ);
938 if (!member.is()) {
939 SAL_WARN(
940 "configmgr.dconf",
941 "bad " << path << " denoting undefined template "
942 << templ);
943 continue;
944 }
945 member = member->clone(true);
946 break;
947 default:
948 assert(false); // cannot happen
949 }
950 } else if (!templ.isEmpty() && templ != member->getTemplateName()) {
951 SAL_WARN(
952 "configmgr.dconf",
953 "bad " << path
954 << " denoting set element of non-matching template "
955 << member->getTemplateName());
956 continue;
957 }
958 }
959 if (member.is()) {
960 if (member->getFinalized() < layer) {
961 continue;
962 }
963 switch (member->kind()) {
965 {
966 if (isDir) {
967 SAL_WARN(
968 "configmgr.dconf",
969 "bad dir " << path << " does not match property");
970 continue;
971 }
973 static_cast<PropertyNode *>(member.get()));
974 css::uno::Any value;
975 switch (readValue(
976 client, path, prop->getStaticType(),
977 prop->isNillable(), prop->isExtension(),
978 &value))
979 {
980 case ReadValue::Error:
981 continue;
982 case ReadValue::Value:
983 prop->setValue(layer, value);
984 finalize(client, path, member, layer);
985 break;
986 case ReadValue::Remove:
987 remove = true;
988 break;
989 }
990 break;
991 }
993 {
994 if (isDir) {
995 SAL_WARN(
996 "configmgr.dconf",
997 "bad dir " << path
998 << " does not match localized value");
999 continue;
1000 }
1001 assert(
1002 node.is()
1003 && node->kind() == Node::KIND_LOCALIZED_PROPERTY);
1005 static_cast<LocalizedPropertyNode *>(node.get()));
1006 css::uno::Any value;
1007 if (readValue(
1008 client, path, locProp->getStaticType(),
1009 locProp->isNillable(), false, &value)
1010 == ReadValue::Error)
1011 {
1012 continue;
1013 }
1014 static_cast<LocalizedValueNode *>(member.get())->setValue(
1015 layer, value);
1016 finalize(client, path, member, layer);
1017 break;
1018 }
1020 case Node::KIND_GROUP:
1021 case Node::KIND_SET:
1022 if (!isDir) {
1023 SAL_WARN(
1024 "configmgr.dconf",
1025 "bad key " << path
1026 << " does not match localized property, group, or"
1027 " set, respectively");
1028 continue;
1029 }
1030 assert(path.endsWith("/"));
1031 readDir(
1032 data, layer, member, member->getMembers(), client, path);
1033 break;
1034 default:
1035 assert(false); // cannot happen
1036 }
1037 }
1038 if (remove) {
1039 if (!(member.is() && member->getMandatory())) {
1040 members.erase(name);
1041 }
1042 } else if (replace) {
1043 members.erase(name);
1044 members.insert(NodeMap::value_type(name, member));
1045 } else if (insert) {
1046 members.insert(NodeMap::value_type(name, member));
1047 }
1048 }
1049}
1050
1051OString encodeSegment(OUString const & name, bool setElement) {
1052 if (!setElement) {
1053 return name.toUtf8();
1054 }
1055 OUStringBuffer buf;
1056 for (sal_Int32 i = 0; i != name.getLength(); ++i) {
1057 sal_Unicode c = name[i];
1058 switch (c) {
1059 case '\0':
1060 buf.append("\\00");
1061 break;
1062 case '/':
1063 buf.append("\\2F");
1064 break;
1065 case '\\':
1066 buf.append("\\5C");
1067 break;
1068 default:
1069 buf.append(c);
1070 }
1071 }
1072 return buf.makeStringAndClear().toUtf8();
1073}
1074
1075OString encodeString(OUString const & value) {
1076 OUStringBuffer buf;
1077 for (sal_Int32 i = 0; i != value.getLength(); ++i) {
1078 sal_Unicode c = value[i];
1079 switch (c) {
1080 case '\0':
1081 buf.append("\\00");
1082 break;
1083 case '\\':
1084 buf.append("\\5C");
1085 break;
1086 default:
1087 buf.append(c);
1088 }
1089 }
1090 return buf.makeStringAndClear().toUtf8();
1091}
1092
1093bool addProperty(
1094 ChangesetHolder const & changeset, OString const & pathRepresentation,
1095 Type type, bool nillable, css::uno::Any const & value)
1096{
1097 Type dynType = getDynamicType(value);
1098 assert(dynType != TYPE_ERROR);
1099 if (type == TYPE_ANY) {
1100 type = dynType;
1101 }
1102 GVariantHolder v;
1103 std::forward_list<GVariantHolder> children;
1104 if (dynType == TYPE_NIL) {
1105 switch (type) {
1106 case TYPE_BOOLEAN:
1107 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_BOOLEAN, nullptr));
1108 break;
1109 case TYPE_SHORT:
1110 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT16, nullptr));
1111 break;
1112 case TYPE_INT:
1113 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT32, nullptr));
1114 break;
1115 case TYPE_LONG:
1116 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_INT64, nullptr));
1117 break;
1118 case TYPE_DOUBLE:
1119 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_DOUBLE, nullptr));
1120 break;
1121 case TYPE_STRING:
1122 v.reset(g_variant_new_maybe(G_VARIANT_TYPE_STRING, nullptr));
1123 break;
1124 case TYPE_HEXBINARY:
1125 case TYPE_BOOLEAN_LIST:
1126 case TYPE_SHORT_LIST:
1127 case TYPE_INT_LIST:
1128 case TYPE_LONG_LIST:
1129 case TYPE_DOUBLE_LIST:
1130 case TYPE_STRING_LIST:
1132 {
1133 static char const * const typeString[
1135 = { "ay", "ab", "an", "ai", "ax", "ad", "as", "aay" };
1136 GVariantTypeHolder ty(
1137 g_variant_type_new(typeString[type - TYPE_HEXBINARY]));
1138 if (ty.get() == nullptr) {
1139 SAL_WARN("configmgr.dconf", "g_variant_type_new failed");
1140 return false;
1141 }
1142 v.reset(g_variant_new_maybe(ty.get(), nullptr));
1143 break;
1144 }
1145 default:
1146 assert(false); // this cannot happen
1147 break;
1148 }
1149 if (v.get() == nullptr) {
1150 SAL_WARN("configmgr.dconf", "g_variant_new_maybe failed");
1151 return false;
1152 }
1153 } else {
1154 switch (type) {
1155 case TYPE_BOOLEAN:
1156 v.reset(g_variant_new_boolean(value.get<bool>()));
1157 break;
1158 case TYPE_SHORT:
1159 v.reset(g_variant_new_int16(value.get<sal_Int16>()));
1160 break;
1161 case TYPE_INT:
1162 v.reset(g_variant_new_int32(value.get<sal_Int32>()));
1163 break;
1164 case TYPE_LONG:
1165 v.reset(g_variant_new_int64(value.get<sal_Int64>()));
1166 break;
1167 case TYPE_DOUBLE:
1168 v.reset(g_variant_new_double(value.get<double>()));
1169 break;
1170 case TYPE_STRING:
1171 v.reset(
1172 g_variant_new_string(
1173 encodeString(value.get<OUString>()).getStr()));
1174 break;
1175 case TYPE_HEXBINARY:
1176 {
1177 css::uno::Sequence<sal_Int8> seq(
1178 value.get<css::uno::Sequence<sal_Int8>>());
1179 static_assert(
1180 sizeof(sal_Int32) <= sizeof(gsize),
1181 "G_MAXSIZE too small");
1182 static_assert(
1183 sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
1184 v.reset(
1185 g_variant_new_fixed_array(
1186 G_VARIANT_TYPE_BYTE, seq.getConstArray(),
1187 seq.getLength(), sizeof (sal_Int8)));
1188 break;
1189 }
1190 case TYPE_BOOLEAN_LIST:
1191 {
1192 css::uno::Sequence<sal_Bool> seq(
1193 value.get<css::uno::Sequence<sal_Bool>>());
1194 static_assert(
1195 sizeof(sal_Int32) <= sizeof(gsize),
1196 "G_MAXSIZE too small");
1197 static_assert(sizeof (sal_Bool) == 1, "size mismatch");
1198 v.reset(
1199 g_variant_new_fixed_array(
1200 G_VARIANT_TYPE_BOOLEAN, seq.getConstArray(),
1201 seq.getLength(), sizeof (sal_Bool)));
1202 break;
1203 }
1204 case TYPE_SHORT_LIST:
1205 {
1206 css::uno::Sequence<sal_Int16> seq(
1207 value.get<css::uno::Sequence<sal_Int16>>());
1208 static_assert(
1209 sizeof(sal_Int32) <= sizeof(gsize),
1210 "G_MAXSIZE too small");
1211 static_assert(
1212 sizeof (sal_Int16) == sizeof (gint16), "size mismatch");
1213 v.reset(
1214 g_variant_new_fixed_array(
1215 G_VARIANT_TYPE_INT16, seq.getConstArray(),
1216 seq.getLength(), sizeof (sal_Int16)));
1217 //TODO: endian-ness?
1218 break;
1219 }
1220 case TYPE_INT_LIST:
1221 {
1222 css::uno::Sequence<sal_Int32> seq(
1223 value.get<css::uno::Sequence<sal_Int32>>());
1224 static_assert(
1225 sizeof(sal_Int32) <= sizeof(gsize),
1226 "G_MAXSIZE too small");
1227 static_assert(
1228 sizeof (sal_Int32) == sizeof (gint32), "size mismatch");
1229 v.reset(
1230 g_variant_new_fixed_array(
1231 G_VARIANT_TYPE_INT32, seq.getConstArray(),
1232 seq.getLength(), sizeof (sal_Int32)));
1233 //TODO: endian-ness?
1234 break;
1235 }
1236 case TYPE_LONG_LIST:
1237 {
1238 css::uno::Sequence<sal_Int64> seq(
1239 value.get<css::uno::Sequence<sal_Int64>>());
1240 static_assert(
1241 sizeof(sal_Int32) <= sizeof(gsize),
1242 "G_MAXSIZE too small");
1243 static_assert(
1244 sizeof (sal_Int64) == sizeof (gint64), "size mismatch");
1245 v.reset(
1246 g_variant_new_fixed_array(
1247 G_VARIANT_TYPE_INT64, seq.getConstArray(),
1248 seq.getLength(), sizeof (sal_Int64)));
1249 //TODO: endian-ness?
1250 break;
1251 }
1252 case TYPE_DOUBLE_LIST:
1253 {
1254 css::uno::Sequence<double> seq(
1255 value.get<css::uno::Sequence<double>>());
1256 static_assert(
1257 sizeof(sal_Int32) <= sizeof(gsize),
1258 "G_MAXSIZE too small");
1259 static_assert(
1260 sizeof (double) == sizeof (gdouble), "size mismatch");
1261 v.reset(
1262 g_variant_new_fixed_array(
1263 G_VARIANT_TYPE_DOUBLE, seq.getConstArray(),
1264 seq.getLength(), sizeof (double)));
1265 //TODO: endian-ness?
1266 break;
1267 }
1268 case TYPE_STRING_LIST:
1269 {
1270 const css::uno::Sequence<OUString> seq(
1271 value.get<css::uno::Sequence<OUString>>());
1272 std::vector<GVariant *> vs;
1273 for (OUString const & s : seq) {
1274 children.emplace_front(
1275 g_variant_new_string(encodeString(s).getStr()));
1276 if (children.front().get() == nullptr) {
1277 SAL_WARN(
1278 "configmgr.dconf", "g_variant_new_string failed");
1279 return false;
1280 }
1281 vs.push_back(children.front().get());
1282 }
1283 static_assert(
1284 sizeof(sal_Int32) <= sizeof(gsize),
1285 "G_MAXSIZE too small");
1286 v.reset(
1287 g_variant_new_array(
1288 G_VARIANT_TYPE_STRING, vs.data(), seq.getLength()));
1289 break;
1290 }
1292 {
1293 const css::uno::Sequence<css::uno::Sequence<sal_Int8>> seqSeq(
1294 value.get<
1295 css::uno::Sequence<css::uno::Sequence<sal_Int8>>>());
1296 std::vector<GVariant *> vs;
1297 for (css::uno::Sequence<sal_Int8> const & seq : seqSeq) {
1298 static_assert(
1299 sizeof(sal_Int32) <= sizeof(gsize),
1300 "G_MAXSIZE too small");
1301 static_assert(
1302 sizeof (sal_Int8) == sizeof (guchar), "size mismatch");
1303 children.emplace_front(
1304 g_variant_new_fixed_array(
1305 G_VARIANT_TYPE_BYTE, seq.getConstArray(),
1306 seq.getLength(), sizeof (sal_Int8)));
1307 if (children.front().get() == nullptr) {
1308 SAL_WARN(
1309 "configmgr.dconf",
1310 "g_variant_new_fixed_array failed");
1311 return false;
1312 }
1313 vs.push_back(children.front().get());
1314 }
1315 GVariantTypeHolder ty(g_variant_type_new("aay"));
1316 if (ty.get() == nullptr) {
1317 SAL_WARN("configmgr.dconf", "g_variant_type_new failed");
1318 return false;
1319 }
1320 static_assert(
1321 sizeof(sal_Int32) <= sizeof(gsize),
1322 "G_MAXSIZE too small");
1323 v.reset(
1324 g_variant_new_array(ty.get(), vs.data(), seqSeq.getLength()));
1325 break;
1326 }
1327 default:
1328 assert(false); // this cannot happen
1329 break;
1330 }
1331 if (v.get() == nullptr) {
1332 SAL_WARN("configmgr.dconf", "GVariant creation failed");
1333 return false;
1334 }
1335 if (nillable) {
1336 GVariantHolder v1(g_variant_new_maybe(nullptr, v.get()));
1337 if (v1.get() == nullptr) {
1338 SAL_WARN("configmgr.dconf", "g_variant_new_maybe failed");
1339 return false;
1340 }
1341 v.release();
1342 v.reset(v1.get());
1343 v1.release();
1344 }
1345 }
1346 dconf_changeset_set(
1347 changeset.get(), pathRepresentation.getStr(), v.get());
1348 for (auto & i: children) {
1349 i.release();
1350 }
1351 v.release();
1352 return true;
1353}
1354
1355bool addNode(
1356 Components & components, ChangesetHolder const & changeset,
1357 rtl::Reference<Node> const & parent, OString const & pathRepresentation,
1358 rtl::Reference<Node> const & node)
1359{
1360 switch (node->kind()) {
1362 {
1363 PropertyNode * prop = static_cast<PropertyNode *>(node.get());
1364 if (!addProperty(
1365 changeset, pathRepresentation, prop->getStaticType(),
1366 prop->isNillable(), prop->getValue(components)))
1367 {
1368 return false;
1369 }
1370 break;
1371 }
1373 {
1374 //TODO: name.isEmpty()?
1375 LocalizedPropertyNode * locprop
1376 = static_cast<LocalizedPropertyNode *>(parent.get());
1377 if (!addProperty(
1378 changeset, pathRepresentation,
1379 locprop->getStaticType(), locprop->isNillable(),
1380 static_cast<LocalizedValueNode *>(node.get())->getValue()))
1381 {
1382 return false;
1383 }
1384 break;
1385 }
1387 case Node::KIND_GROUP:
1388 case Node::KIND_SET:
1389 for (auto const & i: node->getMembers()) {
1390 OUString templ(i.second->getTemplateName());
1391 OString path(
1392 pathRepresentation + "/"
1393 + encodeSegment(i.first, !templ.isEmpty()));
1394 if (!templ.isEmpty()) {
1395 path += "/";
1396 GVariantHolder v(g_variant_new_string("replace"));
1397 if (v.get() == nullptr) {
1398 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1399 return false;
1400 }
1401 dconf_changeset_set(
1402 changeset.get(), OString(path + "op").getStr(), v.get());
1403 v.release();
1404 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1405 if (v.get() == nullptr) {
1406 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1407 return false;
1408 }
1409 dconf_changeset_set(
1410 changeset.get(), OString(path + "template").getStr(),
1411 v.get());
1412 v.release();
1413 path += "content";
1414 }
1415 if (!addNode(components, changeset, parent, path, i.second)) {
1416 return false;
1417 }
1418 }
1419 break;
1420 case Node::KIND_ROOT:
1421 assert(false); // this cannot happen
1422 break;
1423 }
1424 return true;
1425}
1426
1427bool addModifications(
1428 Components & components, ChangesetHolder const & changeset,
1429 OString const & parentPathRepresentation,
1430 rtl::Reference<Node> const & parent, OUString const & nodeName,
1431 rtl::Reference<Node> const & node,
1432 Modifications::Node const & modifications)
1433{
1434 // It is never necessary to write oor:finalized or oor:mandatory attributes,
1435 // as they cannot be set via the UNO API.
1436 if (modifications.children.empty()) {
1437 assert(parent.is());
1438 // components themselves have no parent but must have children
1439 if (node.is()) {
1440 OUString templ(node->getTemplateName());
1441 OString path(
1442 parentPathRepresentation + "/"
1443 + encodeSegment(nodeName, !templ.isEmpty()));
1444 if (!templ.isEmpty()) {
1445 path += "/";
1446 GVariantHolder v(g_variant_new_string("replace"));
1447 if (v.get() == nullptr) {
1448 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1449 return false;
1450 }
1451 dconf_changeset_set(
1452 changeset.get(), OString(path + "op").getStr(), v.get());
1453 v.release();
1454 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1455 if (v.get() == nullptr) {
1456 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1457 return false;
1458 }
1459 dconf_changeset_set(
1460 changeset.get(), OString(path + "template").getStr(),
1461 v.get());
1462 v.release();
1463 path += "content";
1464 }
1465 if (!addNode(components, changeset, parent, path, node)) {
1466 return false;
1467 }
1468 } else {
1469 switch (parent->kind()) {
1471 case Node::KIND_GROUP:
1472 {
1473 GVariantHolder v(g_variant_new_tuple(nullptr, 0));
1474 if (v.get() == nullptr) {
1475 SAL_WARN(
1476 "configmgr.dconf", "g_variant_new_tuple failed");
1477 return false;
1478 }
1479 OString path(parentPathRepresentation);
1480 if (!nodeName.isEmpty()) { // KIND_LOCALIZED_PROPERTY
1481 path += "/" + encodeSegment(nodeName, false);
1482 }
1483 dconf_changeset_set(
1484 changeset.get(), path.getStr(), v.get());
1485 v.release();
1486 break;
1487 }
1488 case Node::KIND_SET:
1489 {
1490 OString path(
1491 parentPathRepresentation + "/"
1492 + encodeSegment(nodeName, true) + "/");
1493 GVariantHolder v(g_variant_new_string("remove"));
1494 if (v.get() == nullptr) {
1495 SAL_WARN(
1496 "configmgr.dconf", "g_variant_new_string failed");
1497 return false;
1498 }
1499 dconf_changeset_set(
1500 changeset.get(), OString(path + "op").getStr(),
1501 v.get());
1502 v.release();
1503 dconf_changeset_set(
1504 changeset.get(), OString(path + "template").getStr(),
1505 nullptr);
1506 dconf_changeset_set(
1507 changeset.get(), OString(path + "content/").getStr(),
1508 nullptr);
1509 break;
1510 }
1511 default:
1512 assert(false); // this cannot happen
1513 break;
1514 }
1515 }
1516 } else {
1517 assert(node.is());
1518 OUString templ(node->getTemplateName());
1519 OString path(
1520 parentPathRepresentation + "/"
1521 + encodeSegment(nodeName, !templ.isEmpty()));
1522 if (!templ.isEmpty()) {
1523 path += "/";
1524 GVariantHolder v(g_variant_new_string("fuse"));
1525 if (v.get() == nullptr) {
1526 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1527 return false;
1528 }
1529 dconf_changeset_set(
1530 changeset.get(), OString(path + "op").getStr(), v.get());
1531 v.release();
1532 v.reset(g_variant_new_string(encodeString(templ).getStr()));
1533 if (v.get() == nullptr) {
1534 SAL_WARN("configmgr.dconf", "g_variant_new_string failed");
1535 return false;
1536 }
1537 dconf_changeset_set(
1538 changeset.get(), OString(path + "template").getStr(), v.get());
1539 v.release();
1540 path += "content";
1541 }
1542 for (auto const & i: modifications.children) {
1543 if (!addModifications(
1544 components, changeset, path, node, i.first,
1545 node->getMember(i.first), i.second))
1546 {
1547 return false;
1548 }
1549 }
1550 }
1551 return true;
1552}
1553
1554}
1555
1556void readLayer(Data & data, int layer) {
1557 GObjectHolder<DConfClient> client(dconf_client_new());
1558 if (client.get() == nullptr) {
1559 SAL_WARN("configmgr.dconf", "dconf_client_new failed");
1560 return;
1561 }
1562 readDir(
1563 data, layer, rtl::Reference<Node>(), data.getComponents(), client,
1564 getRoot() + "/");
1565}
1566
1567void writeModifications(Components & components, Data & data) {
1568 GObjectHolder<DConfClient> client(dconf_client_new());
1569 if (client.get() == nullptr) {
1570 SAL_WARN("configmgr.dconf", "dconf_client_new failed");
1571 }
1572 ChangesetHolder cs(dconf_changeset_new());
1573 if (cs.get() == nullptr) {
1574 SAL_WARN("configmgr.dconf", "dconf_changeset_new failed");
1575 return;
1576 }
1577 for (auto const & i: data.modifications.getRoot().children) {
1578 if (!addModifications(
1579 components, cs, getRoot(), rtl::Reference<Node>(), i.first,
1580 data.getComponents().findNode(Data::NO_LAYER, i.first),
1581 i.second))
1582 {
1583 return;
1584 }
1585 }
1586 if (!dconf_client_change_sync(
1587 client.get(), cs.get(), nullptr, nullptr, nullptr))
1588 {
1589 //TODO: GError
1590 SAL_WARN("configmgr.dconf", "dconf_client_change_sync failed");
1591 return;
1592 }
1593 data.modifications.clear();
1594}
1595
1596}
1597
1598/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
Node const & getRoot() const
rtl::Reference< Node > findNode(int layer, OUString const &name) const
Definition: nodemap.cxx:43
NodeMapImpl::value_type value_type
Definition: nodemap.hxx:39
@ KIND_LOCALIZED_PROPERTY
Definition: node.hxx:35
@ KIND_LOCALIZED_VALUE
Definition: node.hxx:35
Any value
OUString name
Definition: components.cxx:85
T * object_
Definition: dconf.cxx:137
GVariantType * type_
Definition: dconf.cxx:184
GVariant * variant_
Definition: dconf.cxx:165
gchar ** array_
Definition: dconf.cxx:199
DConfChangeset * changeset_
Definition: dconf.cxx:220
float v
void * p
sal_Int64 n
uno_Any a
#define SAL_WARN(area, stream)
std::map< const SwTextNode *, const sal_uInt32 > NodeMap
OUStringBuffer & remove(OUStringBuffer &rIn, sal_Unicode c)
double getDouble(const Any &_rAny)
OUString getString(const Any &_rAny)
void readLayer(Data &data, int layer)
Definition: dconf.cxx:1556
void writeModifications(Components &components, Data &data)
Definition: dconf.cxx:1567
@ TYPE_HEXBINARY_LIST
Definition: type.hxx:36
@ TYPE_HEXBINARY
Definition: type.hxx:34
@ TYPE_BOOLEAN
Definition: type.hxx:33
@ TYPE_STRING_LIST
Definition: type.hxx:36
@ TYPE_INT_LIST
Definition: type.hxx:35
@ TYPE_NIL
Definition: type.hxx:33
@ TYPE_ANY
Definition: type.hxx:33
@ TYPE_DOUBLE
Definition: type.hxx:34
@ TYPE_LONG
Definition: type.hxx:34
@ TYPE_BOOLEAN_LIST
Definition: type.hxx:34
@ TYPE_SHORT
Definition: type.hxx:33
@ TYPE_INT
Definition: type.hxx:33
@ TYPE_DOUBLE_LIST
Definition: type.hxx:35
@ TYPE_STRING
Definition: type.hxx:34
@ TYPE_ERROR
Definition: type.hxx:33
@ TYPE_LONG_LIST
Definition: type.hxx:35
@ TYPE_SHORT_LIST
Definition: type.hxx:35
Type getDynamicType(css::uno::Any const &value)
Definition: type.cxx:101
Error
Status finalize()
Value
int i
css::beans::Optional< css::uno::Any > getValue(std::u16string_view id)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
None
Op_< std::function< void(double &, double)>, double > Op
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
OUString encodeSegment(const OUString &rSegment)
PyObject_HEAD PyUNO_callable_Internals * members
RegError REGISTRY_CALLTYPE setValue(RegKeyHandle hKey, rtl_uString *keyName, RegValueType valueType, RegValue pData, sal_uInt32 valueSize)
Modifications modifications
Definition: data.hxx:51
NodeMap & getComponents() const
Definition: data.cxx:293
unsigned char sal_Bool
sal_uInt16 sal_Unicode
signed char sal_Int8
ResultType type
std::vector< uno::Reference< sheet::XSpreadsheetDocument > > Components