It is 'registered', not 'registred'
[glib.git] / gio / gresourcefile.c
blobe399e54ccab7fe0925c1781bf0e21fa823c9654d
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Alexander Larsson <alexl@redhat.com>
23 #include "config.h"
25 #include <string.h>
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 "gseekable.h"
34 #include "gfileinputstream.h"
35 #include "gfileinfo.h"
36 #include "gfileenumerator.h"
37 #include "gcontenttype.h"
38 #include "gioerror.h"
39 #include <glib/gstdio.h>
40 #include "glibintl.h"
42 struct _GResourceFile
44 GObject parent_instance;
46 char *path;
49 struct _GResourceFileEnumerator
51 GFileEnumerator parent;
53 GFileAttributeMatcher *matcher;
54 char *path;
55 char *attributes;
56 GFileQueryInfoFlags flags;
57 int index;
59 char **children;
62 struct _GResourceFileEnumeratorClass
64 GFileEnumeratorClass parent_class;
67 typedef struct _GResourceFileEnumerator GResourceFileEnumerator;
68 typedef struct _GResourceFileEnumeratorClass GResourceFileEnumeratorClass;
70 static void g_resource_file_file_iface_init (GFileIface *iface);
72 static GFileAttributeInfoList *resource_writable_attributes = NULL;
73 static GFileAttributeInfoList *resource_writable_namespaces = NULL;
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))
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))
89 typedef struct _GResourceFileInputStream GResourceFileInputStream;
90 typedef struct _GResourceFileInputStreamClass GResourceFileInputStreamClass;
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))
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);
100 static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
101 const char *attributes,
102 GFileQueryInfoFlags flags,
103 GCancellable *cancellable,
104 GError **error);
107 static GType _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
109 static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
112 static void
113 g_resource_file_finalize (GObject *object)
115 GResourceFile *resource;
117 resource = G_RESOURCE_FILE (object);
119 g_free (resource->path);
121 G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
124 static void
125 g_resource_file_class_init (GResourceFileClass *klass)
127 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129 gobject_class->finalize = g_resource_file_finalize;
131 resource_writable_attributes = g_file_attribute_info_list_new ();
132 resource_writable_namespaces = g_file_attribute_info_list_new ();
135 static void
136 g_resource_file_init (GResourceFile *resource)
140 static char *
141 canonicalize_filename (const char *filename)
143 char *canon, *start, *p, *q;
145 /* Skip multiple inital slashes */
146 while (filename[0] == '/' && filename[1] == '/')
147 filename++;
149 if (*filename != '/')
150 canon = g_strconcat ("/", filename, NULL);
151 else
152 canon = g_strdup (filename);
154 start = canon + 1;
156 p = start;
157 while (*p != 0)
159 if (p[0] == '.' && (p[1] == 0 || p[1] == '/'))
161 memmove (p, p+1, strlen (p+1)+1);
163 else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || p[2] == '/'))
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);
176 else
178 /* Skip until next separator */
179 while (*p != 0 && *p != '/')
180 p++;
182 if (*p != 0)
184 /* Canonicalize one separator */
185 *p++ = '/';
189 /* Remove additional separators */
190 q = p;
191 while (*q && *q == '/')
192 q++;
194 if (p != q)
195 memmove (p, q, strlen (q)+1);
198 /* Remove trailing slashes */
199 if (p > start && *(p-1) == '/')
200 *(p-1) = 0;
202 return canon;
205 static GFile *
206 g_resource_file_new_for_path (const char *path)
208 GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
210 resource->path = canonicalize_filename (path);
212 return G_FILE (resource);
215 GFile *
216 _g_resource_file_new (const char *uri)
218 GFile *resource;
219 char *path;
221 path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
222 resource = g_resource_file_new_for_path (path);
223 g_free (path);
225 return G_FILE (resource);
228 static gboolean
229 g_resource_file_is_native (GFile *file)
231 return FALSE;
234 static gboolean
235 g_resource_file_has_uri_scheme (GFile *file,
236 const char *uri_scheme)
238 return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
241 static char *
242 g_resource_file_get_uri_scheme (GFile *file)
244 return g_strdup ("resource");
247 static char *
248 g_resource_file_get_basename (GFile *file)
250 gchar *base;
252 base = strrchr (G_RESOURCE_FILE (file)->path, '/');
253 return g_strdup (base + 1);
256 static char *
257 g_resource_file_get_path (GFile *file)
259 return NULL;
262 static char *
263 g_resource_file_get_uri (GFile *file)
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;
272 static char *
273 g_resource_file_get_parse_name (GFile *file)
275 return g_resource_file_get_uri (file);
278 static GFile *
279 g_resource_file_get_parent (GFile *file)
281 GResourceFile *resource = G_RESOURCE_FILE (file);
282 GResourceFile *parent;
283 gchar *end;
285 end = strrchr (resource->path, '/');
287 if (end == G_RESOURCE_FILE (file)->path)
288 return NULL;
290 parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
291 parent->path = g_strndup (resource->path,
292 end - resource->path);
294 return G_FILE (parent);
297 static GFile *
298 g_resource_file_dup (GFile *file)
300 GResourceFile *resource = G_RESOURCE_FILE (file);
302 return g_resource_file_new_for_path (resource->path);
305 static guint
306 g_resource_file_hash (GFile *file)
308 GResourceFile *resource = G_RESOURCE_FILE (file);
310 return g_str_hash (resource->path);
313 static gboolean
314 g_resource_file_equal (GFile *file1,
315 GFile *file2)
317 GResourceFile *resource1 = G_RESOURCE_FILE (file1);
318 GResourceFile *resource2 = G_RESOURCE_FILE (file2);
320 return g_str_equal (resource1->path, resource2->path);
323 static const char *
324 match_prefix (const char *path,
325 const char *prefix)
327 int prefix_len;
329 prefix_len = strlen (prefix);
330 if (strncmp (path, prefix, prefix_len) != 0)
331 return NULL;
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--;
339 return path + prefix_len;
342 static gboolean
343 g_resource_file_prefix_matches (GFile *parent,
344 GFile *descendant)
346 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
347 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
348 const char *remainder;
350 remainder = match_prefix (descendant_resource->path, parent_resource->path);
351 if (remainder != NULL && *remainder == '/')
352 return TRUE;
353 return FALSE;
356 static char *
357 g_resource_file_get_relative_path (GFile *parent,
358 GFile *descendant)
360 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
361 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
362 const char *remainder;
364 remainder = match_prefix (descendant_resource->path, parent_resource->path);
366 if (remainder != NULL && *remainder == '/')
367 return g_strdup (remainder + 1);
368 return NULL;
371 static GFile *
372 g_resource_file_resolve_relative_path (GFile *file,
373 const char *relative_path)
375 GResourceFile *resource = G_RESOURCE_FILE (file);
376 char *filename;
377 GFile *child;
379 if (relative_path[0] == '/')
380 return g_resource_file_new_for_path (relative_path);
382 filename = g_build_path ("/", resource->path, relative_path, NULL);
383 child = g_resource_file_new_for_path (filename);
384 g_free (filename);
386 return child;
389 static GFileEnumerator *
390 g_resource_file_enumerate_children (GFile *file,
391 const char *attributes,
392 GFileQueryInfoFlags flags,
393 GCancellable *cancellable,
394 GError **error)
396 GResourceFile *resource = G_RESOURCE_FILE (file);
397 return _g_resource_file_enumerator_new (resource,
398 attributes, flags,
399 cancellable, error);
402 static GFile *
403 g_resource_file_get_child_for_display_name (GFile *file,
404 const char *display_name,
405 GError **error)
407 GFile *new_file;
409 new_file = g_file_get_child (file, display_name);
411 return new_file;
414 static GFileInfo *
415 g_resource_file_query_info (GFile *file,
416 const char *attributes,
417 GFileQueryInfoFlags flags,
418 GCancellable *cancellable,
419 GError **error)
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;
432 is_dir = FALSE;
433 children = g_resources_enumerate_children (resource->path, 0, NULL);
434 if (children != NULL)
436 g_strfreev (children);
437 is_dir = TRUE;
440 /* root is always there */
441 if (strcmp ("/", resource->path) == 0)
442 is_dir = TRUE;
444 if (!is_dir)
446 res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
447 if (!res)
449 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
451 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
452 _("The resource at '%s' does not exist"),
453 resource->path);
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;
463 matcher = g_file_attribute_matcher_new (attributes);
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);
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);
477 if (is_dir)
479 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
481 else
483 GBytes *bytes;
484 char *content_type;
486 g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
487 g_file_info_set_size (info, size);
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)))
494 const guchar *data;
495 gsize data_size;
497 data = g_bytes_get_data (bytes, &data_size);
498 content_type = g_content_type_guess (base, data, data_size, NULL);
500 g_bytes_unref (bytes);
502 else
503 content_type = NULL;
505 if (content_type)
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);
510 g_free (content_type);
514 g_free (base);
515 g_file_attribute_matcher_unref (matcher);
517 return info;
520 static GFileAttributeInfoList *
521 g_resource_file_query_settable_attributes (GFile *file,
522 GCancellable *cancellable,
523 GError **error)
525 return g_file_attribute_info_list_ref (resource_writable_attributes);
528 static GFileAttributeInfoList *
529 g_resource_file_query_writable_namespaces (GFile *file,
530 GCancellable *cancellable,
531 GError **error)
533 return g_file_attribute_info_list_ref (resource_writable_namespaces);
536 static GFileInputStream *
537 g_resource_file_read (GFile *file,
538 GCancellable *cancellable,
539 GError **error)
541 GResourceFile *resource = G_RESOURCE_FILE (file);
542 GError *my_error = NULL;
543 GInputStream *stream;
544 GFileInputStream *res;
546 stream = g_resources_open_stream (resource->path, 0, &my_error);
548 if (stream == NULL)
550 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
552 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
553 _("The resource at '%s' does not exist"),
554 resource->path);
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;
563 res = _g_resource_file_input_stream_new (stream, file);
564 g_object_unref (stream);
565 return res;
568 static void
569 g_resource_file_file_iface_init (GFileIface *iface)
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;
592 iface->supports_thread_contexts = TRUE;
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);
602 static void
603 g_resource_file_enumerator_finalize (GObject *object)
605 GResourceFileEnumerator *resource;
607 resource = G_RESOURCE_FILE_ENUMERATOR (object);
609 g_strfreev (resource->children);
610 g_free (resource->path);
611 g_free (resource->attributes);
613 G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
616 static void
617 g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
619 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
620 GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
622 gobject_class->finalize = g_resource_file_enumerator_finalize;
624 enumerator_class->next_file = g_resource_file_enumerator_next_file;
625 enumerator_class->close_fn = g_resource_file_enumerator_close;
628 static void
629 g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
633 static GFileEnumerator *
634 _g_resource_file_enumerator_new (GResourceFile *file,
635 const char *attributes,
636 GFileQueryInfoFlags flags,
637 GCancellable *cancellable,
638 GError **error)
640 GResourceFileEnumerator *resource;
641 char **children;
642 gboolean res;
644 children = g_resources_enumerate_children (file->path, 0, NULL);
645 if (children == NULL &&
646 strcmp ("/", file->path) != 0)
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;
660 resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
661 "container", file,
662 NULL);
664 resource->children = children;
665 resource->path = g_strdup (file->path);
666 resource->attributes = g_strdup (attributes);
667 resource->flags = flags;
669 return G_FILE_ENUMERATOR (resource);
672 static GFileInfo *
673 g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
674 GCancellable *cancellable,
675 GError **error)
677 GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
678 char *path;
679 GFileInfo *info;
680 GFile *file;
682 if (resource->children == NULL ||
683 resource->children[resource->index] == NULL)
684 return NULL;
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);
690 info = g_file_query_info (file,
691 resource->attributes,
692 resource->flags,
693 cancellable,
694 error);
696 g_object_unref (file);
698 return info;
701 static gboolean
702 g_resource_file_enumerator_close (GFileEnumerator *enumerator,
703 GCancellable *cancellable,
704 GError **error)
706 return TRUE;
710 struct _GResourceFileInputStream
712 GFileInputStream parent_instance;
713 GInputStream *stream;
714 GFile *file;
717 struct _GResourceFileInputStreamClass
719 GFileInputStreamClass parent_class;
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);
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);
749 static void
750 g_resource_file_input_stream_finalize (GObject *object)
752 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
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);
759 static void
760 g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
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);
766 gobject_class->finalize = g_resource_file_input_stream_finalize;
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;
777 static void
778 g_resource_file_input_stream_init (GResourceFileInputStream *info)
782 static GFileInputStream *
783 _g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
785 GResourceFileInputStream *stream;
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);
791 return G_FILE_INPUT_STREAM (stream);
794 static gssize
795 g_resource_file_input_stream_read (GInputStream *stream,
796 void *buffer,
797 gsize count,
798 GCancellable *cancellable,
799 GError **error)
801 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
802 return g_input_stream_read (file->stream,
803 buffer, count, cancellable, error);
806 static gssize
807 g_resource_file_input_stream_skip (GInputStream *stream,
808 gsize count,
809 GCancellable *cancellable,
810 GError **error)
812 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
813 return g_input_stream_skip (file->stream,
814 count, cancellable, error);
817 static gboolean
818 g_resource_file_input_stream_close (GInputStream *stream,
819 GCancellable *cancellable,
820 GError **error)
822 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
823 return g_input_stream_close (file->stream,
824 cancellable, error);
828 static goffset
829 g_resource_file_input_stream_tell (GFileInputStream *stream)
831 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
833 if (!G_IS_SEEKABLE (file->stream))
834 return 0;
836 return g_seekable_tell (G_SEEKABLE (file->stream));
839 static gboolean
840 g_resource_file_input_stream_can_seek (GFileInputStream *stream)
842 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
844 return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
847 static gboolean
848 g_resource_file_input_stream_seek (GFileInputStream *stream,
849 goffset offset,
850 GSeekType type,
851 GCancellable *cancellable,
852 GError **error)
854 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
856 if (!G_IS_SEEKABLE (file->stream))
858 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
859 _("Input stream doesn't implement seek"));
860 return FALSE;
863 return g_seekable_seek (G_SEEKABLE (file->stream),
864 offset, type, cancellable, error);
867 static GFileInfo *
868 g_resource_file_input_stream_query_info (GFileInputStream *stream,
869 const char *attributes,
870 GCancellable *cancellable,
871 GError **error)
873 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
875 return g_file_query_info (file->file, attributes, 0, cancellable, error);