fda74635c839f3d2b830e65205c7059550b783dc
[platform/upstream/glib.git] / gio / gsettings-mapping.c
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 of the licence, 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
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 && 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 && 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
206     return FALSE;
207
208   if (G_VALUE_HOLDS_INT (value))
209     {
210       g_value_set_int (value, l);
211       return (G_MININT32 <= l && l <= G_MAXINT32);
212     }
213   else if (G_VALUE_HOLDS_UINT (value))
214     {
215       g_value_set_uint (value, l);
216       return (0 <= l && l <= G_MAXUINT32);
217     }
218   else if (G_VALUE_HOLDS_INT64 (value))
219     {
220       g_value_set_int64 (value, l);
221       return (G_MININT64 <= l && l <= G_MAXINT64);
222     }
223   else if (G_VALUE_HOLDS_UINT64 (value))
224     {
225       g_value_set_uint64 (value, l);
226       return (0 <= l && l <= G_MAXUINT64);
227     }
228   else if (G_VALUE_HOLDS_DOUBLE (value))
229     {
230       g_value_set_double (value, l);
231       return TRUE;
232     }
233
234   return FALSE;
235 }
236
237 static gboolean
238 g_settings_get_mapping_float (GValue   *value,
239                               GVariant *variant)
240 {
241   const GVariantType *type;
242   gdouble d;
243   gint64 l;
244
245   type = g_variant_get_type (variant);
246
247   if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
248     d = g_variant_get_double (variant);
249   else
250     return FALSE;
251
252   l = (gint64)d;
253   if (G_VALUE_HOLDS_INT (value))
254     {
255       g_value_set_int (value, l);
256       return (G_MININT32 <= l && l <= G_MAXINT32);
257     }
258   else if (G_VALUE_HOLDS_UINT (value))
259     {
260       g_value_set_uint (value, l);
261       return (0 <= l && l <= G_MAXUINT32);
262     }
263   else if (G_VALUE_HOLDS_INT64 (value))
264     {
265       g_value_set_int64 (value, l);
266       return (G_MININT64 <= l && l <= G_MAXINT64);
267     }
268   else if (G_VALUE_HOLDS_UINT64 (value))
269     {
270       g_value_set_uint64 (value, l);
271       return (0 <= l && l <= G_MAXUINT64);
272     }
273   else if (G_VALUE_HOLDS_DOUBLE (value))
274     {
275       g_value_set_double (value, d);
276       return TRUE;
277     }
278
279   return FALSE;
280 }
281 static gboolean
282 g_settings_get_mapping_unsigned_int (GValue   *value,
283                                      GVariant *variant)
284 {
285   const GVariantType *type;
286   guint64 u;
287
288   type = g_variant_get_type (variant);
289
290   if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
291     u = g_variant_get_uint16 (variant);
292   else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
293     u = g_variant_get_uint32 (variant);
294   else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
295     u = g_variant_get_uint64 (variant);
296   else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
297     u = g_variant_get_handle (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_char (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_char (value, (gchar) 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     return g_settings_get_mapping_int (value, variant);
466
467   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
468     return g_settings_get_mapping_float (value, variant);
469
470   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
471            g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
472            g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64) ||
473            g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
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 lookup enum nick '%s' via GType\n", 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\n",
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 }