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