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