schema source: avoid introspection confusion
[platform/upstream/glib.git] / gio / gsettingsschema.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  * Copyright © 2011 Canonical Limited
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the licence, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include "gsettingsschema-internal.h"
24 #include "gsettings.h"
25
26 #include "gvdb/gvdb-reader.h"
27 #include "strinfo.c"
28
29 #include <glibintl.h>
30 #include <string.h>
31
32 struct _GSettingsSchema
33 {
34   const gchar *gettext_domain;
35   const gchar *path;
36   GQuark *items;
37   gint n_items;
38   GvdbTable *table;
39   gchar *id;
40
41   gint ref_count;
42 };
43
44 typedef struct _GSettingsSchemaSource GSettingsSchemaSource;
45
46 G_DEFINE_BOXED_TYPE (GSettingsSchemaSource, g_settings_schema_source, g_settings_schema_source_ref, g_settings_schema_source_unref)
47 G_DEFINE_BOXED_TYPE (GSettingsSchema, g_settings_schema, g_settings_schema_ref, g_settings_schema_unref)
48
49 struct _GSettingsSchemaSource
50 {
51   GSettingsSchemaSource *parent;
52   GvdbTable *table;
53
54   gint ref_count;
55 };
56
57 static GSettingsSchemaSource *schema_sources;
58
59 static void
60 prepend_schema_table (GvdbTable *table)
61 {
62   GSettingsSchemaSource *source;
63
64   /* we steal the reference from 'schema_sources' for our ->parent */
65   source = g_slice_new (GSettingsSchemaSource);
66   source->parent = schema_sources;
67   source->table = table;
68   source->ref_count = 1;
69
70   schema_sources = source;
71 }
72
73 GSettingsSchemaSource *
74 g_settings_schema_source_ref (GSettingsSchemaSource *source)
75 {
76   g_atomic_int_inc (&source->ref_count);
77
78   return source;
79 }
80
81 void
82 g_settings_schema_source_unref (GSettingsSchemaSource *source)
83 {
84   if (g_atomic_int_dec_and_test (&source->ref_count))
85     {
86       if (source == schema_sources)
87         g_error ("g_settings_schema_source_unref() called too many times on the default schema source");
88
89       if (source->parent)
90         g_settings_schema_source_unref (source->parent);
91       gvdb_table_unref (source->table);
92
93       g_slice_free (GSettingsSchemaSource, source);
94     }
95 }
96
97 GSettingsSchemaSource *
98 g_settings_schema_source_new_from_directory (const gchar            *directory,
99                                              GSettingsSchemaSource  *parent,
100                                              gboolean                trusted,
101                                              GError                **error)
102 {
103   GSettingsSchemaSource *source;
104   GvdbTable *table;
105   gchar *filename;
106
107   filename = g_build_filename (directory, "gschemas.compiled", NULL);
108   table = gvdb_table_new (filename, trusted, error);
109   g_free (filename);
110
111   if (table == NULL)
112     return NULL;
113
114   source = g_slice_new (GSettingsSchemaSource);
115   source->parent = parent ? g_settings_schema_source_ref (parent) : NULL;
116   source->table = table;
117   source->ref_count = 1;
118
119   return source;
120 }
121
122 static void
123 initialise_schema_sources (void)
124 {
125   static gsize initialised;
126
127   /* need a separate variable because 'schema_sources' may legitimately
128    * be null if we have zero valid schema sources
129    */
130   if G_UNLIKELY (g_once_init_enter (&initialised))
131     {
132       const gchar * const *dirs;
133       const gchar *path;
134       gint i;
135
136       /* iterate in reverse: count up, then count down */
137       dirs = g_get_system_data_dirs ();
138       for (i = 0; dirs[i]; i++);
139
140       while (i--)
141         {
142           gchar *filename;
143           GvdbTable *table;
144
145           filename = g_build_filename (dirs[i], "glib-2.0", "schemas", "gschemas.compiled", NULL);
146           table = gvdb_table_new (filename, TRUE, NULL);
147
148           if (table != NULL)
149             prepend_schema_table (table);
150
151           g_free (filename);
152         }
153
154       if ((path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL)
155         {
156           gchar *filename;
157           GvdbTable *table;
158
159           filename = g_build_filename (path, "gschemas.compiled", NULL);
160           table = gvdb_table_new (filename, TRUE, NULL);
161
162           if (table != NULL)
163             prepend_schema_table (table);
164
165           g_free (filename);
166         }
167
168       g_once_init_leave (&initialised, TRUE);
169     }
170 }
171
172 GSettingsSchemaSource *
173 g_settings_schema_source_get_default (void)
174 {
175   initialise_schema_sources ();
176
177   return schema_sources;
178 }
179
180 GSettingsSchema *
181 g_settings_schema_source_lookup (GSettingsSchemaSource *source,
182                                  const gchar           *schema_id,
183                                  gboolean               recursive)
184 {
185   GSettingsSchema *schema;
186   GvdbTable *table;
187
188   g_return_val_if_fail (source != NULL, NULL);
189   g_return_val_if_fail (schema_id != NULL, NULL);
190
191   table = gvdb_table_get_table (source->table, schema_id);
192
193   if (table == NULL && recursive)
194     for (source = source->parent; source; source = source->parent)
195       if ((table = gvdb_table_get_table (source->table, schema_id)))
196         break;
197
198   if (table == NULL)
199     return NULL;
200
201   schema = g_slice_new0 (GSettingsSchema);
202   schema->ref_count = 1;
203   schema->id = g_strdup (schema_id);
204   schema->table = table;
205   schema->path = g_settings_schema_get_string (schema, ".path");
206   schema->gettext_domain = g_settings_schema_get_string (schema, ".gettext-domain");
207
208   if (schema->gettext_domain)
209     bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
210
211   return schema;
212 }
213
214 static gboolean
215 steal_item (gpointer key,
216             gpointer value,
217             gpointer user_data)
218 {
219   gchar ***ptr = user_data;
220
221   *(*ptr)++ = (gchar *) key;
222
223   return TRUE;
224 }
225
226 static const gchar * const *non_relocatable_schema_list;
227 static const gchar * const *relocatable_schema_list;
228 static gsize schema_lists_initialised;
229
230 static void
231 ensure_schema_lists (void)
232 {
233   if (g_once_init_enter (&schema_lists_initialised))
234     {
235       GSettingsSchemaSource *source;
236       GHashTable *single, *reloc;
237       const gchar **ptr;
238       gchar **list;
239       gint i;
240
241       initialise_schema_sources ();
242
243       /* We use hash tables to avoid duplicate listings for schemas that
244        * appear in more than one file.
245        */
246       single = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
247       reloc = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
248
249       for (source = schema_sources; source; source = source->parent)
250         {
251           list = gvdb_table_list (source->table, "");
252
253           g_assert (list != NULL);
254
255           for (i = 0; list[i]; i++)
256             {
257               if (!g_hash_table_lookup (single, list[i]) &&
258                   !g_hash_table_lookup (reloc, list[i]))
259                 {
260                   GvdbTable *table;
261
262                   table = gvdb_table_get_table (source->table, list[i]);
263                   g_assert (table != NULL);
264
265                   if (gvdb_table_has_value (table, ".path"))
266                     g_hash_table_insert (single, g_strdup (list[i]), NULL);
267                   else
268                     g_hash_table_insert (reloc, g_strdup (list[i]), NULL);
269
270                   gvdb_table_unref (table);
271                 }
272             }
273
274           g_strfreev (list);
275         }
276
277       ptr = g_new (const gchar *, g_hash_table_size (single) + 1);
278       non_relocatable_schema_list = ptr;
279       g_hash_table_foreach_steal (single, steal_item, &ptr);
280       g_hash_table_unref (single);
281       *ptr = NULL;
282
283       ptr = g_new (const gchar *, g_hash_table_size (reloc) + 1);
284       relocatable_schema_list = ptr;
285       g_hash_table_foreach_steal (reloc, steal_item, &ptr);
286       g_hash_table_unref (reloc);
287       *ptr = NULL;
288
289       g_once_init_leave (&schema_lists_initialised, TRUE);
290     }
291 }
292
293 /**
294  * g_settings_list_schemas:
295  *
296  * Gets a list of the #GSettings schemas installed on the system.  The
297  * returned list is exactly the list of schemas for which you may call
298  * g_settings_new() without adverse effects.
299  *
300  * This function does not list the schemas that do not provide their own
301  * paths (ie: schemas for which you must use
302  * g_settings_new_with_path()).  See
303  * g_settings_list_relocatable_schemas() for that.
304  *
305  * Returns: (element-type utf8) (transfer none):  a list of #GSettings
306  *   schemas that are available.  The list must not be modified or
307  *   freed.
308  *
309  * Since: 2.26
310  **/
311 const gchar * const *
312 g_settings_list_schemas (void)
313 {
314   ensure_schema_lists ();
315
316   return non_relocatable_schema_list;
317 }
318
319 /**
320  * g_settings_list_relocatable_schemas:
321  *
322  * Gets a list of the relocatable #GSettings schemas installed on the
323  * system.  These are schemas that do not provide their own path.  It is
324  * usual to instantiate these schemas directly, but if you want to you
325  * can use g_settings_new_with_path() to specify the path.
326  *
327  * The output of this function, tTaken together with the output of
328  * g_settings_list_schemas() represents the complete list of all
329  * installed schemas.
330  *
331  * Returns: (element-type utf8) (transfer none): a list of relocatable
332  *   #GSettings schemas that are available.  The list must not be
333  *   modified or freed.
334  *
335  * Since: 2.28
336  **/
337 const gchar * const *
338 g_settings_list_relocatable_schemas (void)
339 {
340   ensure_schema_lists ();
341
342   return relocatable_schema_list;
343 }
344
345 GSettingsSchema *
346 g_settings_schema_ref (GSettingsSchema *schema)
347 {
348   g_atomic_int_inc (&schema->ref_count);
349
350   return schema;
351 }
352
353 void
354 g_settings_schema_unref (GSettingsSchema *schema)
355 {
356   if (g_atomic_int_dec_and_test (&schema->ref_count))
357     {
358       gvdb_table_unref (schema->table);
359       g_free (schema->items);
360       g_free (schema->id);
361
362       g_slice_free (GSettingsSchema, schema);
363     }
364 }
365
366 const gchar *
367 g_settings_schema_get_string (GSettingsSchema *schema,
368                               const gchar     *key)
369 {
370   const gchar *result = NULL;
371   GVariant *value;
372
373   if ((value = gvdb_table_get_raw_value (schema->table, key)))
374     {
375       result = g_variant_get_string (value, NULL);
376       g_variant_unref (value);
377     }
378
379   return result;
380 }
381
382 GVariantIter *
383 g_settings_schema_get_value (GSettingsSchema *schema,
384                              const gchar     *key)
385 {
386   GVariantIter *iter;
387   GVariant *value;
388
389   value = gvdb_table_get_raw_value (schema->table, key);
390
391   if G_UNLIKELY (value == NULL)
392     g_error ("Settings schema '%s' does not contain a key named '%s'", schema->id, key);
393
394   iter = g_variant_iter_new (value);
395   g_variant_unref (value);
396
397   return iter;
398 }
399
400 const gchar *
401 g_settings_schema_get_path (GSettingsSchema *schema)
402 {
403   return schema->path;
404 }
405
406 const gchar *
407 g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
408 {
409   return schema->gettext_domain;
410 }
411
412 gboolean
413 g_settings_schema_has_key (GSettingsSchema *schema,
414                            const gchar     *key)
415 {
416   return gvdb_table_has_value (schema->table, key);
417 }
418
419 const GQuark *
420 g_settings_schema_list (GSettingsSchema *schema,
421                         gint            *n_items)
422 {
423   gint i, j;
424
425   if (schema->items == NULL)
426     {
427       gchar **list;
428       gint len;
429
430       list = gvdb_table_list (schema->table, "");
431       len = list ? g_strv_length (list) : 0;
432
433       schema->items = g_new (GQuark, len);
434       j = 0;
435
436       for (i = 0; i < len; i++)
437         if (list[i][0] != '.')
438           schema->items[j++] = g_quark_from_string (list[i]);
439       schema->n_items = j;
440
441       g_strfreev (list);
442     }
443
444   *n_items = schema->n_items;
445   return schema->items;
446 }
447
448 const gchar *
449 g_settings_schema_get_id (GSettingsSchema *schema)
450 {
451   return schema->id;
452 }
453
454 static inline void
455 endian_fixup (GVariant **value)
456 {
457 #if G_BYTE_ORDER == G_BIG_ENDIAN
458   GVariant *tmp;
459
460   tmp = g_variant_byteswap (*value);
461   g_variant_unref (*value);
462   *value = tmp;
463 #endif
464 }
465
466 void
467 g_settings_schema_key_init (GSettingsSchemaKey *key,
468                             GSettingsSchema    *schema,
469                             const gchar        *name)
470 {
471   GVariantIter *iter;
472   GVariant *data;
473   guchar code;
474
475   memset (key, 0, sizeof *key);
476
477   iter = g_settings_schema_get_value (schema, name);
478
479   key->schema = g_settings_schema_ref (schema);
480   key->default_value = g_variant_iter_next_value (iter);
481   endian_fixup (&key->default_value);
482   key->type = g_variant_get_type (key->default_value);
483   key->name = g_intern_string (name);
484
485   while (g_variant_iter_next (iter, "(y*)", &code, &data))
486     {
487       switch (code)
488         {
489         case 'l':
490           /* translation requested */
491           g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed);
492           break;
493
494         case 'e':
495           /* enumerated types... */
496           key->is_enum = TRUE;
497           goto choice;
498
499         case 'f':
500           /* flags... */
501           key->is_flags = TRUE;
502           goto choice;
503
504         choice: case 'c':
505           /* ..., choices, aliases */
506           key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32));
507           break;
508
509         case 'r':
510           g_variant_get (data, "(**)", &key->minimum, &key->maximum);
511           endian_fixup (&key->minimum);
512           endian_fixup (&key->maximum);
513           break;
514
515         default:
516           g_warning ("unknown schema extension '%c'", code);
517           break;
518         }
519
520       g_variant_unref (data);
521     }
522
523   g_variant_iter_free (iter);
524 }
525
526 void
527 g_settings_schema_key_clear (GSettingsSchemaKey *key)
528 {
529   if (key->minimum)
530     g_variant_unref (key->minimum);
531
532   if (key->maximum)
533     g_variant_unref (key->maximum);
534
535   g_variant_unref (key->default_value);
536
537   g_settings_schema_unref (key->schema);
538 }
539
540 gboolean
541 g_settings_schema_key_type_check (GSettingsSchemaKey *key,
542                                   GVariant           *value)
543 {
544   g_return_val_if_fail (value != NULL, FALSE);
545
546   return g_variant_is_of_type (value, key->type);
547 }
548
549 gboolean
550 g_settings_schema_key_range_check (GSettingsSchemaKey *key,
551                                    GVariant           *value)
552 {
553   if (key->minimum == NULL && key->strinfo == NULL)
554     return TRUE;
555
556   if (g_variant_is_container (value))
557     {
558       gboolean ok = TRUE;
559       GVariantIter iter;
560       GVariant *child;
561
562       g_variant_iter_init (&iter, value);
563       while (ok && (child = g_variant_iter_next_value (&iter)))
564         {
565           ok = g_settings_schema_key_range_check (key, child);
566           g_variant_unref (child);
567         }
568
569       return ok;
570     }
571
572   if (key->minimum)
573     {
574       return g_variant_compare (key->minimum, value) <= 0 &&
575              g_variant_compare (value, key->maximum) <= 0;
576     }
577
578   return strinfo_is_string_valid (key->strinfo, key->strinfo_length,
579                                   g_variant_get_string (value, NULL));
580 }
581
582 GVariant *
583 g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
584                                    GVariant           *value)
585 {
586   const gchar *target;
587
588   if (g_settings_schema_key_range_check (key, value))
589     return g_variant_ref (value);
590
591   if (key->strinfo == NULL)
592     return NULL;
593
594   if (g_variant_is_container (value))
595     {
596       GVariantBuilder builder;
597       GVariantIter iter;
598       GVariant *child;
599
600       g_variant_iter_init (&iter, value);
601       g_variant_builder_init (&builder, g_variant_get_type (value));
602
603       while ((child = g_variant_iter_next_value (&iter)))
604         {
605           GVariant *fixed;
606
607           fixed = g_settings_schema_key_range_fixup (key, child);
608           g_variant_unref (child);
609
610           if (fixed == NULL)
611             {
612               g_variant_builder_clear (&builder);
613               return NULL;
614             }
615
616           g_variant_builder_add_value (&builder, fixed);
617           g_variant_unref (fixed);
618         }
619
620       return g_variant_ref_sink (g_variant_builder_end (&builder));
621     }
622
623   target = strinfo_string_from_alias (key->strinfo, key->strinfo_length,
624                                       g_variant_get_string (value, NULL));
625   return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL;
626 }
627
628
629 GVariant *
630 g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
631 {
632   const gchar *translated;
633   GError *error = NULL;
634   const gchar *domain;
635   GVariant *value;
636
637   domain = g_settings_schema_get_gettext_domain (key->schema);
638
639   if (key->lc_char == '\0')
640     /* translation not requested for this key */
641     return NULL;
642
643   if (key->lc_char == 't')
644     translated = g_dcgettext (domain, key->unparsed, LC_TIME);
645   else
646     translated = g_dgettext (domain, key->unparsed);
647
648   if (translated == key->unparsed)
649     /* the default value was not translated */
650     return NULL;
651
652   /* try to parse the translation of the unparsed default */
653   value = g_variant_parse (key->type, translated, NULL, NULL, &error);
654
655   if (value == NULL)
656     {
657       g_warning ("Failed to parse translated string `%s' for "
658                  "key `%s' in schema `%s': %s", key->unparsed, key->name,
659                  g_settings_schema_get_id (key->schema), error->message);
660       g_warning ("Using untranslated default instead.");
661       g_error_free (error);
662     }
663
664   else if (!g_settings_schema_key_range_check (key, value))
665     {
666       g_warning ("Translated default `%s' for key `%s' in schema `%s' "
667                  "is outside of valid range", key->unparsed, key->name,
668                  g_settings_schema_get_id (key->schema));
669       g_variant_unref (value);
670       value = NULL;
671     }
672
673   return value;
674 }
675
676 gint
677 g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
678                                GVariant           *value)
679 {
680   gboolean it_worked;
681   guint result;
682
683   it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length,
684                                         g_variant_get_string (value, NULL),
685                                         &result);
686
687   /* 'value' can only come from the backend after being filtered for validity,
688    * from the translation after being filtered for validity, or from the schema
689    * itself (which the schema compiler checks for validity).  If this assertion
690    * fails then it's really a bug in GSettings or the schema compiler...
691    */
692   g_assert (it_worked);
693
694   return result;
695 }
696
697 GVariant *
698 g_settings_schema_key_from_enum (GSettingsSchemaKey *key,
699                                  gint                value)
700 {
701   const gchar *string;
702
703   string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value);
704
705   if (string == NULL)
706     return NULL;
707
708   return g_variant_new_string (string);
709 }
710
711 guint
712 g_settings_schema_key_to_flags (GSettingsSchemaKey *key,
713                                 GVariant           *value)
714 {
715   GVariantIter iter;
716   const gchar *flag;
717   guint result;
718
719   result = 0;
720   g_variant_iter_init (&iter, value);
721   while (g_variant_iter_next (&iter, "&s", &flag))
722     {
723       gboolean it_worked;
724       guint flag_value;
725
726       it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value);
727       /* as in g_settings_to_enum() */
728       g_assert (it_worked);
729
730       result |= flag_value;
731     }
732
733   return result;
734 }
735
736 GVariant *
737 g_settings_schema_key_from_flags (GSettingsSchemaKey *key,
738                                   guint               value)
739 {
740   GVariantBuilder builder;
741   gint i;
742
743   g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
744
745   for (i = 0; i < 32; i++)
746     if (value & (1u << i))
747       {
748         const gchar *string;
749
750         string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i);
751
752         if (string == NULL)
753           {
754             g_variant_builder_clear (&builder);
755             return NULL;
756           }
757
758         g_variant_builder_add (&builder, "s", string);
759       }
760
761   return g_variant_builder_end (&builder);
762 }