Add gtk-doc for gsettingsschema{,source}
[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 /**
33  * SECTION:gsettingsschema
34  * @short_description: introspecting and controlling the loading of
35  *                     #GSettings schemas
36  *
37  * The #GSettingsSchemaSource and #GSettingsSchema APIs provide a
38  * mechanism for advanced control over the loading of schemas and a
39  * mechanism for introspecting their content.
40  *
41  * Since: 2.32
42  */
43
44 /**
45  * GSettingsSchema:
46  *
47  * This is an opaque structure type.  You may not access it directly.
48  *
49  * Since: 2.32
50  **/
51 struct _GSettingsSchema
52 {
53   const gchar *gettext_domain;
54   const gchar *path;
55   GQuark *items;
56   gint n_items;
57   GvdbTable *table;
58   gchar *id;
59
60   gint ref_count;
61 };
62
63 typedef struct _GSettingsSchemaSource GSettingsSchemaSource;
64
65 /**
66  * G_TYPE_SETTINGS_SCHEMA_SOURCE:
67  *
68  * A boxed #GType corresponding to #GSettingsSchemaSource.
69  *
70  * Since: 2.32
71  **/
72 G_DEFINE_BOXED_TYPE (GSettingsSchemaSource, g_settings_schema_source, g_settings_schema_source_ref, g_settings_schema_source_unref)
73
74 /**
75  * G_TYPE_SETTINGS_SCHEMA:
76  *
77  * A boxed #GType corresponding to #GSettingsSchema.
78  *
79  * Since: 2.32
80  **/
81 G_DEFINE_BOXED_TYPE (GSettingsSchema, g_settings_schema, g_settings_schema_ref, g_settings_schema_unref)
82
83 /**
84  * GSettingsSchemaSource:
85  *
86  * This is an opaque structure type.  You may not access it directly.
87  *
88  * Since: 2.32
89  **/
90 struct _GSettingsSchemaSource
91 {
92   GSettingsSchemaSource *parent;
93   GvdbTable *table;
94
95   gint ref_count;
96 };
97
98 static GSettingsSchemaSource *schema_sources;
99
100 static void
101 prepend_schema_table (GvdbTable *table)
102 {
103   GSettingsSchemaSource *source;
104
105   /* we steal the reference from 'schema_sources' for our ->parent */
106   source = g_slice_new (GSettingsSchemaSource);
107   source->parent = schema_sources;
108   source->table = table;
109   source->ref_count = 1;
110
111   schema_sources = source;
112 }
113
114 /**
115  * g_settings_schema_source_ref:
116  * @source: a #GSettingsSchemaSource
117  *
118  * Increase the reference count of @source, returning a new reference.
119  *
120  * Returns: a new reference to @source
121  *
122  * Since: 2.32
123  **/
124 GSettingsSchemaSource *
125 g_settings_schema_source_ref (GSettingsSchemaSource *source)
126 {
127   g_atomic_int_inc (&source->ref_count);
128
129   return source;
130 }
131
132 /**
133  * g_settings_schema_source_unref:
134  * @source: a #GSettingsSchemaSource
135  *
136  * Decrease the reference count of @source, possibly freeing it.
137  *
138  * Since: 2.32
139  **/
140 void
141 g_settings_schema_source_unref (GSettingsSchemaSource *source)
142 {
143   if (g_atomic_int_dec_and_test (&source->ref_count))
144     {
145       if (source == schema_sources)
146         g_error ("g_settings_schema_source_unref() called too many times on the default schema source");
147
148       if (source->parent)
149         g_settings_schema_source_unref (source->parent);
150       gvdb_table_unref (source->table);
151
152       g_slice_free (GSettingsSchemaSource, source);
153     }
154 }
155
156 /**
157  * g_settings_schema_source_new_from_directory:
158  * @directory: the filename of a directory
159  * @parent: (allow-none): a #GSettingsSchemaSource, or %NULL
160  * @trusted: %TRUE, if the directory is trusted
161  * @error: a pointer to a #GError pointer set to %NULL, or %NULL
162  *
163  * Attempts to create a new schema source corresponding to the contents
164  * of the given directory.
165  *
166  * This function is not required for normal uses of #GSettings but it
167  * may be useful to authors of plugin management systems.
168  *
169  * The directory should contain a file called
170  * <filename>gschemas.compiled</filename> as produced by
171  * <command>glib-compile-schemas</command>.
172  *
173  * If @trusted is %TRUE then <filename>gschemas.compiled</filename> is
174  * trusted not to be corrupted.  This assumption has a performance
175  * advantage, but can result in crashes or inconsistent behaviour in the
176  * case of a corrupted file.  Generally, you should set @trusted to
177  * %TRUE for files installed by the system and to %FALSE for files in
178  * the home directory.
179  *
180  * If @parent is non-%NULL then there are two effects.
181  *
182  * First, if g_settings_schema_source_lookup() is called with the
183  * @recursive flag set to %TRUE and the schema can not be found in the
184  * source, the lookup will recurse to the parent.
185  *
186  * Second, any references to other schemas specified within this
187  * source (ie: <literal>child</literal> or <literal>extents</literal>)
188  * references may be resolved from the @parent.
189  *
190  * For this second reason, except in very unusual situations, the
191  * @parent should probably be given as the default schema source, as
192  * returned by g_settings_schema_source_get_default().
193  *
194  * Since: 2.32
195  **/
196 GSettingsSchemaSource *
197 g_settings_schema_source_new_from_directory (const gchar            *directory,
198                                              GSettingsSchemaSource  *parent,
199                                              gboolean                trusted,
200                                              GError                **error)
201 {
202   GSettingsSchemaSource *source;
203   GvdbTable *table;
204   gchar *filename;
205
206   filename = g_build_filename (directory, "gschemas.compiled", NULL);
207   table = gvdb_table_new (filename, trusted, error);
208   g_free (filename);
209
210   if (table == NULL)
211     return NULL;
212
213   source = g_slice_new (GSettingsSchemaSource);
214   source->parent = parent ? g_settings_schema_source_ref (parent) : NULL;
215   source->table = table;
216   source->ref_count = 1;
217
218   return source;
219 }
220
221 static void
222 initialise_schema_sources (void)
223 {
224   static gsize initialised;
225
226   /* need a separate variable because 'schema_sources' may legitimately
227    * be null if we have zero valid schema sources
228    */
229   if G_UNLIKELY (g_once_init_enter (&initialised))
230     {
231       const gchar * const *dirs;
232       const gchar *path;
233       gint i;
234
235       /* iterate in reverse: count up, then count down */
236       dirs = g_get_system_data_dirs ();
237       for (i = 0; dirs[i]; i++);
238
239       while (i--)
240         {
241           gchar *filename;
242           GvdbTable *table;
243
244           filename = g_build_filename (dirs[i], "glib-2.0", "schemas", "gschemas.compiled", NULL);
245           table = gvdb_table_new (filename, TRUE, NULL);
246
247           if (table != NULL)
248             prepend_schema_table (table);
249
250           g_free (filename);
251         }
252
253       if ((path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL)
254         {
255           gchar *filename;
256           GvdbTable *table;
257
258           filename = g_build_filename (path, "gschemas.compiled", NULL);
259           table = gvdb_table_new (filename, TRUE, NULL);
260
261           if (table != NULL)
262             prepend_schema_table (table);
263
264           g_free (filename);
265         }
266
267       g_once_init_leave (&initialised, TRUE);
268     }
269 }
270
271 /**
272  * g_settings_schema_source_get_default:
273  *
274  * Gets the default system schema source.
275  *
276  * This function is not required for normal uses of #GSettings but it
277  * may be useful to authors of plugin management systems or to those who
278  * want to introspect the content of schemas.
279  *
280  * If no schemas are installed, %NULL will be returned.
281  *
282  * The returned source may actually consist of multiple schema sources
283  * from different directories, depending on which directories were given
284  * in <envar>XDG_DATA_DIRS</envar> and
285  * <envar>GSETTINGS_SCHEMA_DIR</envar>.  For this reason, all lookups
286  * performed against the default source should probably be done
287  * recursively.
288  *
289  * Returns: (transfer none): the default schema source
290  *
291  * Since: 2.32
292  **/
293  GSettingsSchemaSource *
294 g_settings_schema_source_get_default (void)
295 {
296   initialise_schema_sources ();
297
298   return schema_sources;
299 }
300
301 /**
302  * g_settings_schema_source_lookup:
303  * @source: a #GSettingsSchemaSource
304  * @schema_id: a schema ID
305  * @recursive: %TRUE if the lookup should be recursive
306  *
307  * Looks up a schema with the identifier @schema_id in @source.
308  *
309  * This function is not required for normal uses of #GSettings but it
310  * may be useful to authors of plugin management systems or to those who
311  * want to introspect the content of schemas.
312  *
313  * If the schema isn't found directly in @source and @recursive is %TRUE
314  * then the parent sources will also be checked.
315  *
316  * If the schema isn't found, %NULL is returned.
317  *
318  * Returns: (transfer full): a new #GSettingsSchema
319  *
320  * Since: 2.32
321  **/
322 GSettingsSchema *
323 g_settings_schema_source_lookup (GSettingsSchemaSource *source,
324                                  const gchar           *schema_id,
325                                  gboolean               recursive)
326 {
327   GSettingsSchema *schema;
328   GvdbTable *table;
329
330   g_return_val_if_fail (source != NULL, NULL);
331   g_return_val_if_fail (schema_id != NULL, NULL);
332
333   table = gvdb_table_get_table (source->table, schema_id);
334
335   if (table == NULL && recursive)
336     for (source = source->parent; source; source = source->parent)
337       if ((table = gvdb_table_get_table (source->table, schema_id)))
338         break;
339
340   if (table == NULL)
341     return NULL;
342
343   schema = g_slice_new0 (GSettingsSchema);
344   schema->ref_count = 1;
345   schema->id = g_strdup (schema_id);
346   schema->table = table;
347   schema->path = g_settings_schema_get_string (schema, ".path");
348   schema->gettext_domain = g_settings_schema_get_string (schema, ".gettext-domain");
349
350   if (schema->gettext_domain)
351     bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
352
353   return schema;
354 }
355
356 static gboolean
357 steal_item (gpointer key,
358             gpointer value,
359             gpointer user_data)
360 {
361   gchar ***ptr = user_data;
362
363   *(*ptr)++ = (gchar *) key;
364
365   return TRUE;
366 }
367
368 static const gchar * const *non_relocatable_schema_list;
369 static const gchar * const *relocatable_schema_list;
370 static gsize schema_lists_initialised;
371
372 static void
373 ensure_schema_lists (void)
374 {
375   if (g_once_init_enter (&schema_lists_initialised))
376     {
377       GSettingsSchemaSource *source;
378       GHashTable *single, *reloc;
379       const gchar **ptr;
380       gchar **list;
381       gint i;
382
383       initialise_schema_sources ();
384
385       /* We use hash tables to avoid duplicate listings for schemas that
386        * appear in more than one file.
387        */
388       single = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
389       reloc = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
390
391       for (source = schema_sources; source; source = source->parent)
392         {
393           list = gvdb_table_list (source->table, "");
394
395           g_assert (list != NULL);
396
397           for (i = 0; list[i]; i++)
398             {
399               if (!g_hash_table_lookup (single, list[i]) &&
400                   !g_hash_table_lookup (reloc, list[i]))
401                 {
402                   GvdbTable *table;
403
404                   table = gvdb_table_get_table (source->table, list[i]);
405                   g_assert (table != NULL);
406
407                   if (gvdb_table_has_value (table, ".path"))
408                     g_hash_table_insert (single, g_strdup (list[i]), NULL);
409                   else
410                     g_hash_table_insert (reloc, g_strdup (list[i]), NULL);
411
412                   gvdb_table_unref (table);
413                 }
414             }
415
416           g_strfreev (list);
417         }
418
419       ptr = g_new (const gchar *, g_hash_table_size (single) + 1);
420       non_relocatable_schema_list = ptr;
421       g_hash_table_foreach_steal (single, steal_item, &ptr);
422       g_hash_table_unref (single);
423       *ptr = NULL;
424
425       ptr = g_new (const gchar *, g_hash_table_size (reloc) + 1);
426       relocatable_schema_list = ptr;
427       g_hash_table_foreach_steal (reloc, steal_item, &ptr);
428       g_hash_table_unref (reloc);
429       *ptr = NULL;
430
431       g_once_init_leave (&schema_lists_initialised, TRUE);
432     }
433 }
434
435 /**
436  * g_settings_list_schemas:
437  *
438  * Gets a list of the #GSettings schemas installed on the system.  The
439  * returned list is exactly the list of schemas for which you may call
440  * g_settings_new() without adverse effects.
441  *
442  * This function does not list the schemas that do not provide their own
443  * paths (ie: schemas for which you must use
444  * g_settings_new_with_path()).  See
445  * g_settings_list_relocatable_schemas() for that.
446  *
447  * Returns: (element-type utf8) (transfer none):  a list of #GSettings
448  *   schemas that are available.  The list must not be modified or
449  *   freed.
450  *
451  * Since: 2.26
452  **/
453 const gchar * const *
454 g_settings_list_schemas (void)
455 {
456   ensure_schema_lists ();
457
458   return non_relocatable_schema_list;
459 }
460
461 /**
462  * g_settings_list_relocatable_schemas:
463  *
464  * Gets a list of the relocatable #GSettings schemas installed on the
465  * system.  These are schemas that do not provide their own path.  It is
466  * usual to instantiate these schemas directly, but if you want to you
467  * can use g_settings_new_with_path() to specify the path.
468  *
469  * The output of this function, taken together with the output of
470  * g_settings_list_schemas() represents the complete list of all
471  * installed schemas.
472  *
473  * Returns: (element-type utf8) (transfer none): a list of relocatable
474  *   #GSettings schemas that are available.  The list must not be
475  *   modified or freed.
476  *
477  * Since: 2.28
478  **/
479 const gchar * const *
480 g_settings_list_relocatable_schemas (void)
481 {
482   ensure_schema_lists ();
483
484   return relocatable_schema_list;
485 }
486
487 /**
488  * g_settings_schema_ref:
489  * @schema: a #GSettingsSchema
490  *
491  * Increase the reference count of @schema, returning a new reference.
492  *
493  * Returns: a new reference to @schema
494  *
495  * Since: 2.32
496  **/
497 GSettingsSchema *
498 g_settings_schema_ref (GSettingsSchema *schema)
499 {
500   g_atomic_int_inc (&schema->ref_count);
501
502   return schema;
503 }
504
505 /**
506  * g_settings_schema_unref:
507  * @schema: a #GSettingsSchema
508  *
509  * Decrease the reference count of @schema, possibly freeing it.
510  *
511  * Since: 2.32
512  **/
513 void
514 g_settings_schema_unref (GSettingsSchema *schema)
515 {
516   if (g_atomic_int_dec_and_test (&schema->ref_count))
517     {
518       gvdb_table_unref (schema->table);
519       g_free (schema->items);
520       g_free (schema->id);
521
522       g_slice_free (GSettingsSchema, schema);
523     }
524 }
525
526 const gchar *
527 g_settings_schema_get_string (GSettingsSchema *schema,
528                               const gchar     *key)
529 {
530   const gchar *result = NULL;
531   GVariant *value;
532
533   if ((value = gvdb_table_get_raw_value (schema->table, key)))
534     {
535       result = g_variant_get_string (value, NULL);
536       g_variant_unref (value);
537     }
538
539   return result;
540 }
541
542 GVariantIter *
543 g_settings_schema_get_value (GSettingsSchema *schema,
544                              const gchar     *key)
545 {
546   GVariantIter *iter;
547   GVariant *value;
548
549   value = gvdb_table_get_raw_value (schema->table, key);
550
551   if G_UNLIKELY (value == NULL)
552     g_error ("Settings schema '%s' does not contain a key named '%s'", schema->id, key);
553
554   iter = g_variant_iter_new (value);
555   g_variant_unref (value);
556
557   return iter;
558 }
559
560 /**
561  * g_settings_schema_get_path:
562  * @schema: a #GSettingsSchema
563  *
564  * Gets the path associated with @schema, or %NULL.
565  *
566  * Schemas may be single-instance or relocatable.  Single-instance
567  * schemas correspond to exactly one set of keys in the backend
568  * database: those located at the path returned by this function.
569  *
570  * Relocatable schemas can be referenced by other schemas and can
571  * threfore describe multiple sets of keys at different locations.  For
572  * relocatable schemas, this function will return %NULL.
573  *
574  * Returns: (transfer none): the path of the schema, or %NULL
575  *
576  * Since: 2.32
577  **/
578 const gchar *
579 g_settings_schema_get_path (GSettingsSchema *schema)
580 {
581   return schema->path;
582 }
583
584 const gchar *
585 g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
586 {
587   return schema->gettext_domain;
588 }
589
590 gboolean
591 g_settings_schema_has_key (GSettingsSchema *schema,
592                            const gchar     *key)
593 {
594   return gvdb_table_has_value (schema->table, key);
595 }
596
597 const GQuark *
598 g_settings_schema_list (GSettingsSchema *schema,
599                         gint            *n_items)
600 {
601   gint i, j;
602
603   if (schema->items == NULL)
604     {
605       gchar **list;
606       gint len;
607
608       list = gvdb_table_list (schema->table, "");
609       len = list ? g_strv_length (list) : 0;
610
611       schema->items = g_new (GQuark, len);
612       j = 0;
613
614       for (i = 0; i < len; i++)
615         if (list[i][0] != '.')
616           schema->items[j++] = g_quark_from_string (list[i]);
617       schema->n_items = j;
618
619       g_strfreev (list);
620     }
621
622   *n_items = schema->n_items;
623   return schema->items;
624 }
625
626 /**
627  * g_settings_schema_get_id:
628  * @schema: a #GSettingsSchema
629  *
630  * Get the ID of @schema.
631  *
632  * Returns: (transfer none): the ID
633  **/
634 const gchar *
635 g_settings_schema_get_id (GSettingsSchema *schema)
636 {
637   return schema->id;
638 }
639
640 static inline void
641 endian_fixup (GVariant **value)
642 {
643 #if G_BYTE_ORDER == G_BIG_ENDIAN
644   GVariant *tmp;
645
646   tmp = g_variant_byteswap (*value);
647   g_variant_unref (*value);
648   *value = tmp;
649 #endif
650 }
651
652 void
653 g_settings_schema_key_init (GSettingsSchemaKey *key,
654                             GSettingsSchema    *schema,
655                             const gchar        *name)
656 {
657   GVariantIter *iter;
658   GVariant *data;
659   guchar code;
660
661   memset (key, 0, sizeof *key);
662
663   iter = g_settings_schema_get_value (schema, name);
664
665   key->schema = g_settings_schema_ref (schema);
666   key->default_value = g_variant_iter_next_value (iter);
667   endian_fixup (&key->default_value);
668   key->type = g_variant_get_type (key->default_value);
669   key->name = g_intern_string (name);
670
671   while (g_variant_iter_next (iter, "(y*)", &code, &data))
672     {
673       switch (code)
674         {
675         case 'l':
676           /* translation requested */
677           g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed);
678           break;
679
680         case 'e':
681           /* enumerated types... */
682           key->is_enum = TRUE;
683           goto choice;
684
685         case 'f':
686           /* flags... */
687           key->is_flags = TRUE;
688           goto choice;
689
690         choice: case 'c':
691           /* ..., choices, aliases */
692           key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32));
693           break;
694
695         case 'r':
696           g_variant_get (data, "(**)", &key->minimum, &key->maximum);
697           endian_fixup (&key->minimum);
698           endian_fixup (&key->maximum);
699           break;
700
701         default:
702           g_warning ("unknown schema extension '%c'", code);
703           break;
704         }
705
706       g_variant_unref (data);
707     }
708
709   g_variant_iter_free (iter);
710 }
711
712 void
713 g_settings_schema_key_clear (GSettingsSchemaKey *key)
714 {
715   if (key->minimum)
716     g_variant_unref (key->minimum);
717
718   if (key->maximum)
719     g_variant_unref (key->maximum);
720
721   g_variant_unref (key->default_value);
722
723   g_settings_schema_unref (key->schema);
724 }
725
726 gboolean
727 g_settings_schema_key_type_check (GSettingsSchemaKey *key,
728                                   GVariant           *value)
729 {
730   g_return_val_if_fail (value != NULL, FALSE);
731
732   return g_variant_is_of_type (value, key->type);
733 }
734
735 gboolean
736 g_settings_schema_key_range_check (GSettingsSchemaKey *key,
737                                    GVariant           *value)
738 {
739   if (key->minimum == NULL && key->strinfo == NULL)
740     return TRUE;
741
742   if (g_variant_is_container (value))
743     {
744       gboolean ok = TRUE;
745       GVariantIter iter;
746       GVariant *child;
747
748       g_variant_iter_init (&iter, value);
749       while (ok && (child = g_variant_iter_next_value (&iter)))
750         {
751           ok = g_settings_schema_key_range_check (key, child);
752           g_variant_unref (child);
753         }
754
755       return ok;
756     }
757
758   if (key->minimum)
759     {
760       return g_variant_compare (key->minimum, value) <= 0 &&
761              g_variant_compare (value, key->maximum) <= 0;
762     }
763
764   return strinfo_is_string_valid (key->strinfo, key->strinfo_length,
765                                   g_variant_get_string (value, NULL));
766 }
767
768 GVariant *
769 g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
770                                    GVariant           *value)
771 {
772   const gchar *target;
773
774   if (g_settings_schema_key_range_check (key, value))
775     return g_variant_ref (value);
776
777   if (key->strinfo == NULL)
778     return NULL;
779
780   if (g_variant_is_container (value))
781     {
782       GVariantBuilder builder;
783       GVariantIter iter;
784       GVariant *child;
785
786       g_variant_iter_init (&iter, value);
787       g_variant_builder_init (&builder, g_variant_get_type (value));
788
789       while ((child = g_variant_iter_next_value (&iter)))
790         {
791           GVariant *fixed;
792
793           fixed = g_settings_schema_key_range_fixup (key, child);
794           g_variant_unref (child);
795
796           if (fixed == NULL)
797             {
798               g_variant_builder_clear (&builder);
799               return NULL;
800             }
801
802           g_variant_builder_add_value (&builder, fixed);
803           g_variant_unref (fixed);
804         }
805
806       return g_variant_ref_sink (g_variant_builder_end (&builder));
807     }
808
809   target = strinfo_string_from_alias (key->strinfo, key->strinfo_length,
810                                       g_variant_get_string (value, NULL));
811   return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL;
812 }
813
814
815 GVariant *
816 g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
817 {
818   const gchar *translated;
819   GError *error = NULL;
820   const gchar *domain;
821   GVariant *value;
822
823   domain = g_settings_schema_get_gettext_domain (key->schema);
824
825   if (key->lc_char == '\0')
826     /* translation not requested for this key */
827     return NULL;
828
829   if (key->lc_char == 't')
830     translated = g_dcgettext (domain, key->unparsed, LC_TIME);
831   else
832     translated = g_dgettext (domain, key->unparsed);
833
834   if (translated == key->unparsed)
835     /* the default value was not translated */
836     return NULL;
837
838   /* try to parse the translation of the unparsed default */
839   value = g_variant_parse (key->type, translated, NULL, NULL, &error);
840
841   if (value == NULL)
842     {
843       g_warning ("Failed to parse translated string `%s' for "
844                  "key `%s' in schema `%s': %s", key->unparsed, key->name,
845                  g_settings_schema_get_id (key->schema), error->message);
846       g_warning ("Using untranslated default instead.");
847       g_error_free (error);
848     }
849
850   else if (!g_settings_schema_key_range_check (key, value))
851     {
852       g_warning ("Translated default `%s' for key `%s' in schema `%s' "
853                  "is outside of valid range", key->unparsed, key->name,
854                  g_settings_schema_get_id (key->schema));
855       g_variant_unref (value);
856       value = NULL;
857     }
858
859   return value;
860 }
861
862 gint
863 g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
864                                GVariant           *value)
865 {
866   gboolean it_worked;
867   guint result;
868
869   it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length,
870                                         g_variant_get_string (value, NULL),
871                                         &result);
872
873   /* 'value' can only come from the backend after being filtered for validity,
874    * from the translation after being filtered for validity, or from the schema
875    * itself (which the schema compiler checks for validity).  If this assertion
876    * fails then it's really a bug in GSettings or the schema compiler...
877    */
878   g_assert (it_worked);
879
880   return result;
881 }
882
883 GVariant *
884 g_settings_schema_key_from_enum (GSettingsSchemaKey *key,
885                                  gint                value)
886 {
887   const gchar *string;
888
889   string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value);
890
891   if (string == NULL)
892     return NULL;
893
894   return g_variant_new_string (string);
895 }
896
897 guint
898 g_settings_schema_key_to_flags (GSettingsSchemaKey *key,
899                                 GVariant           *value)
900 {
901   GVariantIter iter;
902   const gchar *flag;
903   guint result;
904
905   result = 0;
906   g_variant_iter_init (&iter, value);
907   while (g_variant_iter_next (&iter, "&s", &flag))
908     {
909       gboolean it_worked;
910       guint flag_value;
911
912       it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value);
913       /* as in g_settings_to_enum() */
914       g_assert (it_worked);
915
916       result |= flag_value;
917     }
918
919   return result;
920 }
921
922 GVariant *
923 g_settings_schema_key_from_flags (GSettingsSchemaKey *key,
924                                   guint               value)
925 {
926   GVariantBuilder builder;
927   gint i;
928
929   g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
930
931   for (i = 0; i < 32; i++)
932     if (value & (1u << i))
933       {
934         const gchar *string;
935
936         string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i);
937
938         if (string == NULL)
939           {
940             g_variant_builder_clear (&builder);
941             return NULL;
942           }
943
944         g_variant_builder_add (&builder, "s", string);
945       }
946
947   return g_variant_builder_end (&builder);
948 }