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