nexmon – Blame information for rev 1

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