tizen: kdbus: make i explicitly positive in make_single_header_vector
[platform/upstream/glib.git] / gio / gresourcefile.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "gresource.h"
28 #include "gresourcefile.h"
29 #include "gfileattribute.h"
30 #include <gfileattribute-priv.h>
31 #include <gfileinfo-priv.h>
32 #include "gfile.h"
33 #include "gfilemonitor.h"
34 #include "gseekable.h"
35 #include "gfileinputstream.h"
36 #include "gfileinfo.h"
37 #include "gfileenumerator.h"
38 #include "gcontenttype.h"
39 #include "gioerror.h"
40 #include <glib/gstdio.h>
41 #include "glibintl.h"
42
43 struct _GResourceFile
44 {
45   GObject parent_instance;
46
47   char *path;
48 };
49
50 struct _GResourceFileEnumerator
51 {
52   GFileEnumerator parent;
53
54   GFileAttributeMatcher *matcher;
55   char *path;
56   char *attributes;
57   GFileQueryInfoFlags flags;
58   int index;
59
60   char **children;
61 };
62
63 struct _GResourceFileEnumeratorClass
64 {
65   GFileEnumeratorClass parent_class;
66 };
67
68 typedef struct _GResourceFileEnumerator        GResourceFileEnumerator;
69 typedef struct _GResourceFileEnumeratorClass   GResourceFileEnumeratorClass;
70
71 static void g_resource_file_file_iface_init (GFileIface *iface);
72
73 static GFileAttributeInfoList *resource_writable_attributes = NULL;
74 static GFileAttributeInfoList *resource_writable_namespaces = NULL;
75
76 static GType _g_resource_file_enumerator_get_type (void);
77
78 #define G_TYPE_RESOURCE_FILE_ENUMERATOR         (_g_resource_file_enumerator_get_type ())
79 #define G_RESOURCE_FILE_ENUMERATOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumerator))
80 #define G_RESOURCE_FILE_ENUMERATOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
81 #define G_IS_RESOURCE_FILE_ENUMERATOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR))
82 #define G_IS_RESOURCE_FILE_ENUMERATOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_ENUMERATOR))
83 #define G_RESOURCE_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
84
85 #define G_TYPE_RESOURCE_FILE_INPUT_STREAM         (_g_resource_file_input_stream_get_type ())
86 #define G_RESOURCE_FILE_INPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStream))
87 #define G_RESOURCE_FILE_INPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
88 #define G_IS_RESOURCE_FILE_INPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
89 #define G_IS_RESOURCE_FILE_INPUT_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
90 #define G_RESOURCE_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
91
92 typedef struct _GResourceFileInputStream         GResourceFileInputStream;
93 typedef struct _GResourceFileInputStreamClass    GResourceFileInputStreamClass;
94
95 #define g_resource_file_get_type _g_resource_file_get_type
96 G_DEFINE_TYPE_WITH_CODE (GResourceFile, g_resource_file, G_TYPE_OBJECT,
97                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
98                                                 g_resource_file_file_iface_init))
99
100 #define g_resource_file_enumerator_get_type _g_resource_file_enumerator_get_type
101 G_DEFINE_TYPE (GResourceFileEnumerator, g_resource_file_enumerator, G_TYPE_FILE_ENUMERATOR)
102
103 static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
104                                                          const char           *attributes,
105                                                          GFileQueryInfoFlags   flags,
106                                                          GCancellable         *cancellable,
107                                                          GError              **error);
108
109
110 static GType              _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
111
112 static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
113
114
115 static void
116 g_resource_file_finalize (GObject *object)
117 {
118   GResourceFile *resource;
119
120   resource = G_RESOURCE_FILE (object);
121
122   g_free (resource->path);
123
124   G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
125 }
126
127 static void
128 g_resource_file_class_init (GResourceFileClass *klass)
129 {
130   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
131
132   gobject_class->finalize = g_resource_file_finalize;
133
134   resource_writable_attributes = g_file_attribute_info_list_new ();
135   resource_writable_namespaces = g_file_attribute_info_list_new ();
136 }
137
138 static void
139 g_resource_file_init (GResourceFile *resource)
140 {
141 }
142
143 static inline gchar *
144 scan_backwards (const gchar *begin,
145                 const gchar *end,
146                 gchar        c)
147 {
148   while (end >= begin)
149     {
150       if (*end == c)
151         return (gchar *)end;
152       end--;
153     }
154
155   return NULL;
156 }
157
158 static inline void
159 pop_to_previous_part (const gchar  *begin,
160                       gchar       **out)
161 {
162   if (*out > begin)
163     *out = scan_backwards (begin, *out - 1, '/');
164 }
165
166 /*
167  * canonicalize_filename:
168  * @in: the path to be canonicalized
169  *
170  * The path @in may contain non-canonical path pieces such as "../"
171  * or duplicated "/". This will resolve those into a form that only
172  * contains a single / at a time and resolves all "../". The resulting
173  * path must also start with a /.
174  *
175  * Returns: the canonical form of the path
176  */
177 static char *
178 canonicalize_filename (const char *in)
179 {
180   gchar *bptr;
181   char *out;
182
183   bptr = out = g_malloc (strlen (in) + 2);
184   *out = '/';
185
186   while (*in != 0)
187     {
188       g_assert (*out == '/');
189
190       /* move past slashes */
191       while (*in == '/')
192         in++;
193
194       /* Handle ./ ../ .\0 ..\0 */
195       if (*in == '.')
196         {
197           /* If this is ../ or ..\0 move up */
198           if (in[1] == '.' && (in[2] == '/' || in[2] == 0))
199             {
200               pop_to_previous_part (bptr, &out);
201               in += 2;
202               continue;
203             }
204
205           /* If this is ./ skip past it */
206           if (in[1] == '/' || in[1] == 0)
207             {
208               in += 1;
209               continue;
210             }
211         }
212
213       /* Scan to the next path piece */
214       while (*in != 0 && *in != '/')
215         *(++out) = *(in++);
216
217       /* Add trailing /, compress the rest on the next go round. */
218       if (*in == '/')
219         *(++out) = *(in++);
220     }
221
222   /* Trim trailing / from path */
223   if (out > bptr && *out == '/')
224     *out = 0;
225   else
226     *(++out) = 0;
227
228   return bptr;
229 }
230
231 static GFile *
232 g_resource_file_new_for_path (const char *path)
233 {
234   GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
235
236   resource->path = canonicalize_filename (path);
237
238   return G_FILE (resource);
239 }
240
241 /* Will return %NULL if @uri is malformed */
242 GFile *
243 _g_resource_file_new (const char *uri)
244 {
245   GFile *resource;
246   char *path;
247
248   path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
249   if (path == NULL)
250     return NULL;
251
252   resource = g_resource_file_new_for_path (path);
253   g_free (path);
254
255   return G_FILE (resource);
256 }
257
258 static gboolean
259 g_resource_file_is_native (GFile *file)
260 {
261   return FALSE;
262 }
263
264 static gboolean
265 g_resource_file_has_uri_scheme (GFile      *file,
266                                 const char *uri_scheme)
267 {
268   return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
269 }
270
271 static char *
272 g_resource_file_get_uri_scheme (GFile *file)
273 {
274   return g_strdup ("resource");
275 }
276
277 static char *
278 g_resource_file_get_basename (GFile *file)
279 {
280   gchar *base;
281
282   base = strrchr (G_RESOURCE_FILE (file)->path, '/');
283   return g_strdup (base + 1);
284 }
285
286 static char *
287 g_resource_file_get_path (GFile *file)
288 {
289   return NULL;
290 }
291
292 static char *
293 g_resource_file_get_uri (GFile *file)
294 {
295   char *escaped, *res;
296   escaped = g_uri_escape_string (G_RESOURCE_FILE (file)->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
297   res = g_strconcat ("resource://", escaped, NULL);
298   g_free (escaped);
299   return res;
300 }
301
302 static char *
303 g_resource_file_get_parse_name (GFile *file)
304 {
305   return g_resource_file_get_uri (file);
306 }
307
308 static GFile *
309 g_resource_file_get_parent (GFile *file)
310 {
311   GResourceFile *resource = G_RESOURCE_FILE (file);
312   GResourceFile *parent;
313   gchar *end;
314
315   end = strrchr (resource->path, '/');
316
317   if (end == G_RESOURCE_FILE (file)->path)
318     return NULL;
319
320   parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
321   parent->path = g_strndup (resource->path,
322                             end - resource->path);
323
324   return G_FILE (parent);
325 }
326
327 static GFile *
328 g_resource_file_dup (GFile *file)
329 {
330   GResourceFile *resource = G_RESOURCE_FILE (file);
331
332   return g_resource_file_new_for_path (resource->path);
333 }
334
335 static guint
336 g_resource_file_hash (GFile *file)
337 {
338   GResourceFile *resource = G_RESOURCE_FILE (file);
339
340   return g_str_hash (resource->path);
341 }
342
343 static gboolean
344 g_resource_file_equal (GFile *file1,
345                        GFile *file2)
346 {
347   GResourceFile *resource1 = G_RESOURCE_FILE (file1);
348   GResourceFile *resource2 = G_RESOURCE_FILE (file2);
349
350   return g_str_equal (resource1->path, resource2->path);
351 }
352
353 static const char *
354 match_prefix (const char *path,
355               const char *prefix)
356 {
357   int prefix_len;
358
359   prefix_len = strlen (prefix);
360   if (strncmp (path, prefix, prefix_len) != 0)
361     return NULL;
362
363   /* Handle the case where prefix is the root, so that
364    * the IS_DIR_SEPRARATOR check below works */
365   if (prefix_len > 0 &&
366       prefix[prefix_len-1] == '/')
367     prefix_len--;
368
369   return path + prefix_len;
370 }
371
372 static gboolean
373 g_resource_file_prefix_matches (GFile *parent,
374                                 GFile *descendant)
375 {
376   GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
377   GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
378   const char *remainder;
379
380   remainder = match_prefix (descendant_resource->path, parent_resource->path);
381   if (remainder != NULL && *remainder == '/')
382     return TRUE;
383   return FALSE;
384 }
385
386 static char *
387 g_resource_file_get_relative_path (GFile *parent,
388                                    GFile *descendant)
389 {
390   GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
391   GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
392   const char *remainder;
393
394   remainder = match_prefix (descendant_resource->path, parent_resource->path);
395
396   if (remainder != NULL && *remainder == '/')
397     return g_strdup (remainder + 1);
398   return NULL;
399 }
400
401 static GFile *
402 g_resource_file_resolve_relative_path (GFile      *file,
403                                        const char *relative_path)
404 {
405   GResourceFile *resource = G_RESOURCE_FILE (file);
406   char *filename;
407   GFile *child;
408
409   if (relative_path[0] == '/')
410     return g_resource_file_new_for_path (relative_path);
411
412   filename = g_build_path ("/", resource->path, relative_path, NULL);
413   child = g_resource_file_new_for_path (filename);
414   g_free (filename);
415
416   return child;
417 }
418
419 static GFileEnumerator *
420 g_resource_file_enumerate_children (GFile                *file,
421                                     const char           *attributes,
422                                     GFileQueryInfoFlags   flags,
423                                     GCancellable         *cancellable,
424                                     GError              **error)
425 {
426   GResourceFile *resource = G_RESOURCE_FILE (file);
427   return _g_resource_file_enumerator_new (resource,
428                                           attributes, flags,
429                                           cancellable, error);
430 }
431
432 static GFile *
433 g_resource_file_get_child_for_display_name (GFile        *file,
434                                             const char   *display_name,
435                                             GError      **error)
436 {
437   GFile *new_file;
438
439   new_file = g_file_get_child (file, display_name);
440
441   return new_file;
442 }
443
444 static GFileInfo *
445 g_resource_file_query_info (GFile                *file,
446                             const char           *attributes,
447                             GFileQueryInfoFlags   flags,
448                             GCancellable         *cancellable,
449                             GError              **error)
450 {
451   GResourceFile *resource = G_RESOURCE_FILE (file);
452   GError *my_error = NULL;
453   GFileInfo *info;
454   GFileAttributeMatcher *matcher;
455   gboolean res;
456   gsize size = 0;
457   guint32 resource_flags = 0;
458   char **children;
459   gboolean is_dir;
460   char *base;
461
462   is_dir = FALSE;
463   children = g_resources_enumerate_children (resource->path, 0, NULL);
464   if (children != NULL)
465     {
466       g_strfreev (children);
467       is_dir = TRUE;
468     }
469
470   /* root is always there */
471   if (strcmp ("/", resource->path) == 0)
472     is_dir = TRUE;
473
474   if (!is_dir)
475     {
476       res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
477       if (!res)
478         {
479           if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
480             {
481               g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
482                            _("The resource at “%s” does not exist"),
483                            resource->path);
484             }
485           else
486             g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
487                                  my_error->message);
488           g_clear_error (&my_error);
489           return FALSE;
490         }
491     }
492
493   matcher = g_file_attribute_matcher_new (attributes);
494
495   info = g_file_info_new ();
496   base = g_resource_file_get_basename (file);
497   g_file_info_set_name (info, base);
498   g_file_info_set_display_name (info, base);
499
500   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, TRUE);
501   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, FALSE);
502   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, FALSE);
503   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, FALSE);
504   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, FALSE);
505   _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, FALSE);
506
507   if (is_dir)
508     {
509       g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
510     }
511   else
512     {
513       GBytes *bytes;
514       char *content_type;
515
516       g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
517       g_file_info_set_size (info, size);
518
519       if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
520            ((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) && 
521             _g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) &&
522           (bytes = g_resources_lookup_data (resource->path, 0, NULL)))
523         {
524           const guchar *data;
525           gsize data_size;
526
527           data = g_bytes_get_data (bytes, &data_size);
528           content_type = g_content_type_guess (base, data, data_size, NULL);
529
530           g_bytes_unref (bytes);
531         }
532       else
533         content_type = NULL;
534
535       if (content_type)
536         {
537           _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE, content_type);
538           _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
539
540           g_free (content_type);
541         }
542     }
543
544   g_free (base);
545   g_file_attribute_matcher_unref (matcher);
546
547   return info;
548 }
549
550 static GFileInfo *
551 g_resource_file_query_filesystem_info (GFile         *file,
552                                        const char    *attributes,
553                                        GCancellable  *cancellable,
554                                        GError       **error)
555 {
556   GFileInfo *info;
557   GFileAttributeMatcher *matcher;
558
559   info = g_file_info_new ();
560
561   matcher = g_file_attribute_matcher_new (attributes);
562   if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
563     g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "resource");
564
565   if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
566     g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
567
568   g_file_attribute_matcher_unref (matcher);
569
570   return info;
571 }
572
573 static GFileAttributeInfoList *
574 g_resource_file_query_settable_attributes (GFile         *file,
575                                            GCancellable  *cancellable,
576                                            GError       **error)
577 {
578   return g_file_attribute_info_list_ref (resource_writable_attributes);
579 }
580
581 static GFileAttributeInfoList *
582 g_resource_file_query_writable_namespaces (GFile         *file,
583                                            GCancellable  *cancellable,
584                                            GError       **error)
585 {
586   return g_file_attribute_info_list_ref (resource_writable_namespaces);
587 }
588
589 static GFileInputStream *
590 g_resource_file_read (GFile         *file,
591                       GCancellable  *cancellable,
592                       GError       **error)
593 {
594   GResourceFile *resource = G_RESOURCE_FILE (file);
595   GError *my_error = NULL;
596   GInputStream *stream;
597   GFileInputStream *res;
598
599   stream = g_resources_open_stream (resource->path, 0, &my_error);
600
601   if (stream == NULL)
602     {
603       if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
604         {
605           g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
606                        _("The resource at “%s” does not exist"),
607                        resource->path);
608         }
609       else
610         g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
611                              my_error->message);
612       g_clear_error (&my_error);
613       return NULL;
614     }
615
616   res = _g_resource_file_input_stream_new (stream, file);
617   g_object_unref (stream);
618   return res;
619 }
620
621 typedef GFileMonitor GResourceFileMonitor;
622 typedef GFileMonitorClass GResourceFileMonitorClass;
623
624 GType g_resource_file_monitor_get_type (void);
625
626 G_DEFINE_TYPE (GResourceFileMonitor, g_resource_file_monitor, G_TYPE_FILE_MONITOR)
627
628 static gboolean
629 g_resource_file_monitor_cancel (GFileMonitor *monitor)
630 {
631   return TRUE;
632 }
633
634 static void
635 g_resource_file_monitor_init (GResourceFileMonitor *monitor)
636 {
637 }
638
639 static void
640 g_resource_file_monitor_class_init (GResourceFileMonitorClass *class)
641 {
642   class->cancel = g_resource_file_monitor_cancel;
643 }
644
645 static GFileMonitor *
646 g_resource_file_monitor_file (GFile              *file,
647                               GFileMonitorFlags   flags,
648                               GCancellable       *cancellable,
649                               GError            **error)
650 {
651   return g_object_new (g_resource_file_monitor_get_type (), NULL);
652 }
653
654 static GFile *
655 g_resource_file_set_display_name (GFile         *file,
656                                   const char    *display_name,
657                                   GCancellable  *cancellable,
658                                   GError       **error)
659 {
660   g_set_error_literal (error,
661                        G_IO_ERROR,
662                        G_IO_ERROR_NOT_SUPPORTED,
663                        _("Resource files cannot be renamed"));
664   return NULL;
665 }
666
667 static void
668 g_resource_file_file_iface_init (GFileIface *iface)
669 {
670   iface->dup = g_resource_file_dup;
671   iface->hash = g_resource_file_hash;
672   iface->equal = g_resource_file_equal;
673   iface->is_native = g_resource_file_is_native;
674   iface->has_uri_scheme = g_resource_file_has_uri_scheme;
675   iface->get_uri_scheme = g_resource_file_get_uri_scheme;
676   iface->get_basename = g_resource_file_get_basename;
677   iface->get_path = g_resource_file_get_path;
678   iface->get_uri = g_resource_file_get_uri;
679   iface->get_parse_name = g_resource_file_get_parse_name;
680   iface->get_parent = g_resource_file_get_parent;
681   iface->prefix_matches = g_resource_file_prefix_matches;
682   iface->get_relative_path = g_resource_file_get_relative_path;
683   iface->resolve_relative_path = g_resource_file_resolve_relative_path;
684   iface->get_child_for_display_name = g_resource_file_get_child_for_display_name;
685   iface->set_display_name = g_resource_file_set_display_name;
686   iface->enumerate_children = g_resource_file_enumerate_children;
687   iface->query_info = g_resource_file_query_info;
688   iface->query_filesystem_info = g_resource_file_query_filesystem_info;
689   iface->query_settable_attributes = g_resource_file_query_settable_attributes;
690   iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
691   iface->read_fn = g_resource_file_read;
692   iface->monitor_file = g_resource_file_monitor_file;
693
694   iface->supports_thread_contexts = TRUE;
695 }
696
697 static GFileInfo *g_resource_file_enumerator_next_file (GFileEnumerator  *enumerator,
698                                                         GCancellable     *cancellable,
699                                                         GError          **error);
700 static gboolean   g_resource_file_enumerator_close     (GFileEnumerator  *enumerator,
701                                                         GCancellable     *cancellable,
702                                                         GError          **error);
703
704 static void
705 g_resource_file_enumerator_finalize (GObject *object)
706 {
707   GResourceFileEnumerator *resource;
708
709   resource = G_RESOURCE_FILE_ENUMERATOR (object);
710
711   g_strfreev (resource->children);
712   g_free (resource->path);
713   g_free (resource->attributes);
714
715   G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
716 }
717
718 static void
719 g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
720 {
721   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
722   GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
723
724   gobject_class->finalize = g_resource_file_enumerator_finalize;
725
726   enumerator_class->next_file = g_resource_file_enumerator_next_file;
727   enumerator_class->close_fn = g_resource_file_enumerator_close;
728 }
729
730 static void
731 g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
732 {
733 }
734
735 static GFileEnumerator *
736 _g_resource_file_enumerator_new (GResourceFile *file,
737                                  const char           *attributes,
738                                  GFileQueryInfoFlags   flags,
739                                  GCancellable         *cancellable,
740                                  GError              **error)
741 {
742   GResourceFileEnumerator *resource;
743   char **children;
744   gboolean res;
745
746   children = g_resources_enumerate_children (file->path, 0, NULL);
747   if (children == NULL &&
748       strcmp ("/", file->path) != 0)
749     {
750       res = g_resources_get_info (file->path, 0, NULL, NULL, NULL);
751       if (res)
752         g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
753                      _("The resource at “%s” is not a directory"),
754                      file->path);
755       else
756         g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
757                      _("The resource at “%s” does not exist"),
758                      file->path);
759       return NULL;
760     }
761
762   resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
763                            "container", file,
764                            NULL);
765
766   resource->children = children;
767   resource->path = g_strdup (file->path);
768   resource->attributes = g_strdup (attributes);
769   resource->flags = flags;
770
771   return G_FILE_ENUMERATOR (resource);
772 }
773
774 static GFileInfo *
775 g_resource_file_enumerator_next_file (GFileEnumerator  *enumerator,
776                                       GCancellable     *cancellable,
777                                       GError          **error)
778 {
779   GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
780   char *path;
781   GFileInfo *info;
782   GFile *file;
783
784   if (resource->children == NULL ||
785       resource->children[resource->index] == NULL)
786     return NULL;
787
788   path = g_build_path ("/", resource->path, resource->children[resource->index++], NULL);
789   file = g_resource_file_new_for_path (path);
790   g_free (path);
791
792   info = g_file_query_info (file,
793                             resource->attributes,
794                             resource->flags,
795                             cancellable,
796                             error);
797
798   g_object_unref (file);
799
800   return info;
801 }
802
803 static gboolean
804 g_resource_file_enumerator_close (GFileEnumerator  *enumerator,
805                                GCancellable     *cancellable,
806                                GError          **error)
807 {
808   return TRUE;
809 }
810
811
812 struct _GResourceFileInputStream
813 {
814   GFileInputStream parent_instance;
815   GInputStream *stream;
816   GFile *file;
817 };
818
819 struct _GResourceFileInputStreamClass
820 {
821   GFileInputStreamClass parent_class;
822 };
823
824 #define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
825 G_DEFINE_TYPE (GResourceFileInputStream, g_resource_file_input_stream, G_TYPE_FILE_INPUT_STREAM)
826
827 static gssize     g_resource_file_input_stream_read       (GInputStream      *stream,
828                                                            void              *buffer,
829                                                            gsize              count,
830                                                            GCancellable      *cancellable,
831                                                            GError           **error);
832 static gssize     g_resource_file_input_stream_skip       (GInputStream      *stream,
833                                                            gsize              count,
834                                                            GCancellable      *cancellable,
835                                                            GError           **error);
836 static gboolean   g_resource_file_input_stream_close      (GInputStream      *stream,
837                                                            GCancellable      *cancellable,
838                                                            GError           **error);
839 static goffset    g_resource_file_input_stream_tell       (GFileInputStream  *stream);
840 static gboolean   g_resource_file_input_stream_can_seek   (GFileInputStream  *stream);
841 static gboolean   g_resource_file_input_stream_seek       (GFileInputStream  *stream,
842                                                            goffset            offset,
843                                                            GSeekType          type,
844                                                            GCancellable      *cancellable,
845                                                            GError           **error);
846 static GFileInfo *g_resource_file_input_stream_query_info (GFileInputStream  *stream,
847                                                            const char        *attributes,
848                                                            GCancellable      *cancellable,
849                                                            GError           **error);
850
851 static void
852 g_resource_file_input_stream_finalize (GObject *object)
853 {
854   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
855
856   g_object_unref (file->stream);
857   g_object_unref (file->file);
858   G_OBJECT_CLASS (g_resource_file_input_stream_parent_class)->finalize (object);
859 }
860
861 static void
862 g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
863 {
864   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
865   GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
866   GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
867
868   gobject_class->finalize = g_resource_file_input_stream_finalize;
869
870   stream_class->read_fn = g_resource_file_input_stream_read;
871   stream_class->skip = g_resource_file_input_stream_skip;
872   stream_class->close_fn = g_resource_file_input_stream_close;
873   file_stream_class->tell = g_resource_file_input_stream_tell;
874   file_stream_class->can_seek = g_resource_file_input_stream_can_seek;
875   file_stream_class->seek = g_resource_file_input_stream_seek;
876   file_stream_class->query_info = g_resource_file_input_stream_query_info;
877 }
878
879 static void
880 g_resource_file_input_stream_init (GResourceFileInputStream *info)
881 {
882 }
883
884 static GFileInputStream *
885 _g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
886 {
887   GResourceFileInputStream *stream;
888
889   stream = g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM, NULL);
890   stream->stream = g_object_ref (in_stream);
891   stream->file = g_object_ref (file);
892
893   return G_FILE_INPUT_STREAM (stream);
894 }
895
896 static gssize
897 g_resource_file_input_stream_read (GInputStream  *stream,
898                                    void          *buffer,
899                                    gsize          count,
900                                    GCancellable  *cancellable,
901                                    GError       **error)
902 {
903   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
904   return g_input_stream_read (file->stream,
905                               buffer, count, cancellable, error);
906 }
907
908 static gssize
909 g_resource_file_input_stream_skip (GInputStream  *stream,
910                                    gsize          count,
911                                    GCancellable  *cancellable,
912                                    GError       **error)
913 {
914   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
915   return g_input_stream_skip (file->stream,
916                               count, cancellable, error);
917 }
918
919 static gboolean
920 g_resource_file_input_stream_close (GInputStream  *stream,
921                                     GCancellable  *cancellable,
922                                     GError       **error)
923 {
924   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
925   return g_input_stream_close (file->stream,
926                                cancellable, error);
927 }
928
929
930 static goffset
931 g_resource_file_input_stream_tell (GFileInputStream *stream)
932 {
933   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
934
935   if (!G_IS_SEEKABLE (file->stream))
936       return 0;
937
938   return g_seekable_tell (G_SEEKABLE (file->stream));
939 }
940
941 static gboolean
942 g_resource_file_input_stream_can_seek (GFileInputStream *stream)
943 {
944   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
945
946   return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
947 }
948
949 static gboolean
950 g_resource_file_input_stream_seek (GFileInputStream  *stream,
951                                    goffset            offset,
952                                    GSeekType          type,
953                                    GCancellable      *cancellable,
954                                    GError           **error)
955 {
956   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
957
958   if (!G_IS_SEEKABLE (file->stream))
959     {
960       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
961                            _("Input stream doesn’t implement seek"));
962       return FALSE;
963     }
964
965   return g_seekable_seek (G_SEEKABLE (file->stream),
966                           offset, type, cancellable, error);
967 }
968
969 static GFileInfo *
970 g_resource_file_input_stream_query_info (GFileInputStream  *stream,
971                                          const char        *attributes,
972                                          GCancellable      *cancellable,
973                                          GError           **error)
974 {
975   GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
976
977   return g_file_query_info (file->file, attributes, 0, cancellable, error);
978 }