1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 * Author: Alexander Larsson <alexl@redhat.com>
27 #include "gresource.h"
28 #include "gresourcefile.h"
29 #include "gfileattribute.h"
30 #include <gfileattribute-priv.h>
31 #include <gfileinfo-priv.h>
33 #include "gfilemonitor.h"
34 #include "gseekable.h"
35 #include "gfileinputstream.h"
36 #include "gfileinfo.h"
37 #include "gfileenumerator.h"
38 #include "gcontenttype.h"
40 #include <glib/gstdio.h>
45 GObject parent_instance;
50 struct _GResourceFileEnumerator
52 GFileEnumerator parent;
54 GFileAttributeMatcher *matcher;
57 GFileQueryInfoFlags flags;
63 struct _GResourceFileEnumeratorClass
65 GFileEnumeratorClass parent_class;
68 typedef struct _GResourceFileEnumerator GResourceFileEnumerator;
69 typedef struct _GResourceFileEnumeratorClass GResourceFileEnumeratorClass;
71 static void g_resource_file_file_iface_init (GFileIface *iface);
73 static GFileAttributeInfoList *resource_writable_attributes = NULL;
74 static GFileAttributeInfoList *resource_writable_namespaces = NULL;
76 static GType _g_resource_file_enumerator_get_type (void);
78 #define G_TYPE_RESOURCE_FILE_ENUMERATOR (_g_resource_file_enumerator_get_type ())
79 #define G_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumerator))
80 #define G_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
81 #define G_IS_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR))
82 #define G_IS_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_ENUMERATOR))
83 #define G_RESOURCE_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
85 #define G_TYPE_RESOURCE_FILE_INPUT_STREAM (_g_resource_file_input_stream_get_type ())
86 #define G_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStream))
87 #define G_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
88 #define G_IS_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
89 #define G_IS_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
90 #define G_RESOURCE_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
92 typedef struct _GResourceFileInputStream GResourceFileInputStream;
93 typedef struct _GResourceFileInputStreamClass GResourceFileInputStreamClass;
95 #define g_resource_file_get_type _g_resource_file_get_type
96 G_DEFINE_TYPE_WITH_CODE (GResourceFile, g_resource_file, G_TYPE_OBJECT,
97 G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
98 g_resource_file_file_iface_init))
100 #define g_resource_file_enumerator_get_type _g_resource_file_enumerator_get_type
101 G_DEFINE_TYPE (GResourceFileEnumerator, g_resource_file_enumerator, G_TYPE_FILE_ENUMERATOR)
103 static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
104 const char *attributes,
105 GFileQueryInfoFlags flags,
106 GCancellable *cancellable,
110 static GType _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
112 static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
116 g_resource_file_finalize (GObject *object)
118 GResourceFile *resource;
120 resource = G_RESOURCE_FILE (object);
122 g_free (resource->path);
124 G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
128 g_resource_file_class_init (GResourceFileClass *klass)
130 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
132 gobject_class->finalize = g_resource_file_finalize;
134 resource_writable_attributes = g_file_attribute_info_list_new ();
135 resource_writable_namespaces = g_file_attribute_info_list_new ();
139 g_resource_file_init (GResourceFile *resource)
143 static inline gchar *
144 scan_backwards (const gchar *begin,
159 pop_to_previous_part (const gchar *begin,
163 *out = scan_backwards (begin, *out - 1, '/');
167 * canonicalize_filename:
168 * @in: the path to be canonicalized
170 * The path @in may contain non-canonical path pieces such as "../"
171 * or duplicated "/". This will resolve those into a form that only
172 * contains a single / at a time and resolves all "../". The resulting
173 * path must also start with a /.
175 * Returns: the canonical form of the path
178 canonicalize_filename (const char *in)
183 bptr = out = g_malloc (strlen (in) + 2);
188 g_assert (*out == '/');
190 /* move past slashes */
194 /* Handle ./ ../ .\0 ..\0 */
197 /* If this is ../ or ..\0 move up */
198 if (in[1] == '.' && (in[2] == '/' || in[2] == 0))
200 pop_to_previous_part (bptr, &out);
205 /* If this is ./ skip past it */
206 if (in[1] == '/' || in[1] == 0)
213 /* Scan to the next path piece */
214 while (*in != 0 && *in != '/')
217 /* Add trailing /, compress the rest on the next go round. */
222 /* Trim trailing / from path */
223 if (out > bptr && *out == '/')
232 g_resource_file_new_for_path (const char *path)
234 GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
236 resource->path = canonicalize_filename (path);
238 return G_FILE (resource);
241 /* Will return %NULL if @uri is malformed */
243 _g_resource_file_new (const char *uri)
248 path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
252 resource = g_resource_file_new_for_path (path);
255 return G_FILE (resource);
259 g_resource_file_is_native (GFile *file)
265 g_resource_file_has_uri_scheme (GFile *file,
266 const char *uri_scheme)
268 return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
272 g_resource_file_get_uri_scheme (GFile *file)
274 return g_strdup ("resource");
278 g_resource_file_get_basename (GFile *file)
282 base = strrchr (G_RESOURCE_FILE (file)->path, '/');
283 return g_strdup (base + 1);
287 g_resource_file_get_path (GFile *file)
293 g_resource_file_get_uri (GFile *file)
296 escaped = g_uri_escape_string (G_RESOURCE_FILE (file)->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
297 res = g_strconcat ("resource://", escaped, NULL);
303 g_resource_file_get_parse_name (GFile *file)
305 return g_resource_file_get_uri (file);
309 g_resource_file_get_parent (GFile *file)
311 GResourceFile *resource = G_RESOURCE_FILE (file);
312 GResourceFile *parent;
315 end = strrchr (resource->path, '/');
317 if (end == G_RESOURCE_FILE (file)->path)
320 parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
321 parent->path = g_strndup (resource->path,
322 end - resource->path);
324 return G_FILE (parent);
328 g_resource_file_dup (GFile *file)
330 GResourceFile *resource = G_RESOURCE_FILE (file);
332 return g_resource_file_new_for_path (resource->path);
336 g_resource_file_hash (GFile *file)
338 GResourceFile *resource = G_RESOURCE_FILE (file);
340 return g_str_hash (resource->path);
344 g_resource_file_equal (GFile *file1,
347 GResourceFile *resource1 = G_RESOURCE_FILE (file1);
348 GResourceFile *resource2 = G_RESOURCE_FILE (file2);
350 return g_str_equal (resource1->path, resource2->path);
354 match_prefix (const char *path,
359 prefix_len = strlen (prefix);
360 if (strncmp (path, prefix, prefix_len) != 0)
363 /* Handle the case where prefix is the root, so that
364 * the IS_DIR_SEPRARATOR check below works */
365 if (prefix_len > 0 &&
366 prefix[prefix_len-1] == '/')
369 return path + prefix_len;
373 g_resource_file_prefix_matches (GFile *parent,
376 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
377 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
378 const char *remainder;
380 remainder = match_prefix (descendant_resource->path, parent_resource->path);
381 if (remainder != NULL && *remainder == '/')
387 g_resource_file_get_relative_path (GFile *parent,
390 GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
391 GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
392 const char *remainder;
394 remainder = match_prefix (descendant_resource->path, parent_resource->path);
396 if (remainder != NULL && *remainder == '/')
397 return g_strdup (remainder + 1);
402 g_resource_file_resolve_relative_path (GFile *file,
403 const char *relative_path)
405 GResourceFile *resource = G_RESOURCE_FILE (file);
409 if (relative_path[0] == '/')
410 return g_resource_file_new_for_path (relative_path);
412 filename = g_build_path ("/", resource->path, relative_path, NULL);
413 child = g_resource_file_new_for_path (filename);
419 static GFileEnumerator *
420 g_resource_file_enumerate_children (GFile *file,
421 const char *attributes,
422 GFileQueryInfoFlags flags,
423 GCancellable *cancellable,
426 GResourceFile *resource = G_RESOURCE_FILE (file);
427 return _g_resource_file_enumerator_new (resource,
433 g_resource_file_get_child_for_display_name (GFile *file,
434 const char *display_name,
439 new_file = g_file_get_child (file, display_name);
445 g_resource_file_query_info (GFile *file,
446 const char *attributes,
447 GFileQueryInfoFlags flags,
448 GCancellable *cancellable,
451 GResourceFile *resource = G_RESOURCE_FILE (file);
452 GError *my_error = NULL;
454 GFileAttributeMatcher *matcher;
457 guint32 resource_flags = 0;
463 children = g_resources_enumerate_children (resource->path, 0, NULL);
464 if (children != NULL)
466 g_strfreev (children);
470 /* root is always there */
471 if (strcmp ("/", resource->path) == 0)
476 res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
479 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
481 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
482 _("The resource at “%s” does not exist"),
486 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
488 g_clear_error (&my_error);
493 matcher = g_file_attribute_matcher_new (attributes);
495 info = g_file_info_new ();
496 base = g_resource_file_get_basename (file);
497 g_file_info_set_name (info, base);
498 g_file_info_set_display_name (info, base);
500 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, TRUE);
501 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, FALSE);
502 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, FALSE);
503 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, FALSE);
504 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, FALSE);
505 _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, FALSE);
509 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
516 g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
517 g_file_info_set_size (info, size);
519 if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
520 ((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) &&
521 _g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) &&
522 (bytes = g_resources_lookup_data (resource->path, 0, NULL)))
527 data = g_bytes_get_data (bytes, &data_size);
528 content_type = g_content_type_guess (base, data, data_size, NULL);
530 g_bytes_unref (bytes);
537 _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE, content_type);
538 _g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
540 g_free (content_type);
545 g_file_attribute_matcher_unref (matcher);
551 g_resource_file_query_filesystem_info (GFile *file,
552 const char *attributes,
553 GCancellable *cancellable,
557 GFileAttributeMatcher *matcher;
559 info = g_file_info_new ();
561 matcher = g_file_attribute_matcher_new (attributes);
562 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
563 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "resource");
565 if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
566 g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
568 g_file_attribute_matcher_unref (matcher);
573 static GFileAttributeInfoList *
574 g_resource_file_query_settable_attributes (GFile *file,
575 GCancellable *cancellable,
578 return g_file_attribute_info_list_ref (resource_writable_attributes);
581 static GFileAttributeInfoList *
582 g_resource_file_query_writable_namespaces (GFile *file,
583 GCancellable *cancellable,
586 return g_file_attribute_info_list_ref (resource_writable_namespaces);
589 static GFileInputStream *
590 g_resource_file_read (GFile *file,
591 GCancellable *cancellable,
594 GResourceFile *resource = G_RESOURCE_FILE (file);
595 GError *my_error = NULL;
596 GInputStream *stream;
597 GFileInputStream *res;
599 stream = g_resources_open_stream (resource->path, 0, &my_error);
603 if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
605 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
606 _("The resource at “%s” does not exist"),
610 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
612 g_clear_error (&my_error);
616 res = _g_resource_file_input_stream_new (stream, file);
617 g_object_unref (stream);
621 typedef GFileMonitor GResourceFileMonitor;
622 typedef GFileMonitorClass GResourceFileMonitorClass;
624 GType g_resource_file_monitor_get_type (void);
626 G_DEFINE_TYPE (GResourceFileMonitor, g_resource_file_monitor, G_TYPE_FILE_MONITOR)
629 g_resource_file_monitor_cancel (GFileMonitor *monitor)
635 g_resource_file_monitor_init (GResourceFileMonitor *monitor)
640 g_resource_file_monitor_class_init (GResourceFileMonitorClass *class)
642 class->cancel = g_resource_file_monitor_cancel;
645 static GFileMonitor *
646 g_resource_file_monitor_file (GFile *file,
647 GFileMonitorFlags flags,
648 GCancellable *cancellable,
651 return g_object_new (g_resource_file_monitor_get_type (), NULL);
655 g_resource_file_set_display_name (GFile *file,
656 const char *display_name,
657 GCancellable *cancellable,
660 g_set_error_literal (error,
662 G_IO_ERROR_NOT_SUPPORTED,
663 _("Resource files cannot be renamed"));
668 g_resource_file_file_iface_init (GFileIface *iface)
670 iface->dup = g_resource_file_dup;
671 iface->hash = g_resource_file_hash;
672 iface->equal = g_resource_file_equal;
673 iface->is_native = g_resource_file_is_native;
674 iface->has_uri_scheme = g_resource_file_has_uri_scheme;
675 iface->get_uri_scheme = g_resource_file_get_uri_scheme;
676 iface->get_basename = g_resource_file_get_basename;
677 iface->get_path = g_resource_file_get_path;
678 iface->get_uri = g_resource_file_get_uri;
679 iface->get_parse_name = g_resource_file_get_parse_name;
680 iface->get_parent = g_resource_file_get_parent;
681 iface->prefix_matches = g_resource_file_prefix_matches;
682 iface->get_relative_path = g_resource_file_get_relative_path;
683 iface->resolve_relative_path = g_resource_file_resolve_relative_path;
684 iface->get_child_for_display_name = g_resource_file_get_child_for_display_name;
685 iface->set_display_name = g_resource_file_set_display_name;
686 iface->enumerate_children = g_resource_file_enumerate_children;
687 iface->query_info = g_resource_file_query_info;
688 iface->query_filesystem_info = g_resource_file_query_filesystem_info;
689 iface->query_settable_attributes = g_resource_file_query_settable_attributes;
690 iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
691 iface->read_fn = g_resource_file_read;
692 iface->monitor_file = g_resource_file_monitor_file;
694 iface->supports_thread_contexts = TRUE;
697 static GFileInfo *g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
698 GCancellable *cancellable,
700 static gboolean g_resource_file_enumerator_close (GFileEnumerator *enumerator,
701 GCancellable *cancellable,
705 g_resource_file_enumerator_finalize (GObject *object)
707 GResourceFileEnumerator *resource;
709 resource = G_RESOURCE_FILE_ENUMERATOR (object);
711 g_strfreev (resource->children);
712 g_free (resource->path);
713 g_free (resource->attributes);
715 G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
719 g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
721 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
722 GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
724 gobject_class->finalize = g_resource_file_enumerator_finalize;
726 enumerator_class->next_file = g_resource_file_enumerator_next_file;
727 enumerator_class->close_fn = g_resource_file_enumerator_close;
731 g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
735 static GFileEnumerator *
736 _g_resource_file_enumerator_new (GResourceFile *file,
737 const char *attributes,
738 GFileQueryInfoFlags flags,
739 GCancellable *cancellable,
742 GResourceFileEnumerator *resource;
746 children = g_resources_enumerate_children (file->path, 0, NULL);
747 if (children == NULL &&
748 strcmp ("/", file->path) != 0)
750 res = g_resources_get_info (file->path, 0, NULL, NULL, NULL);
752 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
753 _("The resource at “%s” is not a directory"),
756 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
757 _("The resource at “%s” does not exist"),
762 resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
766 resource->children = children;
767 resource->path = g_strdup (file->path);
768 resource->attributes = g_strdup (attributes);
769 resource->flags = flags;
771 return G_FILE_ENUMERATOR (resource);
775 g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
776 GCancellable *cancellable,
779 GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
784 if (resource->children == NULL ||
785 resource->children[resource->index] == NULL)
788 path = g_build_path ("/", resource->path, resource->children[resource->index++], NULL);
789 file = g_resource_file_new_for_path (path);
792 info = g_file_query_info (file,
793 resource->attributes,
798 g_object_unref (file);
804 g_resource_file_enumerator_close (GFileEnumerator *enumerator,
805 GCancellable *cancellable,
812 struct _GResourceFileInputStream
814 GFileInputStream parent_instance;
815 GInputStream *stream;
819 struct _GResourceFileInputStreamClass
821 GFileInputStreamClass parent_class;
824 #define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
825 G_DEFINE_TYPE (GResourceFileInputStream, g_resource_file_input_stream, G_TYPE_FILE_INPUT_STREAM)
827 static gssize g_resource_file_input_stream_read (GInputStream *stream,
830 GCancellable *cancellable,
832 static gssize g_resource_file_input_stream_skip (GInputStream *stream,
834 GCancellable *cancellable,
836 static gboolean g_resource_file_input_stream_close (GInputStream *stream,
837 GCancellable *cancellable,
839 static goffset g_resource_file_input_stream_tell (GFileInputStream *stream);
840 static gboolean g_resource_file_input_stream_can_seek (GFileInputStream *stream);
841 static gboolean g_resource_file_input_stream_seek (GFileInputStream *stream,
844 GCancellable *cancellable,
846 static GFileInfo *g_resource_file_input_stream_query_info (GFileInputStream *stream,
847 const char *attributes,
848 GCancellable *cancellable,
852 g_resource_file_input_stream_finalize (GObject *object)
854 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
856 g_object_unref (file->stream);
857 g_object_unref (file->file);
858 G_OBJECT_CLASS (g_resource_file_input_stream_parent_class)->finalize (object);
862 g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
864 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
865 GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
866 GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
868 gobject_class->finalize = g_resource_file_input_stream_finalize;
870 stream_class->read_fn = g_resource_file_input_stream_read;
871 stream_class->skip = g_resource_file_input_stream_skip;
872 stream_class->close_fn = g_resource_file_input_stream_close;
873 file_stream_class->tell = g_resource_file_input_stream_tell;
874 file_stream_class->can_seek = g_resource_file_input_stream_can_seek;
875 file_stream_class->seek = g_resource_file_input_stream_seek;
876 file_stream_class->query_info = g_resource_file_input_stream_query_info;
880 g_resource_file_input_stream_init (GResourceFileInputStream *info)
884 static GFileInputStream *
885 _g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
887 GResourceFileInputStream *stream;
889 stream = g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM, NULL);
890 stream->stream = g_object_ref (in_stream);
891 stream->file = g_object_ref (file);
893 return G_FILE_INPUT_STREAM (stream);
897 g_resource_file_input_stream_read (GInputStream *stream,
900 GCancellable *cancellable,
903 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
904 return g_input_stream_read (file->stream,
905 buffer, count, cancellable, error);
909 g_resource_file_input_stream_skip (GInputStream *stream,
911 GCancellable *cancellable,
914 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
915 return g_input_stream_skip (file->stream,
916 count, cancellable, error);
920 g_resource_file_input_stream_close (GInputStream *stream,
921 GCancellable *cancellable,
924 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
925 return g_input_stream_close (file->stream,
931 g_resource_file_input_stream_tell (GFileInputStream *stream)
933 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
935 if (!G_IS_SEEKABLE (file->stream))
938 return g_seekable_tell (G_SEEKABLE (file->stream));
942 g_resource_file_input_stream_can_seek (GFileInputStream *stream)
944 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
946 return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
950 g_resource_file_input_stream_seek (GFileInputStream *stream,
953 GCancellable *cancellable,
956 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
958 if (!G_IS_SEEKABLE (file->stream))
960 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
961 _("Input stream doesn’t implement seek"));
965 return g_seekable_seek (G_SEEKABLE (file->stream),
966 offset, type, cancellable, error);
970 g_resource_file_input_stream_query_info (GFileInputStream *stream,
971 const char *attributes,
972 GCancellable *cancellable,
975 GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
977 return g_file_query_info (file->file, attributes, 0, cancellable, error);