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