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
19#include <dconf/dconf.h>
20
21#include <com/sun/star/uno/Sequence.hxx>
22#include <o3tl/safeint.hxx>
23#include <rtl/ustrbuf.hxx>
24#include <sal/log.hxx>
25
26#include "data.hxx"
27#include "dconf.hxx"
28#include "groupnode.hxx"
31#include "nodemap.hxx"
32#include "propertynode.hxx"
33#include "setnode.hxx"
34
35// component-data is encoded in dconf as follows:
36//
37// * The node hierarchy (starting at component nodes with names like
38// "org.openoffice.Setup") maps to dconf paths underneath
39// "/org/libreoffice/registry/".
40//
41// * Component, group, set, and localized property nodes map to dconf dirs,
42// while property and localized value nodes map to dconf keys.
43//
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 :-)"?)
50//
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".
56//
57// * Set elements (which must themselves be either sets or groups) map to
58// "indirection" dconf dirs as follows:
59//
60// ** The dir must contain a key named "op" of string type, with a value of
61// "fuse", "replace", or "remove".
62//
63// ** If "op" is "fuse" or "replace", the dir must contain exactly the following
64// further keys and dirs:
65//
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".
70//
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.
73//
74// ** If "op" is "remove", the dir must contain no further keys or dirs.
75//
76// * Property and localized property value "fuse" operations map to GVariant
77// instances as follows:
78//
79// ** Non-nillable boolean values map to GVariant boolean instances.
80//
81// ** Non-nillable short values map to GVariant int16 instances.
82//
83// ** Non-nillable int values map to GVariant int32 instances.
84//
85// ** Non-nillable long values map to GVariant int64 instances.
86//
87// ** Non-nillable double values map to GVariant double instances.
88//
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".
93//
94// ** Non-nillable hexbinary values map to GVariant byte array instances.
95//
96// ** Non-nillable list values recursively map to GVariant array instances.
97//
98// ** Nillable values recursively map to GVariant maybe instances.
99//
100// * Property "remove" operations map to GVariant instances of empty tuple type.
101//
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.
107//
108// TODO: support "mandatory" and "external"?
109
111
112namespace {
113
114template<typename T> class GObjectHolder {
115public:
116 explicit GObjectHolder(T * object): object_(object) {}
117
118 ~GObjectHolder() {
119 if (object_ != nullptr) {
120 g_object_unref(object_);
121 }
122 }
123
124 T * get() const { return object_; }
125
126private:
127 GObjectHolder(GObjectHolder const &) = delete;
128 GObjectHolder& operator =(GObjectHolder const &) = delete;
129
131};
132
133class GVariantHolder {
134public:
135 explicit GVariantHolder(GVariant * variant = nullptr): variant_(variant) {}
136
137 ~GVariantHolder() { unref(); }
138
139 void reset(GVariant * variant) {
140 unref();
141 variant_ = variant;
142 }
143
144 void release() { variant_ = nullptr; }
145
146 GVariant * get() const { return variant_; }
147
148private:
149 GVariantHolder(GVariantHolder const &) = delete;
150 GVariantHolder& operator =(GVariantHolder const &) = delete;
151
152 void unref() {
153 if (variant_ != nullptr) {
154 g_variant_unref(variant_);
155 }
156 }
157
158 GVariant * variant_;
159};
160
161class GVariantTypeHolder {
162public:
163 explicit GVariantTypeHolder(GVariantType * type): type_(type) {}
164
165 ~GVariantTypeHolder() {
166 if (type_ != nullptr) {
167 g_variant_type_free(type_);
168 }
169 }
170
171 GVariantType * get() const { return type_; }
172
173private:
174 GVariantTypeHolder(GVariantTypeHolder const &) = delete;
175 GVariantTypeHolder& operator =(GVariantTypeHolder const &) = delete;
176
177 GVariantType * type_;
178};
179
180class StringArrayHolder {
181public:
182 explicit StringArrayHolder(gchar ** array): array_(array) {}
183
184 ~StringArrayHolder() { g_strfreev(array_); }
185
186 gchar ** get() const { return array_; }
187
188private:
189 StringArrayHolder(StringArrayHolder const &) = delete;
190 StringArrayHolder& operator =(StringArrayHolder const &) = delete;
191
192 gchar ** array_;
193};
194
195class ChangesetHolder {
196public:
197 explicit ChangesetHolder(DConfChangeset * changeset):
198 changeset_(changeset)
199 {}
200
201 ~ChangesetHolder() {
202 if (changeset_ != nullptr) {
203 dconf_changeset_unref(changeset_);
204 }
205 }
206
207 DConfChangeset * get() const { return changeset_; }
208
209private:
210 ChangesetHolder(ChangesetHolder const &) = delete;
211 ChangesetHolder& operator =(ChangesetHolder const &) = delete;
212
213 DConfChangeset * changeset_;
214};
215
216OString getRoot() {
217 return "/org/libreoffice/registry";
218}
219
220bool decode(OUString * string, bool slash) {
221 for (sal_Int32 i = 0;; ++i) {
222 i = string->indexOf('\\', i);
223 if (i == -1) {
224 return true;
225 }
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;
235 }
236 }
237}
238
239bool getBoolean(
240 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
241{
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;
248 }
249 *value <<= bool(g_variant_get_boolean(variant.get()));
250 return true;
251}
252
253bool getShort(
254 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
255{
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;
262 }
263 *value <<= sal_Int16(g_variant_get_int16(variant.get()));
264 return true;
265}
266
267bool getInt(
268 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
269{
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;
276 }
277 *value <<= sal_Int32(g_variant_get_int32(variant.get()));
278 return true;
279}
280
281bool getLong(
282 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
283{
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;
290 }
291 *value <<= sal_Int64(g_variant_get_int64(variant.get()));
292 return true;
293}
294
295bool getDouble(
296 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
297{
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;
304 }
305 *value <<= double(g_variant_get_double(variant.get()));
306 return true;
307}
308
309bool getStringValue(
310 OString const & key, GVariantHolder const & variant, OUString * value)
311{
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;
318 }
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()))
323 {
324 SAL_WARN("configmgr.dconf", "too long string value for key " << key);
325 return false;
326 }
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)))
332 {
333 SAL_WARN("configmgr.dconf", "non--UTF-8 string value for key " << key);
334 return false;
335 }
336 return decode(value, false);
337}
338
339bool getString(
340 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
341{
342 assert(value != nullptr);
343 OUString v;
344 if (!getStringValue(key, variant, &v)) {
345 return false;
346 }
347 *value <<= v;
348 return true;
349}
350
351bool getHexbinaryValue(
352 OString const & key, GVariantHolder const & variant,
353 css::uno::Sequence<sal_Int8> * value)
354{
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;
361 }
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()))
367 {
368 SAL_WARN("configmgr.dconf", "too long hexbinary value for key " << key);
369 return false;
370 }
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;
376}
377
378bool getHexbinary(
379 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
380{
381 assert(value != nullptr);
382 css::uno::Sequence<sal_Int8> v;
383 if (!getHexbinaryValue(key, variant, &v)) {
384 return false;
385 }
386 *value <<= v;
387 return true;
388}
389
390bool getBooleanList(
391 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
392{
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;
399 }
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()))
405 {
406 SAL_WARN("configmgr.dconf", "too long boolean list for key " << key);
407 return false;
408 }
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;
415}
416
417bool getShortList(
418 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
419{
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;
426 }
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()))
432 {
433 SAL_WARN("configmgr.dconf", "too long short list for key " << key);
434 return false;
435 }
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;
442}
443
444bool getIntList(
445 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
446{
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;
453 }
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()))
459 {
460 SAL_WARN("configmgr.dconf", "too long int list for key " << key);
461 return false;
462 }
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;
469}
470
471bool getLongList(
472 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
473{
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;
480 }
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()))
486 {
487 SAL_WARN("configmgr.dconf", "too long long list for key " << key);
488 return false;
489 }
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;
496}
497
498bool getDoubleList(
499 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
500{
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;
507 }
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()))
513 {
514 SAL_WARN("configmgr.dconf", "too long double list for key " << key);
515 return false;
516 }
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;
523}
524
525bool getStringList(
526 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
527{
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;
534 }
535 gsize n = g_variant_n_children(variant.get());
536 if (n > o3tl::make_unsigned(
537 std::numeric_limits<sal_Int32>::max()))
538 {
539 SAL_WARN("configmgr.dconf", "too long string list for key " << key);
540 return false;
541 }
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;
547 }
548 }
549 *value <<= v;
550 return true;
551}
552
553bool getHexbinaryList(
554 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
555{
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;
562 }
563 gsize n = g_variant_n_children(variant.get());
564 if (n > o3tl::make_unsigned(
565 std::numeric_limits<sal_Int32>::max()))
566 {
567 SAL_WARN("configmgr.dconf", "too long hexbinary list for key " << key);
568 return false;
569 }
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;
576 }
577 }
578 *value <<= v;
579 return true;
580}
581
582bool getAny(
583 OString const & key, GVariantHolder const & variant, css::uno::Any * value)
584{
585 char const * t = g_variant_get_type_string(variant.get());
586 if (std::strcmp(t, "b") == 0) {
587 return getBoolean(key, variant, value);
588 }
589 if (std::strcmp(t, "n") == 0) {
590 return getShort(key, variant, value);
591 }
592 if (std::strcmp(t, "i") == 0) {
593 return getInt(key, variant, value);
594 }
595 if (std::strcmp(t, "x") == 0) {
596 return getLong(key, variant, value);
597 }
598 if (std::strcmp(t, "d") == 0) {
599 return getDouble(key, variant, value);
600 }
601 if (std::strcmp(t, "s") == 0) {
602 return getString(key, variant, value);
603 }
604 if (std::strcmp(t, "ay") == 0) {
605 return getHexbinary(key, variant, value);
606 }
607 if (std::strcmp(t, "ab") == 0) {
608 return getBooleanList(key, variant, value);
609 }
610 if (std::strcmp(t, "an") == 0) {
611 return getShortList(key, variant, value);
612 }
613 if (std::strcmp(t, "ai") == 0) {
614 return getIntList(key, variant, value);
615 }
616 if (std::strcmp(t, "ax") == 0) {
617 return getLongList(key, variant, value);
618 }
619 if (std::strcmp(t, "ad") == 0) {
620 return getDoubleList(key, variant, value);
621 }
622 if (std::strcmp(t, "as") == 0) {
623 return getStringList(key, variant, value);
624 }
625 if (std::strcmp(t, "aay") == 0) {
626 return getHexbinaryList(key, variant, value);
627 }
628 SAL_WARN(
629 "configmgr.dconf", "bad key " << key << " does not match any property");
630 return false;
631}
632
633enum class ReadValue { Error, Value, Remove };
634
635ReadValue readValue(
636 GObjectHolder<DConfClient> const & client, OString const & path, Type type,
637 bool nillable, bool removable, css::uno::Any * value)
638{
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;
646 }
647 if (removable && std::strcmp(g_variant_get_type_string(v.get()), "()") == 0)
648 {
649 return ReadValue::Remove;
650 }
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");
657 }
658 v.reset(g_variant_get_maybe(v.get()));
659 nil = v.get() == nullptr;
660 } else {
661 nil = false;
662 }
663 if (!nil) {
664 switch (type) {
665 case TYPE_ANY:
666 if (!getAny(path, v, value)) {
667 return ReadValue::Error;
668 }
669 break;
670 case TYPE_BOOLEAN:
671 if (!getBoolean(path, v, value)) {
672 return ReadValue::Error;
673 }
674 break;
675 case TYPE_SHORT:
676 if (!getShort(path, v, value)) {
677 return ReadValue::Error;
678 }
679 break;
680 case TYPE_INT:
681 if (!getInt(path, v, value)) {
682 return ReadValue::Error;
683 }
684 break;
685 case TYPE_LONG:
686 if (!getLong(path, v, value)) {
687 return ReadValue::Error;
688 }
689 break;
690 case TYPE_DOUBLE:
691 if (!getDouble(path, v, value)) {
692 return ReadValue::Error;
693 }
694 break;
695 case TYPE_STRING:
696 if (!getString(path, v, value)) {
697 return ReadValue::Error;
698 }
699 break;
700 case TYPE_HEXBINARY:
701 if (!getHexbinary(path, v, value)) {
702 return ReadValue::Error;
703 }
704 break;
706 if (!getBooleanList(path, v, value)) {
707 return ReadValue::Error;
708 }
709 break;
710 case TYPE_SHORT_LIST:
711 if (!getShortList(path, v, value)) {
712 return ReadValue::Error;
713 }
714 break;
715 case TYPE_INT_LIST:
716 if (!getIntList(path, v, value)) {
717 return ReadValue::Error;
718 }
719 break;
720 case TYPE_LONG_LIST:
721 if (!getLongList(path, v, value)) {
722 return ReadValue::Error;
723 }
724 break;
725 case TYPE_DOUBLE_LIST:
726 if (!getDoubleList(path, v, value)) {
727 return ReadValue::Error;
728 }
729 break;
730 case TYPE_STRING_LIST:
731 if (!getStringList(path, v, value)) {
732 return ReadValue::Error;
733 }
734 break;
736 if (!getHexbinaryList(path, v, value)) {
737 return ReadValue::Error;
738 }
739 break;
740 default:
741 assert(false); // cannot happen
742 }
743 }
744 return ReadValue::Value;
745}
746
747void finalize(
748 GObjectHolder<DConfClient> const & client, OString const & path,
749 rtl::Reference<Node> const & node, int layer)
750{
751 if (!dconf_client_is_writable(client.get(), path.getStr())) {
752 node->setFinalized(layer);
753 }
754}
755
756void readDir(
757 Data & data, int layer, rtl::Reference<Node> const & node,
758 NodeMap & members, GObjectHolder<DConfClient> const & client,
759 OString const & dir)
760{
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()))
766 {
767 SAL_WARN("configmgr.dconf", "too long dir/key in dir " << dir);
768 continue;
769 }
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)))
778 {
779 SAL_WARN("configmgr.dconf", "non--UTF-8 dir/key in dir " << dir);
780 continue;
781 }
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;
792 }
793 if (!decode(&name, true)) {
794 continue;
795 }
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;
812 }
813 OUString ops;
814 if (!getStringValue(path2, v, &ops)) {
815 bad = true;
816 break;
817 }
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;
830 }
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;
840 }
841 if (!getStringValue(path2, v, &templ)) {
842 bad = true;
843 break;
844 }
845 if (!static_cast<SetNode *>(node.get())->
846 isValidTemplate(templ))
847 {
848 SAL_WARN(
849 "configmgr.dconf",
850 "bad key " << path2 << " value " << templ
851 << " denotes unsupported set element template");
852 bad = true;
853 break;
854 }
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;
864 }
865 }
866 if (bad) {
867 continue;
868 }
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;
885 }
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;
898 }
899 remove = true;
900 replace = false;
901 break;
902 }
903 } else {
904 remove = false;
905 replace = false;
906 }
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;
914 }
915 switch (node->kind()) {
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;
923 }
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;
937 }
938 member = member->clone(true);
939 break;
940 default:
941 assert(false); // cannot happen
942 }
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;
950 }
951 }
952 if (member.is()) {
953 if (member->getFinalized() < layer) {
954 continue;
955 }
956 switch (member->kind()) {
958 {
959 if (isDir) {
960 SAL_WARN(
961 "configmgr.dconf",
962 "bad dir " << path << " does not match property");
963 continue;
964 }
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))
972 {
973 case ReadValue::Error:
974 continue;
975 case ReadValue::Value:
976 prop->setValue(layer, value);
977 finalize(client, path, member, layer);
978 break;
979 case ReadValue::Remove:
980 remove = true;
981 break;
982 }
983 break;
984 }
986 {
987 if (isDir) {
988 SAL_WARN(
989 "configmgr.dconf",
990 "bad dir " << path
991 << " does not match localized value");
992 continue;
993 }
994 assert(
995 node.is()
996 && node->kind() == Node::KIND_LOCALIZED_PROPERTY);
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)
1004 {
1005 continue;
1006 }
1007 static_cast<LocalizedValueNode *>(member.get())->setValue(
1008 layer, value);
1009 finalize(client, path, member, layer);
1010 break;
1011 }
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;
1022 }
1023 assert(path.endsWith("/"));
1024 readDir(
1025 data, layer, member, member->getMembers(), client, path);
1026 break;
1027 default:
1028 assert(false); // cannot happen
1029 }
1030 }
1031 if (remove) {
1032 if (!(member.is() && member->getMandatory())) {
1033 members.erase(name);
1034 }
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));
1040 }
1041 }
1042}
1043
1044OString encodeSegment(OUString const & name, bool setElement) {
1045 if (!setElement) {
1046 return name.toUtf8();
1047 }
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);
1063 }
1064 }
1065 return buf.makeStringAndClear().toUtf8();
1066}
1067
1068OString 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);
1081 }
1082 }
1083 return buf.makeStringAndClear().toUtf8();
1084}
1085
1086bool addProperty(
1087 ChangesetHolder const & changeset, OString const & pathRepresentation,
1088 Type type, bool nillable, css::uno::Any const & value)
1089{
1090 Type dynType = getDynamicType(value);
1091 assert(dynType != TYPE_ERROR);
1092 if (type == TYPE_ANY) {
1093 type = dynType;
1094 }
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:
1125 {
1126 static char const * const typeString[
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;
1134 }
1135 v.reset(g_variant_new_maybe(ty.get(), nullptr));
1136 break;
1137 }
1138 default:
1139 assert(false); // this cannot happen
1140 break;
1141 }
1142 if (v.get() == nullptr) {
1143 SAL_WARN("configmgr.dconf", "g_variant_new_maybe failed");
1144 return false;
1145 }
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:
1169 {
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;
1182 }
1183 case TYPE_BOOLEAN_LIST:
1184 {
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;
1196 }
1197 case TYPE_SHORT_LIST:
1198 {
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;
1212 }
1213 case TYPE_INT_LIST:
1214 {
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;
1228 }
1229 case TYPE_LONG_LIST:
1230 {
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;
1244 }
1245 case TYPE_DOUBLE_LIST:
1246 {
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;
1260 }
1261 case TYPE_STRING_LIST:
1262 {
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;
1273 }
1274 vs.push_back(children.front().get());
1275 }
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;
1283 }
1285 {
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;
1305 }
1306 vs.push_back(children.front().get());
1307 }
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;
1312 }
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;
1319 }
1320 default:
1321 assert(false); // this cannot happen
1322 break;
1323 }
1324 if (v.get() == nullptr) {
1325 SAL_WARN("configmgr.dconf", "GVariant creation failed");
1326 return false;
1327 }
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;
1333 }
1334 v.release();
1335 v.reset(v1.get());
1336 v1.release();
1337 }
1338 }
1339 dconf_changeset_set(
1340 changeset.get(), pathRepresentation.getStr(), v.get());
1341 for (auto & i: children) {
1342 i.release();
1343 }
1344 v.release();
1345 return true;
1346}
1347
1348bool addNode(
1349 Components & components, ChangesetHolder const & changeset,
1350 rtl::Reference<Node> const & parent, OString const & pathRepresentation,
1351 rtl::Reference<Node> const & node)
1352{
1353 switch (node->kind()) {
1355 {
1356 PropertyNode * prop = static_cast<PropertyNode *>(node.get());
1357 if (!addProperty(
1358 changeset, pathRepresentation, prop->getStaticType(),
1359 prop->isNillable(), prop->getValue(components)))
1360 {
1361 return false;
1362 }
1363 break;
1364 }
1366 {
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()))
1374 {
1375 return false;
1376 }
1377 break;
1378 }
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;
1393 }
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;
1401 }
1402 dconf_changeset_set(
1403 changeset.get(), OString(path + "template").getStr(),
1404 v.get());
1405 v.release();
1406 path += "content";
1407 }
1408 if (!addNode(components, changeset, parent, path, i.second)) {
1409 return false;
1410 }
1411 }
1412 break;
1413 case Node::KIND_ROOT:
1414 assert(false); // this cannot happen
1415 break;
1416 }
1417 return true;
1418}
1419
1420bool 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)
1426{
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;
1443 }
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;
1451 }
1452 dconf_changeset_set(
1453 changeset.get(), OString(path + "template").getStr(),
1454 v.get());
1455 v.release();
1456 path += "content";
1457 }
1458 if (!addNode(components, changeset, parent, path, node)) {
1459 return false;
1460 }
1461 } else {
1462 switch (parent->kind()) {
1464 case Node::KIND_GROUP:
1465 {
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;
1471 }
1472 OString path(parentPathRepresentation);
1473 if (!nodeName.isEmpty()) { // KIND_LOCALIZED_PROPERTY
1474 path += "/" + encodeSegment(nodeName, false);
1475 }
1476 dconf_changeset_set(
1477 changeset.get(), path.getStr(), v.get());
1478 v.release();
1479 break;
1480 }
1481 case Node::KIND_SET:
1482 {
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;
1491 }
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;
1503 }
1504 default:
1505 assert(false); // this cannot happen
1506 break;
1507 }
1508 }
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;
1521 }
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;
1529 }
1530 dconf_changeset_set(
1531 changeset.get(), OString(path + "template").getStr(), v.get());
1532 v.release();
1533 path += "content";
1534 }
1535 for (auto const & i: modifications.children) {
1536 if (!addModifications(
1537 components, changeset, path, node, i.first,
1538 node->getMember(i.first), i.second))
1539 {
1540 return false;
1541 }
1542 }
1543 }
1544 return true;
1545}
1546
1547}
1548
1549void 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;
1554 }
1555 readDir(
1556 data, layer, rtl::Reference<Node>(), data.getComponents(), client,
1557 getRoot() + "/");
1558}
1559
1560void 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");
1564 }
1565 ChangesetHolder cs(dconf_changeset_new());
1566 if (cs.get() == nullptr) {
1567 SAL_WARN("configmgr.dconf", "dconf_changeset_new failed");
1568 return;
1569 }
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))
1575 {
1576 return;
1577 }
1578 }
1579 if (!dconf_client_change_sync(
1580 client.get(), cs.get(), nullptr, nullptr, nullptr))
1581 {
1582 //TODO: GError
1583 SAL_WARN("configmgr.dconf", "dconf_client_change_sync failed");
1584 return;
1585 }
1586 data.modifications.clear();
1587}
1588
1589}
1590
1591/* 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:130
GVariantType * type_
Definition: dconf.cxx:177
GVariant * variant_
Definition: dconf.cxx:158
gchar ** array_
Definition: dconf.cxx:192
DConfChangeset * changeset_
Definition: dconf.cxx:213
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:1549
void writeModifications(Components &components, Data &data)
Definition: dconf.cxx:1560
@ 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:294
unsigned char sal_Bool
sal_uInt16 sal_Unicode
signed char sal_Int8
ResultType type
std::vector< uno::Reference< sheet::XSpreadsheetDocument > > Components