Simplify glib/glib/tests setup
[glib.git] / gio / gresourcefile.c
blobde262463a4320a0f660f3d69e21b68559873e225
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 static GType _g_resource_file_enumerator_get_type (void);
77 #define G_TYPE_RESOURCE_FILE_ENUMERATOR (_g_resource_file_enumerator_get_type ())
78 #define G_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumerator))
79 #define G_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
80 #define G_IS_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR))
81 #define G_IS_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_ENUMERATOR))
82 #define G_RESOURCE_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
84 #define G_TYPE_RESOURCE_FILE_INPUT_STREAM (_g_resource_file_input_stream_get_type ())
85 #define G_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStream))
86 #define G_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
87 #define G_IS_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
88 #define G_IS_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
89 #define G_RESOURCE_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
91 typedef struct _GResourceFileInputStream GResourceFileInputStream;
92 typedef struct _GResourceFileInputStreamClass GResourceFileInputStreamClass;
94 #define g_resource_file_get_type _g_resource_file_get_type
95 G_DEFINE_TYPE_WITH_CODE (GResourceFile, g_resource_file, G_TYPE_OBJECT,
96 G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
97 g_resource_file_file_iface_init))
99 #define g_resource_file_enumerator_get_type _g_resource_file_enumerator_get_type
100 G_DEFINE_TYPE (GResourceFileEnumerator, g_resource_file_enumerator, G_TYPE_FILE_ENUMERATOR);
102 static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
103 const char *attributes,
104 GFileQueryInfoFlags flags,
105 GCancellable *cancellable,
106 GError **error);
109 static GType _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
111 static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
114 static void
115 g_resource_file_finalize (GObject *object)
117 GResourceFile *resource;
119 resource = G_RESOURCE_FILE (object);
121 g_free (resource->path);
123 G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
126 static void
127 g_resource_file_class_init (GResourceFileClass *klass)
129 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
131 gobject_class->finalize = g_resource_file_finalize;
133 resource_writable_attributes = g_file_attribute_info_list_new ();
134 resource_writable_namespaces = g_file_attribute_info_list_new ();
137 static void
138 g_resource_file_init (GResourceFile *resource)
142 static char *
143 canonicalize_filename (const char *filename)
145 char *canon, *start, *p, *q;
147 /* Skip multiple inital slashes */
148 while (filename[0] == '/' && filename[1] == '/')
149 filename++;
151 if (*filename != '/')
152 canon = g_strconcat ("/", filename, NULL);
153 else
154 canon = g_strdup (filename);
156 start = canon + 1;
158 p = start;
159 while (*p != 0)
161 if (p[0] == '.' && (p[1] == 0 || p[1] == '/'))
163 memmove (p, p+1, strlen (p+1)+1);
165 else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || p[2] == '/'))
167 q = p + 2;
168 /* Skip previous separator */
169 p = p - 2;
170 if (p < start)
171 p = start;
172 while (p > start && *p != '/')
173 p--;
174 if (*p == '/')
175 *p++ = '/';
176 memmove (p, q, strlen (q)+1);
178 else
180 /* Skip until next separator */
181 while (*p != 0 && *p != '/')
182 p++;
184 if (*p != 0)
186 /* Canonicalize one separator */
187 *p++ = '/';
191 /* Remove additional separators */
192 q = p;
193 while (*q && *q == '/')
194 q++;
196 if (p != q)
197 memmove (p, q, strlen (q)+1);
200 /* Remove trailing slashes */
201 if (p > start && *(p-1) == '/')
202 *(p-1) = 0;
204 return canon;
207 static GFile *
208 g_resource_file_new_for_path (const char *path)
210 GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
212 resource->path = canonicalize_filename (path);
214 return G_FILE (resource);
217 GFile *
218 _g_resource_file_new (const char *uri)
220 GFile *resource;
221 char *path;
223 path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
224 resource = g_resource_file_new_for_path (path);
225 g_free (path);
227 return G_FILE (resource);
230 static gboolean
231 g_resource_file_is_native (GFile *file)
233 return FALSE;
236 static gboolean
237 g_resource_file_has_uri_scheme (GFile *file,
238 const char *uri_scheme)
240 return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
243 static char *
244 g_resource_file_get_uri_scheme (GFile *file)
246 return g_strdup ("resource");
249 static char *
250 g_resource_file_get_basename (GFile *file)
252 gchar *base;
254 base = strrchr (G_RESOURCE_FILE (file)->path, '/');
255 return g_strdup (base + 1);
258 static char *
259 g_resource_file_get_path (GFile *file)
261 return NULL;
264 static char *
265 g_resource_file_get_uri (GFile *file)
267 char *escaped, *res;
268 escaped = g_uri_escape_string (G_RESOURCE_FILE (file)->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
269 res = g_strconcat ("resource://", escaped, NULL);
270 g_free (escaped);
271 return res;
274 static char *
275 g_resource_file_get_parse_name (GFile *file)
277 return g_resource_file_get_uri (file);
280 static GFile *
281 g_resource_file_get_parent (GFile *file)
283 GResourceFile *resource = G_RESOURCE_FILE (file);
284 GResourceFile *parent;
285 gchar *end;
287 end = strrchr (resource->path, '/');
289 if (end == G_RESOURCE_FILE (file)->path)
290 return NULL;
292 parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
293 parent->path = g_strndup (resource->path,
294 end - resource->path);
296 return G_FILE (parent);
299 static GFile *
300 g_resource_file_dup (GFile *file)
302 GResourceFile *resource = G_RESOURCE_FILE (file);
304 return g_resource_file_new_for_path (resource->path);
307 static guint
308 g_resource_file_hash (GFile *file)
310 GResourceFile *resource = G_RESOURCE_FILE (file);
312 return g_str_hash (resource->path);
315 static gboolean
316 g_resource_file_equal (GFile *file1,
317 GFile *file2)
319 GResourceFile *resource1 = G_RESOURCE_FILE (file1);
320 GResourceFile *resource2 = G_RESOURCE_FILE (file2);
322 return g_str_equal (resource1->path, resource2->path);
325 static const char *
326 match_prefix (const char *path,
327 const char *prefix)
329 int prefix_len;
331 prefix_len = strlen (prefix);
332 if (strncmp (path, prefix, prefix_len) != 0)
333 return NULL;
335 /* Handle the case where prefix is the root, so that
336 * the IS_DIR_SEPRARATOR check below works */
337 if (prefix_len > 0 &&
338 prefix[prefix_len-1] == '/')
339 prefix_len--;
341 return path + prefix_len;
344 static gboolean
345 g_resource_file_prefix_matches (GFile *parent,
346 GFile *descendant)
348 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
349 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
350 const char *remainder;
352 remainder = match_prefix (descendant_resource->path, parent_resource->path);
353 if (remainder != NULL && *remainder == '/')
354 return TRUE;
355 return FALSE;
358 static char *
359 g_resource_file_get_relative_path (GFile *parent,
360 GFile *descendant)
362 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
363 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
364 const char *remainder;
366 remainder = match_prefix (descendant_resource->path, parent_resource->path);
368 if (remainder != NULL && *remainder == '/')
369 return g_strdup (remainder + 1);
370 return NULL;
373 static GFile *
374 g_resource_file_resolve_relative_path (GFile *file,
375 const char *relative_path)
377 GResourceFile *resource = G_RESOURCE_FILE (file);
378 char *filename;
379 GFile *child;
381 if (relative_path[0] == '/')
382 return g_resource_file_new_for_path (relative_path);
384 filename = g_build_path ("/", resource->path, relative_path, NULL);
385 child = g_resource_file_new_for_path (filename);
386 g_free (filename);
388 return child;
391 static GFileEnumerator *
392 g_resource_file_enumerate_children (GFile *file,
393 const char *attributes,
394 GFileQueryInfoFlags flags,
395 GCancellable *cancellable,
396 GError **error)
398 GResourceFile *resource = G_RESOURCE_FILE (file);
399 return _g_resource_file_enumerator_new (resource,
400 attributes, flags,
401 cancellable, error);
404 static GFile *
405 g_resource_file_get_child_for_display_name (GFile *file,
406 const char *display_name,
407 GError **error)
409 GFile *new_file;
411 new_file = g_file_get_child (file, display_name);
413 return new_file;
416 static GFileInfo *
417 g_resource_file_query_info (GFile *file,
418 const char *attributes,
419 GFileQueryInfoFlags flags,
420 GCancellable *cancellable,
421 GError **error)
423 GResourceFile *resource = G_RESOURCE_FILE (file);
424 GError *my_error = NULL;
425 GFileInfo *info;
426 GFileAttributeMatcher *matcher;
427 gboolean res;
428 gsize size;
429 guint32 resource_flags;
430 char **children;
431 gboolean is_dir;
432 char *base;
434 is_dir = FALSE;
435 children = g_resources_enumerate_children (resource->path, 0, NULL);
436 if (children != NULL)
438 g_strfreev (children);
439 is_dir = TRUE;
442 /* root is always there */
443 if (strcmp ("/", resource->path) == 0)
444 is_dir = TRUE;
446 if (!is_dir)
448 res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
449 if (!res)
451 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
453 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
454 _("The resource at '%s' does not exist"),
455 resource->path);
457 else
458 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
459 my_error->message);
460 g_clear_error (&my_error);
461 return FALSE;
465 matcher = g_file_attribute_matcher_new (attributes);
467 info = g_file_info_new ();
468 base = g_resource_file_get_basename (file);
469 g_file_info_set_name (info, base);
470 g_file_info_set_display_name (info, base);
472 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, TRUE);
473 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, FALSE);
474 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, FALSE);
475 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, FALSE);
476 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, FALSE);
477 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, FALSE);
479 if (is_dir)
481 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
483 else
485 GBytes *bytes;
486 char *content_type;
488 g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
489 g_file_info_set_size (info, size);
491 if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
492 ((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) &&
493 _g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) &&
494 (bytes = g_resources_lookup_data (resource->path, 0, NULL)))
496 const guchar *data;
497 gsize data_size;
499 data = g_bytes_get_data (bytes, &data_size);
500 content_type = g_content_type_guess (base, data, data_size, NULL);
502 g_bytes_unref (bytes);
504 else
505 content_type = NULL;
507 if (content_type)
509 _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE, content_type);
510 _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
512 g_free (content_type);
516 g_free (base);
517 g_file_attribute_matcher_unref (matcher);
519 return info;
522 static GFileAttributeInfoList *
523 g_resource_file_query_settable_attributes (GFile *file,
524 GCancellable *cancellable,
525 GError **error)
527 return g_file_attribute_info_list_ref (resource_writable_attributes);
530 static GFileAttributeInfoList *
531 g_resource_file_query_writable_namespaces (GFile *file,
532 GCancellable *cancellable,
533 GError **error)
535 return g_file_attribute_info_list_ref (resource_writable_namespaces);
538 static GFileInputStream *
539 g_resource_file_read (GFile *file,
540 GCancellable *cancellable,
541 GError **error)
543 GResourceFile *resource = G_RESOURCE_FILE (file);
544 GError *my_error = NULL;
545 GInputStream *stream;
546 GFileInputStream *res;
548 stream = g_resources_open_stream (resource->path, 0, &my_error);
550 if (stream == NULL)
552 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
554 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
555 _("The resource at '%s' does not exist"),
556 resource->path);
558 else
559 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
560 my_error->message);
561 g_clear_error (&my_error);
562 return NULL;
565 res = _g_resource_file_input_stream_new (stream, file);
566 g_object_unref (stream);
567 return res;
570 static void
571 g_resource_file_file_iface_init (GFileIface *iface)
573 iface->dup = g_resource_file_dup;
574 iface->hash = g_resource_file_hash;
575 iface->equal = g_resource_file_equal;
576 iface->is_native = g_resource_file_is_native;
577 iface->has_uri_scheme = g_resource_file_has_uri_scheme;
578 iface->get_uri_scheme = g_resource_file_get_uri_scheme;
579 iface->get_basename = g_resource_file_get_basename;
580 iface->get_path = g_resource_file_get_path;
581 iface->get_uri = g_resource_file_get_uri;
582 iface->get_parse_name = g_resource_file_get_parse_name;
583 iface->get_parent = g_resource_file_get_parent;
584 iface->prefix_matches = g_resource_file_prefix_matches;
585 iface->get_relative_path = g_resource_file_get_relative_path;
586 iface->resolve_relative_path = g_resource_file_resolve_relative_path;
587 iface->get_child_for_display_name = g_resource_file_get_child_for_display_name;
588 iface->enumerate_children = g_resource_file_enumerate_children;
589 iface->query_info = g_resource_file_query_info;
590 iface->query_settable_attributes = g_resource_file_query_settable_attributes;
591 iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
592 iface->read_fn = g_resource_file_read;
594 iface->supports_thread_contexts = TRUE;
597 static GFileInfo *g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
598 GCancellable *cancellable,
599 GError **error);
600 static gboolean g_resource_file_enumerator_close (GFileEnumerator *enumerator,
601 GCancellable *cancellable,
602 GError **error);
604 static void
605 g_resource_file_enumerator_finalize (GObject *object)
607 GResourceFileEnumerator *resource;
609 resource = G_RESOURCE_FILE_ENUMERATOR (object);
611 g_strfreev (resource->children);
612 g_free (resource->path);
613 g_free (resource->attributes);
615 G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
618 static void
619 g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
621 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
622 GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
624 gobject_class->finalize = g_resource_file_enumerator_finalize;
626 enumerator_class->next_file = g_resource_file_enumerator_next_file;
627 enumerator_class->close_fn = g_resource_file_enumerator_close;
630 static void
631 g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
635 static GFileEnumerator *
636 _g_resource_file_enumerator_new (GResourceFile *file,
637 const char *attributes,
638 GFileQueryInfoFlags flags,
639 GCancellable *cancellable,
640 GError **error)
642 GResourceFileEnumerator *resource;
643 char **children;
644 gboolean res;
646 children = g_resources_enumerate_children (file->path, 0, NULL);
647 if (children == NULL &&
648 strcmp ("/", file->path) != 0)
650 res = g_resources_get_info (file->path, 0, NULL, NULL, NULL);
651 if (res)
652 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
653 _("The resource at '%s' is not a directory"),
654 file->path);
655 else
656 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
657 _("The resource at '%s' does not exist"),
658 file->path);
659 return NULL;
662 resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
663 "container", file,
664 NULL);
666 resource->children = children;
667 resource->path = g_strdup (file->path);
668 resource->attributes = g_strdup (attributes);
669 resource->flags = flags;
671 return G_FILE_ENUMERATOR (resource);
674 static GFileInfo *
675 g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
676 GCancellable *cancellable,
677 GError **error)
679 GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
680 char *path;
681 GFileInfo *info;
682 GFile *file;
684 if (resource->children == NULL ||
685 resource->children[resource->index] == NULL)
686 return NULL;
688 path = g_build_path ("/", resource->path, resource->children[resource->index++], NULL);
689 file = g_resource_file_new_for_path (path);
690 g_free (path);
692 info = g_file_query_info (file,
693 resource->attributes,
694 resource->flags,
695 cancellable,
696 error);
698 g_object_unref (file);
700 return info;
703 static gboolean
704 g_resource_file_enumerator_close (GFileEnumerator *enumerator,
705 GCancellable *cancellable,
706 GError **error)
708 return TRUE;
712 struct _GResourceFileInputStream
714 GFileInputStream parent_instance;
715 GInputStream *stream;
716 GFile *file;
719 struct _GResourceFileInputStreamClass
721 GFileInputStreamClass parent_class;
724 #define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
725 G_DEFINE_TYPE (GResourceFileInputStream, g_resource_file_input_stream, G_TYPE_FILE_INPUT_STREAM);
727 static gssize g_resource_file_input_stream_read (GInputStream *stream,
728 void *buffer,
729 gsize count,
730 GCancellable *cancellable,
731 GError **error);
732 static gssize g_resource_file_input_stream_skip (GInputStream *stream,
733 gsize count,
734 GCancellable *cancellable,
735 GError **error);
736 static gboolean g_resource_file_input_stream_close (GInputStream *stream,
737 GCancellable *cancellable,
738 GError **error);
739 static goffset g_resource_file_input_stream_tell (GFileInputStream *stream);
740 static gboolean g_resource_file_input_stream_can_seek (GFileInputStream *stream);
741 static gboolean g_resource_file_input_stream_seek (GFileInputStream *stream,
742 goffset offset,
743 GSeekType type,
744 GCancellable *cancellable,
745 GError **error);
746 static GFileInfo *g_resource_file_input_stream_query_info (GFileInputStream *stream,
747 const char *attributes,
748 GCancellable *cancellable,
749 GError **error);
751 static void
752 g_resource_file_input_stream_finalize (GObject *object)
754 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
756 g_object_unref (file->stream);
757 g_object_unref (file->file);
758 G_OBJECT_CLASS (g_resource_file_input_stream_parent_class)->finalize (object);
761 static void
762 g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
764 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
765 GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
766 GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
768 gobject_class->finalize = g_resource_file_input_stream_finalize;
770 stream_class->read_fn = g_resource_file_input_stream_read;
771 stream_class->skip = g_resource_file_input_stream_skip;
772 stream_class->close_fn = g_resource_file_input_stream_close;
773 file_stream_class->tell = g_resource_file_input_stream_tell;
774 file_stream_class->can_seek = g_resource_file_input_stream_can_seek;
775 file_stream_class->seek = g_resource_file_input_stream_seek;
776 file_stream_class->query_info = g_resource_file_input_stream_query_info;
779 static void
780 g_resource_file_input_stream_init (GResourceFileInputStream *info)
784 static GFileInputStream *
785 _g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
787 GResourceFileInputStream *stream;
789 stream = g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM, NULL);
790 stream->stream = g_object_ref (in_stream);
791 stream->file = g_object_ref (file);
793 return G_FILE_INPUT_STREAM (stream);
796 static gssize
797 g_resource_file_input_stream_read (GInputStream *stream,
798 void *buffer,
799 gsize count,
800 GCancellable *cancellable,
801 GError **error)
803 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
804 return g_input_stream_read (file->stream,
805 buffer, count, cancellable, error);
808 static gssize
809 g_resource_file_input_stream_skip (GInputStream *stream,
810 gsize count,
811 GCancellable *cancellable,
812 GError **error)
814 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
815 return g_input_stream_skip (file->stream,
816 count, cancellable, error);
819 static gboolean
820 g_resource_file_input_stream_close (GInputStream *stream,
821 GCancellable *cancellable,
822 GError **error)
824 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
825 return g_input_stream_close (file->stream,
826 cancellable, error);
830 static goffset
831 g_resource_file_input_stream_tell (GFileInputStream *stream)
833 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
835 if (!G_IS_SEEKABLE (file->stream))
836 return 0;
838 return g_seekable_tell (G_SEEKABLE (file->stream));
841 static gboolean
842 g_resource_file_input_stream_can_seek (GFileInputStream *stream)
844 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
846 return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
849 static gboolean
850 g_resource_file_input_stream_seek (GFileInputStream *stream,
851 goffset offset,
852 GSeekType type,
853 GCancellable *cancellable,
854 GError **error)
856 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
858 if (!G_IS_SEEKABLE (file->stream))
860 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
861 _("Input stream doesn't implement seek"));
862 return FALSE;
865 return g_seekable_seek (G_SEEKABLE (file->stream),
866 offset, type, cancellable, error);
869 static GFileInfo *
870 g_resource_file_input_stream_query_info (GFileInputStream *stream,
871 const char *attributes,
872 GCancellable *cancellable,
873 GError **error)
875 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
877 return g_file_query_info (file->file, attributes, 0, cancellable, error);