1 /*
2 * Copyright © 2010 Novell, Inc.
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Vincent Untz <vuntz@gnome.org>
20 */
21
22 #include "config.h"
23
24 #include "gsettings-mapping.h"
25
26 static GVariant *
27 g_settings_set_mapping_int (const GValue *value,
28 const GVariantType *expected_type)
29 {
30 GVariant *variant = NULL;
31 gint64 l;
32
33 if (G_VALUE_HOLDS_INT (value))
34 l = g_value_get_int (value);
35 else if (G_VALUE_HOLDS_INT64 (value))
36 l = g_value_get_int64 (value);
37 else
38 return NULL;
39
40 if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
41 {
42 if (G_MININT16 <= l && l <= G_MAXINT16)
43 variant = g_variant_new_int16 ((gint16) l);
44 }
45 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
46 {
47 if (0 <= l && l <= G_MAXUINT16)
48 variant = g_variant_new_uint16 ((guint16) l);
49 }
50 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
51 {
52 if (G_MININT32 <= l && l <= G_MAXINT32)
53 variant = g_variant_new_int32 ((gint) l);
54 }
55 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
56 {
57 if (0 <= l && l <= G_MAXUINT32)
58 variant = g_variant_new_uint32 ((guint) l);
59 }
60 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
61 {
62 if (G_MININT64 <= l && l <= G_MAXINT64)
63 variant = g_variant_new_int64 ((gint64) l);
64 }
65 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
66 {
67 if (0 <= l && (guint64) l <= G_MAXUINT64)
68 variant = g_variant_new_uint64 ((guint64) l);
69 }
70 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
71 {
72 if (0 <= l && l <= G_MAXUINT32)
73 variant = g_variant_new_handle ((guint) l);
74 }
75 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
76 variant = g_variant_new_double ((gdouble) l);
77
78 return variant;
79 }
80
81 static GVariant *
82 g_settings_set_mapping_float (const GValue *value,
83 const GVariantType *expected_type)
84 {
85 GVariant *variant = NULL;
86 gdouble d;
87 gint64 l;
88
89 if (G_VALUE_HOLDS_DOUBLE (value))
90 d = g_value_get_double (value);
91 else
92 return NULL;
93
94 l = (gint64) d;
95 if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
96 {
97 if (G_MININT16 <= l && l <= G_MAXINT16)
98 variant = g_variant_new_int16 ((gint16) l);
99 }
100 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
101 {
102 if (0 <= l && l <= G_MAXUINT16)
103 variant = g_variant_new_uint16 ((guint16) l);
104 }
105 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
106 {
107 if (G_MININT32 <= l && l <= G_MAXINT32)
108 variant = g_variant_new_int32 ((gint) l);
109 }
110 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
111 {
112 if (0 <= l && l <= G_MAXUINT32)
113 variant = g_variant_new_uint32 ((guint) l);
114 }
115 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
116 {
117 if (G_MININT64 <= l && l <= G_MAXINT64)
118 variant = g_variant_new_int64 ((gint64) l);
119 }
120 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
121 {
122 if (0 <= l && (guint64) l <= G_MAXUINT64)
123 variant = g_variant_new_uint64 ((guint64) l);
124 }
125 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
126 {
127 if (0 <= l && l <= G_MAXUINT32)
128 variant = g_variant_new_handle ((guint) l);
129 }
130 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
131 variant = g_variant_new_double ((gdouble) d);
132
133 return variant;
134 }
135 static GVariant *
136 g_settings_set_mapping_unsigned_int (const GValue *value,
137 const GVariantType *expected_type)
138 {
139 GVariant *variant = NULL;
140 guint64 u;
141
142 if (G_VALUE_HOLDS_UINT (value))
143 u = g_value_get_uint (value);
144 else if (G_VALUE_HOLDS_UINT64 (value))
145 u = g_value_get_uint64 (value);
146 else
147 return NULL;
148
149 if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
150 {
151 if (u <= G_MAXINT16)
152 variant = g_variant_new_int16 ((gint16) u);
153 }
154 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
155 {
156 if (u <= G_MAXUINT16)
157 variant = g_variant_new_uint16 ((guint16) u);
158 }
159 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
160 {
161 if (u <= G_MAXINT32)
162 variant = g_variant_new_int32 ((gint) u);
163 }
164 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
165 {
166 if (u <= G_MAXUINT32)
167 variant = g_variant_new_uint32 ((guint) u);
168 }
169 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
170 {
171 if (u <= G_MAXINT64)
172 variant = g_variant_new_int64 ((gint64) u);
173 }
174 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
175 {
176 if (u <= G_MAXUINT64)
177 variant = g_variant_new_uint64 ((guint64) u);
178 }
179 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
180 {
181 if (u <= G_MAXUINT32)
182 variant = g_variant_new_handle ((guint) u);
183 }
184 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
185 variant = g_variant_new_double ((gdouble) u);
186
187 return variant;
188 }
189
190 static gboolean
191 g_settings_get_mapping_int (GValue *value,
192 GVariant *variant)
193 {
194 const GVariantType *type;
195 gint64 l;
196
197 type = g_variant_get_type (variant);
198
199 if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
200 l = g_variant_get_int16 (variant);
201 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
202 l = g_variant_get_int32 (variant);
203 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
204 l = g_variant_get_int64 (variant);
205 else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
206 l = g_variant_get_handle (variant);
207 else
208 return FALSE;
209
210 if (G_VALUE_HOLDS_INT (value))
211 {
212 g_value_set_int (value, l);
213 return (G_MININT32 <= l && l <= G_MAXINT32);
214 }
215 else if (G_VALUE_HOLDS_UINT (value))
216 {
217 g_value_set_uint (value, l);
218 return (0 <= l && l <= G_MAXUINT32);
219 }
220 else if (G_VALUE_HOLDS_INT64 (value))
221 {
222 g_value_set_int64 (value, l);
223 return (G_MININT64 <= l && l <= G_MAXINT64);
224 }
225 else if (G_VALUE_HOLDS_UINT64 (value))
226 {
227 g_value_set_uint64 (value, l);
228 return (0 <= l && (guint64) l <= G_MAXUINT64);
229 }
230 else if (G_VALUE_HOLDS_DOUBLE (value))
231 {
232 g_value_set_double (value, l);
233 return TRUE;
234 }
235
236 return FALSE;
237 }
238
239 static gboolean
240 g_settings_get_mapping_float (GValue *value,
241 GVariant *variant)
242 {
243 const GVariantType *type;
244 gdouble d;
245 gint64 l;
246
247 type = g_variant_get_type (variant);
248
249 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
250 d = g_variant_get_double (variant);
251 else
252 return FALSE;
253
254 l = (gint64)d;
255 if (G_VALUE_HOLDS_INT (value))
256 {
257 g_value_set_int (value, l);
258 return (G_MININT32 <= l && l <= G_MAXINT32);
259 }
260 else if (G_VALUE_HOLDS_UINT (value))
261 {
262 g_value_set_uint (value, l);
263 return (0 <= l && l <= G_MAXUINT32);
264 }
265 else if (G_VALUE_HOLDS_INT64 (value))
266 {
267 g_value_set_int64 (value, l);
268 return (G_MININT64 <= l && l <= G_MAXINT64);
269 }
270 else if (G_VALUE_HOLDS_UINT64 (value))
271 {
272 g_value_set_uint64 (value, l);
273 return (0 <= l && (guint64) l <= G_MAXUINT64);
274 }
275 else if (G_VALUE_HOLDS_DOUBLE (value))
276 {
277 g_value_set_double (value, d);
278 return TRUE;
279 }
280
281 return FALSE;
282 }
283 static gboolean
284 g_settings_get_mapping_unsigned_int (GValue *value,
285 GVariant *variant)
286 {
287 const GVariantType *type;
288 guint64 u;
289
290 type = g_variant_get_type (variant);
291
292 if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
293 u = g_variant_get_uint16 (variant);
294 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
295 u = g_variant_get_uint32 (variant);
296 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
297 u = g_variant_get_uint64 (variant);
298 else
299 return FALSE;
300
301 if (G_VALUE_HOLDS_INT (value))
302 {
303 g_value_set_int (value, u);
304 return (u <= G_MAXINT32);
305 }
306 else if (G_VALUE_HOLDS_UINT (value))
307 {
308 g_value_set_uint (value, u);
309 return (u <= G_MAXUINT32);
310 }
311 else if (G_VALUE_HOLDS_INT64 (value))
312 {
313 g_value_set_int64 (value, u);
314 return (u <= G_MAXINT64);
315 }
316 else if (G_VALUE_HOLDS_UINT64 (value))
317 {
318 g_value_set_uint64 (value, u);
319 return (u <= G_MAXUINT64);
320 }
321 else if (G_VALUE_HOLDS_DOUBLE (value))
322 {
323 g_value_set_double (value, u);
324 return TRUE;
325 }
326
327 return FALSE;
328 }
329
330 GVariant *
331 g_settings_set_mapping (const GValue *value,
332 const GVariantType *expected_type,
333 gpointer user_data)
334 {
335 gchar *type_string;
336
337 if (G_VALUE_HOLDS_BOOLEAN (value))
338 {
339 if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN))
340 return g_variant_new_boolean (g_value_get_boolean (value));
341 }
342
343 else if (G_VALUE_HOLDS_CHAR (value) ||
344 G_VALUE_HOLDS_UCHAR (value))
345 {
346 if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE))
347 {
348 if (G_VALUE_HOLDS_CHAR (value))
349 return g_variant_new_byte (g_value_get_schar (value));
350 else
351 return g_variant_new_byte (g_value_get_uchar (value));
352 }
353 }
354
355 else if (G_VALUE_HOLDS_INT (value) ||
356 G_VALUE_HOLDS_INT64 (value))
357 return g_settings_set_mapping_int (value, expected_type);
358
359 else if (G_VALUE_HOLDS_DOUBLE (value))
360 return g_settings_set_mapping_float (value, expected_type);
361
362 else if (G_VALUE_HOLDS_UINT (value) ||
363 G_VALUE_HOLDS_UINT64 (value))
364 return g_settings_set_mapping_unsigned_int (value, expected_type);
365
366 else if (G_VALUE_HOLDS_STRING (value))
367 {
368 if (g_value_get_string (value) == NULL)
369 return NULL;
370 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING))
371 return g_variant_new_string (g_value_get_string (value));
372 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTESTRING))
373 return g_variant_new_bytestring (g_value_get_string (value));
374 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
375 return g_variant_new_object_path (g_value_get_string (value));
376 else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE))
377 return g_variant_new_signature (g_value_get_string (value));
378 }
379
380 else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
381 {
382 if (g_value_get_boxed (value) == NULL)
383 return NULL;
384 return g_variant_new_strv ((const gchar **) g_value_get_boxed (value),
385 -1);
386 }
387
388 else if (G_VALUE_HOLDS_ENUM (value))
389 {
390 GEnumValue *enumval;
391 GEnumClass *eclass;
392
393 /* GParamSpecEnum holds a ref on the class so we just peek... */
394 eclass = g_type_class_peek (G_VALUE_TYPE (value));
395 enumval = g_enum_get_value (eclass, g_value_get_enum (value));
396
397 if (enumval)
398 return g_variant_new_string (enumval->value_nick);
399 else
400 return NULL;
401 }
402
403 else if (G_VALUE_HOLDS_FLAGS (value))
404 {
405 GVariantBuilder builder;
406 GFlagsValue *flagsval;
407 GFlagsClass *fclass;
408 guint flags;
409
410 fclass = g_type_class_peek (G_VALUE_TYPE (value));
411 flags = g_value_get_flags (value);
412
413 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
414 while (flags)
415 {
416 flagsval = g_flags_get_first_value (fclass, flags);
417
418 if (flagsval == NULL)
419 {
420 g_variant_builder_clear (&builder);
421 return NULL;
422 }
423
424 g_variant_builder_add (&builder, "s", flagsval->value_nick);
425 flags &= ~flagsval->value;
426 }
427
428 return g_variant_builder_end (&builder);
429 }
430
431 type_string = g_variant_type_dup_string (expected_type);
432 g_critical ("No GSettings bind handler for type \"%s\".", type_string);
433 g_free (type_string);
434
435 return NULL;
436 }
437
438 gboolean
439 g_settings_get_mapping (GValue *value,
440 GVariant *variant,
441 gpointer user_data)
442 {
443 if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
444 {
445 if (!G_VALUE_HOLDS_BOOLEAN (value))
446 return FALSE;
447 g_value_set_boolean (value, g_variant_get_boolean (variant));
448 return TRUE;
449 }
450
451 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
452 {
453 if (G_VALUE_HOLDS_UCHAR (value))
454 g_value_set_uchar (value, g_variant_get_byte (variant));
455 else if (G_VALUE_HOLDS_CHAR (value))
456 g_value_set_schar (value, (gint8)g_variant_get_byte (variant));
457 else
458 return FALSE;
459 return TRUE;
460 }
461
462 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16) ||
463 g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32) ||
464 g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64) ||
465 g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
466 return g_settings_get_mapping_int (value, variant);
467
468 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
469 return g_settings_get_mapping_float (value, variant);
470
471 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
472 g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
473 g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64))
474 return g_settings_get_mapping_unsigned_int (value, variant);
475
476 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING) ||
477 g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
478 g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
479 {
480 if (G_VALUE_HOLDS_STRING (value))
481 {
482 g_value_set_string (value, g_variant_get_string (variant, NULL));
483 return TRUE;
484 }
485
486 else if (G_VALUE_HOLDS_ENUM (value))
487 {
488 GEnumClass *eclass;
489 GEnumValue *evalue;
490 const gchar *nick;
491
492 /* GParamSpecEnum holds a ref on the class so we just peek... */
493 eclass = g_type_class_peek (G_VALUE_TYPE (value));
494 nick = g_variant_get_string (variant, NULL);
495 evalue = g_enum_get_value_by_nick (eclass, nick);
496
497 if (evalue)
498 {
499 g_value_set_enum (value, evalue->value);
500 return TRUE;
501 }
502
503 g_warning ("Unable to look up enum nick ‘%s’ via GType", nick);
504 return FALSE;
505 }
506 }
507 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("as")))
508 {
509 if (G_VALUE_HOLDS (value, G_TYPE_STRV))
510 {
511 g_value_take_boxed (value, g_variant_dup_strv (variant, NULL));
512 return TRUE;
513 }
514
515 else if (G_VALUE_HOLDS_FLAGS (value))
516 {
517 GFlagsClass *fclass;
518 GFlagsValue *fvalue;
519 const gchar *nick;
520 GVariantIter iter;
521 guint flags = 0;
522
523 fclass = g_type_class_peek (G_VALUE_TYPE (value));
524
525 g_variant_iter_init (&iter, variant);
526 while (g_variant_iter_next (&iter, "&s", &nick))
527 {
528 fvalue = g_flags_get_value_by_nick (fclass, nick);
529
530 if (fvalue)
531 flags |= fvalue->value;
532
533 else
534 {
535 g_warning ("Unable to lookup flags nick '%s' via GType",
536 nick);
537 return FALSE;
538 }
539 }
540
541 g_value_set_flags (value, flags);
542 return TRUE;
543 }
544 }
545 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING))
546 {
547 g_value_set_string (value, g_variant_get_bytestring (variant));
548 return TRUE;
549 }
550
551 g_critical ("No GSettings bind handler for type \"%s\".",
552 g_variant_get_type_string (variant));
553
554 return FALSE;
555 }
556
557 gboolean
558 g_settings_mapping_is_compatible (GType gvalue_type,
559 const GVariantType *variant_type)
560 {
561 gboolean ok = FALSE;
562
563 if (gvalue_type == G_TYPE_BOOLEAN)
564 ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN);
565 else if (gvalue_type == G_TYPE_CHAR ||
566 gvalue_type == G_TYPE_UCHAR)
567 ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE);
568 else if (gvalue_type == G_TYPE_INT ||
569 gvalue_type == G_TYPE_UINT ||
570 gvalue_type == G_TYPE_INT64 ||
571 gvalue_type == G_TYPE_UINT64 ||
572 gvalue_type == G_TYPE_DOUBLE)
573 ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16) ||
574 g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16) ||
575 g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32) ||
576 g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32) ||
577 g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64) ||
578 g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64) ||
579 g_variant_type_equal (variant_type, G_VARIANT_TYPE_HANDLE) ||
580 g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE));
581 else if (gvalue_type == G_TYPE_STRING)
582 ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING) ||
583 g_variant_type_equal (variant_type, G_VARIANT_TYPE ("ay")) ||
584 g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
585 g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE));
586 else if (gvalue_type == G_TYPE_STRV)
587 ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as"));
588 else if (G_TYPE_IS_ENUM (gvalue_type))
589 ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING);
590 else if (G_TYPE_IS_FLAGS (gvalue_type))
591 ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE ("as"));
592
593 return ok;
594 }