resources: Add to-pixdata preprocessing option
[platform/upstream/glib.git] / gio / gresource.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2011 Red Hat, Inc
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 License, 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
16  * Public 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  * Authors: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "gresource.h"
28 #include <gvdb/gvdb-reader.h>
29 #include <gi18n.h>
30 #include <gio/gmemoryinputstream.h>
31 #include <gio/gzlibdecompressor.h>
32 #include <gio/gconverterinputstream.h>
33
34 struct _GResource
35 {
36   int ref_count;
37
38   GvdbTable *table;
39 };
40
41 static void register_lazy_static_resources ();
42
43 G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref)
44
45 /**
46  * SECTION:gresource
47  * @short_description: Resource framework
48  * @include: gio/gio.h
49  *
50  * Applications and libraries often contain binary or textual data that is really part of the
51  * application, rather than user data. For instance #GtkBuilder .ui files, splashscreen images,
52  * GMenu markup xml, CSS files, icons, etc. These are often shipped as files in <filename>$datadir/appname</filename>, or
53  * manually included as literal strings in the code.
54  *
55  * The #GResource API and the <link linkend="glib-compile-resources">glib-compile-resources</link> program
56  * provide a convenient and efficient alternative to this which has some nice properties. You
57  * maintain the files as normal files, so its easy to edit them, but during the build the files
58  * are combined into a binary bundle that is linked into the executable. This means that loading
59  * the resource files are efficient (as they are already in memory, shared with other instances) and
60  * simple (no need to check for things like I/O errors or locate the files in the filesystem). It
61  * also makes it easier to create relocatable applications.
62  *
63  * Resource files can also be marked as compresses. Such files will be included in the resource bundle
64  * in a compressed form, but will be automatically uncompressed when the resource is used. This
65  * is very useful e.g. for larger text files that are parsed once (or rarely) and then thrown away.
66  *
67  * Resource files can also be marked to be preprocessed, by setting the value of the
68  * <literal>preprocess</literal> attribute to a comma-separated list of preprocessing options.
69  * The only options currently supported are:
70  *
71  * <literal>xml-stripblanks</literal> which will use <literal>xmllint</literal> to strip
72  * ignorable whitespace from the xml file. For this to work, the <envar>XMLLINT</envar>
73  * environment variable must be set to the full path to the xmllint executable, or xmllint
74  * must be in the PATH; otherwise the preprocessing step is skipped.
75  *
76  * <literal>to-pixdata</literal> which will use <literal>gdk-pixbuf-pixdata</literal> to convert
77  * images to the GdkPixdata format, which allows you to create pixbufs directly using the data inside
78  * the resource file, rather than an (uncompressed) copy if it. For this to work, the gdk-pixbuf-pixdata
79  * program must be in the PATH, or the <envar>GDK_PIXBUF_PIXDATA</envar> environment variable must be
80  * set to the full path to the gdk-pixbuf-pixdata executable; otherwise the preprocessing step is skipped.
81  *
82  * Resource bundles are created by the <link linkend="glib-compile-resources">glib-compile-resources</link> program
83  * which takes an xml file that describes the bundle, and a set of files that the xml references. These
84  * are combined into a binary resource bundle.
85  *
86  * <example id="resource-example"><title>Example resource description</title>
87  * <programlisting><![CDATA[
88  * <?xml version="1.0" encoding="UTF-8"?>
89  * <gresources>
90  *   <gresource prefix="/org/gtk/Example">
91  *     <file>data/splashscreen.png</file>
92  *     <file compressed="true">dialog.ui</file>
93  *     <file preprocess="xml-stripblanks">menumarkup.xml</file>
94  *   </gresource>
95  * </gresources>
96  * ]]></programlisting></example>
97  *
98  * This will create a resource bundle with the following files:
99  * <programlisting><![CDATA[
100  * /org/gtk/Example/data/splashscreen.png
101  * /org/gtk/Example/dialog.ui
102  * /org/gtk/Example/menumarkup.xml
103  * ]]></programlisting>
104  *
105  * Note that all resources in the process share the same namespace, so use java-style
106  * path prefixes (like in the above example) to avoid conflicts.
107  *
108  * You can then use <link linkend="glib-compile-resources">glib-compile-resources</link> to compile the xml to a
109  * binary bundle that you can load with g_resource_load(). However, its more common to use the --generate-source and
110  * --generate-header arguments to create a source file and header to link directly into your application.
111  *
112  * Once a #GResource has been created and registered all the data in it can be accessed globally in the process by
113  * using API calls like g_resources_open_stream() to stream the data or g_resources_lookup_data() to get a direct pointer
114  * to the data. You can also use uris like "resource:///org/gtk/Example/data/splashscreen.png" with #GFile to access
115  * the resource data.
116  *
117  * There are two forms of the generated source, the default version uses the compiler support for constructor
118  * and destructor functions (where availible) to automatically create and register the #GResource on startup
119  * or library load time. If you pass --manual-register two functions to register/unregister the resource is instead
120  * created. This requires an explicit initialization call in your application/library, but it works on all platforms,
121  * even on the minor ones where this is not availible. (Constructor support is availible for at least Win32, MacOS and Linux.)
122  *
123  * Note that resource data can point directly into the data segment of e.g. a library, so if you are unloading libraries
124  * during runtime you need to be very careful with keeping around pointers to data from a resource, as this goes away
125  * when the library is unloaded. However, in practice this is not generally a problem, since most resource accesses
126  * is for your own resources, and resource data is often used once, during parsing, and then released.
127  *
128  * Since: 2.32
129  */
130
131 /**
132  * g_resource_error_quark:
133  *
134  * Gets the #GResource Error Quark.
135  *
136  * Return value: a #GQuark.
137  *
138  * Since: 2.32
139  */
140 GQuark
141 g_resource_error_quark (void)
142 {
143   return g_quark_from_static_string ("g-resource-error-quark");
144 }
145
146 /**
147  * g_resource_ref:
148  * @resource: A #GResource.
149  *
150  * Atomically increments the reference count of @array by one. This
151  * function is MT-safe and may be called from any thread.
152  *
153  * Returns: The passed in #GResource.
154  *
155  * Since: 2.32
156  **/
157 GResource *
158 g_resource_ref (GResource *resource)
159 {
160   g_atomic_int_inc (&resource->ref_count);
161   return resource;
162 }
163
164 /**
165  * g_resource_unref:
166  * @resource: A #GResource.
167  *
168  * Atomically decrements the reference count of @resource by one. If the
169  * reference count drops to 0, all memory allocated by the array is
170  * released. This function is MT-safe and may be called from any
171  * thread.
172  *
173  * Since: 2.32
174  **/
175 void
176 g_resource_unref (GResource *resource)
177 {
178   if (g_atomic_int_dec_and_test (&resource->ref_count))
179     {
180       gvdb_table_unref (resource->table);
181       g_free (resource);
182     }
183 }
184
185 /**
186  * g_resource_new_from_data:
187  * @data: A #GBytes.
188  * @error: return location for a #GError, or %NULL.
189  *
190  * Creates a GResource from a reference to the binary resource bundle.
191  * This will keep a reference to @data while the resource lives, so
192  * the data should not be modified or freed.
193  *
194  * If you want to use this resource in the global resource namespace you need
195  * to register it with g_resources_register().
196  *
197  * Return value: (transfer full): a new #GResource, or %NULL on error.
198  *
199  * Since: 2.32
200  **/
201 GResource *
202 g_resource_new_from_data (GBytes *data,
203                           GError **error)
204 {
205   GResource *resource;
206   GvdbTable *table;
207
208   table = gvdb_table_new_from_data (g_bytes_get_data (data, NULL),
209                                     g_bytes_get_size (data),
210                                     TRUE,
211                                     g_bytes_ref (data),
212                                     (GvdbRefFunc)g_bytes_ref,
213                                     (GDestroyNotify)g_bytes_unref,
214                                     error);
215
216   if (table == NULL)
217     return NULL;
218
219   resource = g_new0 (GResource, 1);
220   resource->ref_count = 1;
221   resource->table = table;
222
223   return resource;
224 }
225
226 /**
227  * g_resource_load:
228  * @filename: (type filename): the path of a filename to load, in the GLib filename encoding.
229  * @error: return location for a #GError, or %NULL.
230  *
231  * Loads a binary resource bundle and creates a #GResource representation of it, allowing
232  * you to query it for data.
233  *
234  * If you want to use this resource in the global resource namespace you need
235  * to register it with g_resources_register().
236  *
237  * Return value: (transfer full): a new #GResource, or %NULL on error.
238  *
239  * Since: 2.32
240  **/
241 GResource *
242 g_resource_load (const gchar *filename,
243                  GError **error)
244 {
245   GResource *resource;
246   GvdbTable *table;
247
248   table = gvdb_table_new (filename, FALSE, error);
249   if (table == NULL)
250     return NULL;
251
252   resource = g_new0 (GResource, 1);
253   resource->table = table;
254
255   return resource;
256 }
257
258 static gboolean do_lookup (GResource *resource,
259                            const char *path,
260                            GResourceLookupFlags lookup_flags,
261                            gsize *size,
262                            guint32 *flags,
263                            const void **data,
264                            gsize *data_size,
265                            GError **error)
266 {
267   char *free_path = NULL;
268   gsize path_len;
269   gboolean res = FALSE;
270   GVariant *value;
271
272   path_len = strlen (path);
273   if (path[path_len-1] == '/')
274     {
275       path = free_path = g_strdup (path);
276       free_path[path_len-1] = 0;
277     }
278
279   value = gvdb_table_get_value (resource->table, path);
280
281   if (value == NULL)
282     {
283       g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
284                    _("The resource at '%s' does not exist"),
285                    path);
286     }
287   else
288     {
289       guint32 _size, _flags;
290       GVariant *array;
291
292       g_variant_get (value, "(uu@ay)",
293                      &_size,
294                      &_flags,
295                      &array);
296
297       if (!res)
298         {
299           if (size)
300             *size = _size;
301           if (flags)
302             *flags = _flags;
303           if (data)
304             *data = g_variant_get_data (array);
305           if (data_size)
306             {
307               /* Don't report trailing newline that non-compressed files has */
308               if (_flags & G_RESOURCE_FLAGS_COMPRESSED)
309                 *data_size = g_variant_get_size (array);
310               else
311                 *data_size = g_variant_get_size (array) - 1;
312             }
313           res = TRUE;
314         }
315     }
316
317   g_free (free_path);
318   return res;
319 }
320
321 /**
322  * g_resource_open_stream:
323  * @resource: A #GResource.
324  * @path: A pathname inside the resource.
325  * @lookup_flags: A #GResourceLookupFlags.
326  * @error: return location for a #GError, or %NULL.
327  *
328  * Looks for a file at the specified @path in the resource and
329  * returns a #GInputStream that lets you read the data.
330  *
331  * @lookup_flags controls the behaviour of the lookup.
332  *
333  * Returns: (transfer full): #GInputStream or %NULL on error.
334  *     Free the returned object with g_object_unref().
335  *
336  * Since: 2.32
337  **/
338 GInputStream *
339 g_resource_open_stream (GResource *resource,
340                         const char *path,
341                         GResourceLookupFlags lookup_flags,
342                         GError **error)
343 {
344   const void *data;
345   gsize data_size;
346   guint32 flags;
347   GInputStream *stream, *stream2;
348
349   if (!do_lookup (resource, path, lookup_flags, NULL, &flags, &data, &data_size, error))
350     return NULL;
351
352   stream = g_memory_input_stream_new_from_data (data, data_size, NULL);
353   g_object_set_data_full (G_OBJECT (stream), "g-resource",
354                           g_resource_ref (resource),
355                           (GDestroyNotify)g_resource_unref);
356
357   if (flags & G_RESOURCE_FLAGS_COMPRESSED)
358     {
359       GZlibDecompressor *decompressor =
360         g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
361
362       stream2 = g_converter_input_stream_new (stream, G_CONVERTER (decompressor));
363       g_object_unref (decompressor);
364       g_object_unref (stream);
365       stream = stream2;
366     }
367
368   return stream;
369 }
370
371 /**
372  * g_resource_lookup_data:
373  * @resource: A #GResource.
374  * @path: A pathname inside the resource.
375  * @lookup_flags: A #GResourceLookupFlags.
376  * @error: return location for a #GError, or %NULL.
377  *
378  * Looks for a file at the specified @path in the resource and
379  * returns a #GBytes that lets you directly access the data in
380  * memory.
381  *
382  * The data is always followed by a zero byte, so you
383  * can safely use the data as a C string. However, that byte
384  * is not included in the size of the GBytes.
385  *
386  * For uncompressed resource files this is a pointer directly into
387  * the resource bundle, which is typically in some readonly data section
388  * in the program binary. For compressed files we allocate memory on
389  * the heap and automatically uncompress the data.
390  *
391  * @lookup_flags controls the behaviour of the lookup.
392  *
393  * Returns: (transfer full): #GBytes or %NULL on error.
394  *     Free the returned object with g_bytes_unref().
395  *
396  * Since: 2.32
397  **/
398 GBytes *
399 g_resource_lookup_data (GResource *resource,
400                         const char *path,
401                         GResourceLookupFlags lookup_flags,
402                         GError **error)
403 {
404   const void *data;
405   guint32 flags;
406   gsize data_size;
407   gsize size;
408
409   if (!do_lookup (resource, path, lookup_flags, &size, &flags, &data, &data_size, error))
410     return NULL;
411
412   if (flags & G_RESOURCE_FLAGS_COMPRESSED)
413     {
414       char *uncompressed, *d;
415       const char *s;
416       GConverterResult res;
417       gsize d_size, s_size;
418       gsize bytes_read, bytes_written;
419
420
421       GZlibDecompressor *decompressor =
422         g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_ZLIB);
423
424       uncompressed = g_malloc (size + 1);
425
426       s = data;
427       s_size = data_size;
428       d = uncompressed;
429       d_size = size;
430
431       do
432         {
433           res = g_converter_convert (G_CONVERTER (decompressor),
434                                      s, s_size,
435                                      d, d_size,
436                                      G_CONVERTER_INPUT_AT_END,
437                                      &bytes_read,
438                                      &bytes_written,
439                                      NULL);
440           if (res == G_CONVERTER_ERROR)
441             {
442               g_free (uncompressed);
443               g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL,
444                            _("The resource at '%s' failed to decompress"),
445                            path);
446               return NULL;
447
448             }
449           s += bytes_read;
450           s_size -= bytes_read;
451           d += bytes_written;
452           d_size -= bytes_written;
453         }
454       while (res != G_CONVERTER_FINISHED);
455
456       uncompressed[size] = 0; /* Zero terminate */
457
458       return g_bytes_new_take (uncompressed, size);
459     }
460   else
461     return g_bytes_new_with_free_func (data, data_size, (GDestroyNotify)g_resource_unref, g_resource_ref (resource));
462 }
463
464 /**
465  * g_resource_get_info:
466  * @resource: A #GResource.
467  * @path: A pathname inside the resource.
468  * @lookup_flags: A #GResourceLookupFlags.
469  * @size:  (out) (allow-none): a location to place the length of the contents of the file,
470  *    or %NULL if the length is not needed
471  * @flags:  (out) (allow-none): a location to place the flags about the file,
472  *    or %NULL if the length is not needed
473  * @error: return location for a #GError, or %NULL.
474  *
475  * Looks for a file at the specified @path in the resource and
476  * if found returns information about it.
477  *
478  * @lookup_flags controls the behaviour of the lookup.
479  *
480  * Returns: %TRUE if the file was found. %FALSE if there were errors.
481  *
482  * Since: 2.32
483  **/
484 gboolean
485 g_resource_get_info (GResource *resource,
486                      const char *path,
487                      GResourceLookupFlags lookup_flags,
488                      gsize *size,
489                      guint32 *flags,
490                      GError **error)
491 {
492   return do_lookup (resource, path, lookup_flags, size, flags, NULL, NULL, error);
493 }
494
495 /**
496  * g_resource_enumerate_children:
497  * @resource: A #GResource.
498  * @path: A pathname inside the resource.
499  * @lookup_flags: A #GResourceLookupFlags.
500  * @error: return location for a #GError, or %NULL.
501  *
502  * Returns all the names of children at the specified @path in the resource.
503  * The return result is a %NULL terminated list of strings which should
504  * be released with g_strfreev().
505  *
506  * @lookup_flags controls the behaviour of the lookup.
507  *
508  * Returns: (array zero-terminated=1) (transfer full): an array of constant strings
509  *
510  * Since: 2.32
511  **/
512 char **
513 g_resource_enumerate_children (GResource *resource,
514                                const char *path,
515                                GResourceLookupFlags lookup_flags,
516                                GError **error)
517 {
518   gchar **children;
519   gsize path_len;
520   char *path_with_slash;
521
522   if (*path == 0)
523     {
524       g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
525                    _("The resource at '%s' does not exist"),
526                    path);
527       return NULL;
528     }
529
530   path_len = strlen (path);
531   if (path[path_len-1] != '/')
532     path_with_slash = g_strconcat (path, "/", NULL);
533   else
534     path_with_slash = g_strdup (path);
535
536   children = gvdb_table_list (resource->table, path_with_slash);
537   g_free (path_with_slash);
538
539   if (children == NULL)
540     {
541       g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
542                    _("The resource at '%s' does not exist"),
543                    path);
544       return NULL;
545     }
546
547   return children;
548 }
549
550 static GRWLock resources_lock;
551 static GList *registered_resources;
552
553 /* This is updated atomically, so we can append to it and check for NULL outside the
554    lock, but all other accesses are done under the write lock */
555 static GStaticResource *lazy_register_resources;
556
557 static void
558 g_resources_register_unlocked (GResource *resource)
559 {
560   registered_resources = g_list_prepend (registered_resources,
561                                         g_resource_ref (resource));
562 }
563
564 static void
565 g_resources_unregister_unlocked (GResource *resource)
566 {
567   if (g_list_find (registered_resources, resource) == NULL)
568     {
569       g_warning ("Tried to remove not registred resource");
570     }
571   else
572     {
573       registered_resources = g_list_remove (registered_resources,
574                                            resource);
575       g_resource_unref (resource);
576     }
577 }
578
579 /**
580  * g_resources_register:
581  * @resource: A #GResource.
582  *
583  * Registers the resource with the process-global set of resources.
584  * Once a resource is registered the files in it can be accessed
585  * with the global resource lookup functions like g_resources_lookup_data().
586  *
587  * Since: 2.32
588  **/
589 void
590 g_resources_register (GResource *resource)
591 {
592   g_rw_lock_writer_lock (&resources_lock);
593   g_resources_register_unlocked (resource);
594   g_rw_lock_writer_unlock (&resources_lock);
595 }
596
597 /**
598  * g_resources_unregister:
599  * @resource: A #GResource.
600  *
601  * Unregisters the resource from the process-global set of resources.
602  *
603  * Since: 2.32
604  **/
605 void
606 g_resources_unregister (GResource *resource)
607 {
608   g_rw_lock_writer_lock (&resources_lock);
609   g_resources_unregister_unlocked (resource);
610   g_rw_lock_writer_unlock (&resources_lock);
611 }
612
613 /**
614  * g_resources_open_stream:
615  * @path: A pathname inside the resource.
616  * @lookup_flags: A #GResourceLookupFlags.
617  * @error: return location for a #GError, or %NULL.
618  *
619  * Looks for a file at the specified @path in the set of
620  * globally registred resources and returns a #GInputStream
621  * that lets you read the data.
622  *
623  * @lookup_flags controls the behaviour of the lookup.
624  *
625  * Returns: (transfer full): #GInputStream or %NULL on error.
626  *     Free the returned object with g_object_unref().
627  *
628  * Since: 2.32
629  **/
630 GInputStream *
631 g_resources_open_stream (const char *path,
632                          GResourceLookupFlags lookup_flags,
633                          GError **error)
634 {
635   GInputStream *res = NULL;
636   GList *l;
637   GInputStream *stream;
638
639   register_lazy_static_resources ();
640
641   g_rw_lock_reader_lock (&resources_lock);
642
643   for (l = registered_resources; l != NULL; l = l->next)
644     {
645       GResource *r = l->data;
646       GError *my_error = NULL;
647
648       stream = g_resource_open_stream (r, path, lookup_flags, &my_error);
649       if (stream == NULL &&
650           g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
651         {
652           g_clear_error (&my_error);
653         }
654       else
655         {
656           if (stream == NULL)
657             g_propagate_error (error, my_error);
658           res = stream;
659           break;
660         }
661     }
662
663   if (l == NULL)
664     g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
665                  _("The resource at '%s' does not exist"),
666                  path);
667
668   g_rw_lock_reader_unlock (&resources_lock);
669
670   return res;
671 }
672
673 /**
674  * g_resources_lookup_data:
675  * @path: A pathname inside the resource.
676  * @lookup_flags: A #GResourceLookupFlags.
677  * @error: return location for a #GError, or %NULL.
678  *
679  * Looks for a file at the specified @path in the set of
680  * globally registred resources and returns a #GBytes that
681  * lets you directly access the data in memory.
682  *
683  * The data is always followed by a zero byte, so you
684  * can safely use the data as a C string. However, that byte
685  * is not included in the size of the GBytes.
686  *
687  * For uncompressed resource files this is a pointer directly into
688  * the resource bundle, which is typically in some readonly data section
689  * in the program binary. For compressed files we allocate memory on
690  * the heap and automatically uncompress the data.
691  *
692  * @lookup_flags controls the behaviour of the lookup.
693  *
694  * Returns: (transfer full): #GBytes or %NULL on error.
695  *     Free the returned object with g_bytes_unref().
696  *
697  * Since: 2.32
698  **/
699 GBytes *
700 g_resources_lookup_data (const char *path,
701                          GResourceLookupFlags lookup_flags,
702                          GError **error)
703 {
704   GBytes *res = NULL;
705   GList *l;
706   GBytes *data;
707
708   register_lazy_static_resources ();
709
710   g_rw_lock_reader_lock (&resources_lock);
711
712   for (l = registered_resources; l != NULL; l = l->next)
713     {
714       GResource *r = l->data;
715       GError *my_error = NULL;
716
717       data = g_resource_lookup_data (r, path, lookup_flags, &my_error);
718       if (data == NULL &&
719           g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
720         {
721           g_clear_error (&my_error);
722         }
723       else
724         {
725           if (data == NULL)
726             g_propagate_error (error, my_error);
727           res = data;
728           break;
729         }
730     }
731
732   if (l == NULL)
733     g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
734                  _("The resource at '%s' does not exist"),
735                  path);
736
737   g_rw_lock_reader_unlock (&resources_lock);
738
739   return res;
740 }
741
742 /**
743  * g_resources_enumerate_children:
744  * @path: A pathname inside the resource.
745  * @lookup_flags: A #GResourceLookupFlags.
746  * @error: return location for a #GError, or %NULL.
747  *
748  * Returns all the names of children at the specified @path in the set of
749  * globally registred resources.
750  * The return result is a %NULL terminated list of strings which should
751  * be released with g_strfreev().
752  *
753  * @lookup_flags controls the behaviour of the lookup.
754  *
755  * Returns: (array zero-terminated=1) (transfer full): an array of constant strings
756  *
757  * Since: 2.32
758  **/
759 char **
760 g_resources_enumerate_children (const char *path,
761                                 GResourceLookupFlags lookup_flags,
762                                 GError **error)
763 {
764   GHashTable *hash = NULL;
765   GList *l;
766   char **children;
767   int i;
768
769   register_lazy_static_resources ();
770
771   g_rw_lock_reader_lock (&resources_lock);
772
773   for (l = registered_resources; l != NULL; l = l->next)
774     {
775       GResource *r = l->data;
776
777       children = g_resource_enumerate_children (r, path, 0, NULL);
778
779       if (children != NULL)
780         {
781           if (hash == NULL)
782             hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
783
784           for (i = 0; children[i] != NULL; i++)
785             g_hash_table_insert (hash, children[i], children[i]);
786           g_free (children);
787         }
788     }
789
790   g_rw_lock_reader_unlock (&resources_lock);
791
792   if (hash == NULL)
793     {
794       g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
795                    _("The resource at '%s' does not exist"),
796                    path);
797       return NULL;
798     }
799   else
800     {
801       GHashTableIter iter;
802       const char *key;
803       guint n_children;
804       n_children = g_hash_table_size (hash);
805       children = g_new (char *, n_children + 1);
806       i = 0;
807
808       g_hash_table_iter_init (&iter, hash);
809       while (g_hash_table_iter_next (&iter, (gpointer *)&key, NULL))
810         children[i++] = g_strdup (key);
811       children[i++] = NULL;
812
813       g_hash_table_destroy (hash);
814
815       return children;
816     }
817 }
818
819 /**
820  * g_resources_get_info:
821  * @path: A pathname inside the resource.
822  * @lookup_flags: A #GResourceLookupFlags.
823  * @size:  (out) (allow-none): a location to place the length of the contents of the file,
824  *    or %NULL if the length is not needed
825  * @flags:  (out) (allow-none): a location to place the flags about the file,
826  *    or %NULL if the length is not needed
827  * @error: return location for a #GError, or %NULL.
828  *
829  * Looks for a file at the specified @path in the set of
830  * globally registred resources and if found returns information about it.
831  *
832  * @lookup_flags controls the behaviour of the lookup.
833  *
834  * Returns: %TRUE if the file was found. %FALSE if there were errors.
835  *
836  * Since: 2.32
837  **/
838 gboolean
839 g_resources_get_info (const char   *path,
840                       GResourceLookupFlags lookup_flags,
841                       gsize        *size,
842                       guint32      *flags,
843                       GError      **error)
844 {
845   gboolean res = FALSE;
846   GList *l;
847   gboolean r_res;
848
849   register_lazy_static_resources ();
850
851   g_rw_lock_reader_lock (&resources_lock);
852
853   for (l = registered_resources; l != NULL; l = l->next)
854     {
855       GResource *r = l->data;
856       GError *my_error = NULL;
857
858       r_res = g_resource_get_info (r, path, lookup_flags, size, flags, &my_error);
859       if (!r_res &&
860           g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
861         {
862           g_clear_error (&my_error);
863         }
864       else
865         {
866           if (!r_res)
867             g_propagate_error (error, my_error);
868           res = r_res;
869           break;
870         }
871     }
872
873   if (l == NULL)
874     g_set_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND,
875                  _("The resource at '%s' does not exist"),
876                  path);
877
878   g_rw_lock_reader_unlock (&resources_lock);
879
880   return res;
881 }
882
883 /* This code is to handle registration of resources very early, from a constructor.
884  * At that point we'd like to do minimal work, to avoid ordering issues. For instance,
885  * we're not allowed to use g_malloc, as the user need to be able to call g_mem_set_vtable
886  * before the first call to g_malloc.
887  *
888  * So, what we do at construction time is that we just register a static structure on
889  * a list of resources that need to be initialized, and then later, when doing any lookups
890  * in the global list of registered resources, or when getting a reference to the
891  * lazily initialized resource we lazily create and register all the GResources on
892  * the lazy list.
893  *
894  * To avoid having to use locks in the constructor, and having to grab the writer lock
895  * when checking the lazy registering list we update lazy_register_resources in
896  * a lock-less fashion (atomic prepend-only, atomic replace with NULL). However, all
897  * operations except:
898  *  * check if there are any resources to lazily initialize
899  *  * Add a static resource to the lazy init list
900  * Do use the full writer lock for protection.
901  */
902
903 static void
904 register_lazy_static_resources_unlocked ()
905 {
906   GStaticResource *list;
907
908   do
909     list = lazy_register_resources;
910   while (!g_atomic_pointer_compare_and_exchange (&lazy_register_resources, list, NULL));
911
912   while (list != NULL)
913     {
914       GBytes *bytes = g_bytes_new_static (list->data, list->data_len);
915       GResource *resource = g_resource_new_from_data (bytes, NULL);
916       if (resource)
917         {
918           g_resources_register_unlocked (resource);
919           g_atomic_pointer_set (&list->resource, resource);
920         }
921       g_bytes_unref (bytes);
922
923       list = list->next;
924     }
925 }
926
927 static void
928 register_lazy_static_resources ()
929 {
930   if (g_atomic_pointer_get (&lazy_register_resources) == NULL)
931     return;
932
933   g_rw_lock_writer_lock (&resources_lock);
934   register_lazy_static_resources_unlocked ();
935   g_rw_lock_writer_unlock (&resources_lock);
936 }
937
938 /**
939  * g_static_resource_init:
940  * @static_resource: pointer to a static #GStaticResource.
941  *
942  * Initializes a GResource from static data using a
943  * GStaticResource.
944  *
945  * This is normally used by code generated by
946  * <link linkend="glib-compile-resources">glib-compile-resources</link> and is
947  * not typically used by other code.
948  *
949  * Since: 2.32
950  **/
951 void
952 g_static_resource_init (GStaticResource *static_resource)
953 {
954   gpointer next;
955
956   do
957     {
958       next = lazy_register_resources;
959       static_resource->next = next;
960     }
961   while (!g_atomic_pointer_compare_and_exchange (&lazy_register_resources, next, static_resource));
962 }
963
964 /**
965  * g_static_resource_fini:
966  * @static_resource: pointer to a static #GStaticResource.
967  *
968  * Finalized a GResource initialized by g_static_resource_init ().
969  *
970  * This is normally used by code generated by
971  * <link linkend="glib-compile-resources">glib-compile-resources</link> and is
972  * not typically used by other code.
973  *
974  * Since: 2.32
975  **/
976 void
977 g_static_resource_fini (GStaticResource *static_resource)
978 {
979   GResource *resource;
980
981   g_rw_lock_writer_lock (&resources_lock);
982
983   register_lazy_static_resources_unlocked ();
984
985   resource = g_atomic_pointer_get (&static_resource->resource);
986   if (resource)
987     {
988       g_atomic_pointer_set (&static_resource->resource, NULL);
989       g_resources_unregister_unlocked (resource);
990       g_resource_unref (resource);
991     }
992
993   g_rw_lock_writer_unlock (&resources_lock);
994 }
995
996 /**
997  * g_static_resource_get_resource:
998  * @static_resource: pointer to a static #GStaticResource.
999  *
1000  * Gets the GResource that was registred by a call to g_static_resource_init ().
1001  *
1002  * This is normally used by code generated by
1003  * <link linkend="glib-compile-resources">glib-compile-resources</link> and is
1004  * not typically used by other code.
1005  *
1006  * Return value:  (transfer none): a #GResource.
1007  *
1008  * Since: 2.32
1009  **/
1010 GResource *
1011 g_static_resource_get_resource  (GStaticResource *static_resource)
1012 {
1013   register_lazy_static_resources ();
1014
1015   return g_atomic_pointer_get (&static_resource->resource);
1016 }