Handle NULL string properties in bindings
[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_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   type_string = g_variant_type_dup_string (expected_type);
379   g_critical ("No GSettings bind handler for type \"%s\".", type_string);
380   g_free (type_string);
381
382   return NULL;
383 }
384
385 gboolean
386 g_settings_get_mapping (GValue   *value,
387                         GVariant *variant,
388                         gpointer  user_data)
389 {
390   if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
391     {
392       if (!G_VALUE_HOLDS_BOOLEAN (value))
393         return FALSE;
394       g_value_set_boolean (value, g_variant_get_boolean (variant));
395       return TRUE;
396     }
397
398   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
399     {
400       if (G_VALUE_HOLDS_UCHAR (value))
401         g_value_set_uchar (value, g_variant_get_byte (variant));
402       else if (G_VALUE_HOLDS_CHAR (value))
403         g_value_set_char (value, (gchar) g_variant_get_byte (variant));
404       else
405         return FALSE;
406       return TRUE;
407     }
408
409   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16)  ||
410            g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32)  ||
411            g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64))
412     return g_settings_get_mapping_int (value, variant);
413
414   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
415     return g_settings_get_mapping_float (value, variant);
416
417   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
418            g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
419            g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64) ||
420            g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
421     return g_settings_get_mapping_unsigned_int (value, variant);
422
423   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)      ||
424            g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
425            g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
426     {
427       g_value_set_string (value, g_variant_get_string (variant, NULL));
428       return TRUE;
429     }
430
431   g_critical ("No GSettings bind handler for type \"%s\".",
432               g_variant_get_type_string (variant));
433
434   return FALSE;
435 }
436
437 gboolean
438 g_settings_mapping_is_compatible (GType               gvalue_type,
439                                   const GVariantType *variant_type)
440 {
441   gboolean ok = FALSE;
442
443   if (gvalue_type == G_TYPE_BOOLEAN)
444     ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN);
445   else if (gvalue_type == G_TYPE_CHAR  ||
446            gvalue_type == G_TYPE_UCHAR)
447     ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE);
448   else if (gvalue_type == G_TYPE_INT    ||
449            gvalue_type == G_TYPE_UINT   ||
450            gvalue_type == G_TYPE_INT64  ||
451            gvalue_type == G_TYPE_UINT64 ||
452            gvalue_type == G_TYPE_DOUBLE)
453     ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16)  ||
454           g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16) ||
455           g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32)  ||
456           g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32) ||
457           g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64)  ||
458           g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64) ||
459           g_variant_type_equal (variant_type, G_VARIANT_TYPE_HANDLE) ||
460           g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE));
461   else if (gvalue_type == G_TYPE_STRING)
462     ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING)      ||
463           g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
464           g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE));
465
466   return ok;
467 }