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.1 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, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
25 #include "gresource.h"
26 #include "gresourcefile.h"
27 #include "gfileattribute.h"
28 #include <gfileattribute-priv.h>
29 #include <gfileinfo-priv.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"
38 #include <glib/gstdio.h>
43 GObject parent_instance
;
48 struct _GResourceFileEnumerator
50 GFileEnumerator parent
;
52 GFileAttributeMatcher
*matcher
;
55 GFileQueryInfoFlags flags
;
61 struct _GResourceFileEnumeratorClass
63 GFileEnumeratorClass parent_class
;
66 typedef struct _GResourceFileEnumerator GResourceFileEnumerator
;
67 typedef struct _GResourceFileEnumeratorClass GResourceFileEnumeratorClass
;
69 static void g_resource_file_file_iface_init (GFileIface
*iface
);
71 static GFileAttributeInfoList
*resource_writable_attributes
= NULL
;
72 static GFileAttributeInfoList
*resource_writable_namespaces
= NULL
;
74 static GType
_g_resource_file_enumerator_get_type (void);
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))
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))
90 typedef struct _GResourceFileInputStream GResourceFileInputStream
;
91 typedef struct _GResourceFileInputStreamClass GResourceFileInputStreamClass
;
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
))
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
)
101 static GFileEnumerator
*_g_resource_file_enumerator_new (GResourceFile
*file
,
102 const char *attributes
,
103 GFileQueryInfoFlags flags
,
104 GCancellable
*cancellable
,
108 static GType
_g_resource_file_input_stream_get_type (void) G_GNUC_CONST
;
110 static GFileInputStream
*_g_resource_file_input_stream_new (GInputStream
*stream
, GFile
*file
);
114 g_resource_file_finalize (GObject
*object
)
116 GResourceFile
*resource
;
118 resource
= G_RESOURCE_FILE (object
);
120 g_free (resource
->path
);
122 G_OBJECT_CLASS (g_resource_file_parent_class
)->finalize (object
);
126 g_resource_file_class_init (GResourceFileClass
*klass
)
128 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
130 gobject_class
->finalize
= g_resource_file_finalize
;
132 resource_writable_attributes
= g_file_attribute_info_list_new ();
133 resource_writable_namespaces
= g_file_attribute_info_list_new ();
137 g_resource_file_init (GResourceFile
*resource
)
141 static inline gchar
*
142 scan_backwards (const gchar
*begin
,
157 pop_to_previous_part (const gchar
*begin
,
161 *out
= scan_backwards (begin
, *out
- 1, '/');
165 * canonicalize_filename:
166 * @in: the path to be canonicalized
168 * The path @in may contain non-canonical path pieces such as "../"
169 * or duplicated "/". This will resolve those into a form that only
170 * contains a single / at a time and resolves all "../". The resulting
171 * path must also start with a /.
173 * Returns: the canonical form of the path
176 canonicalize_filename (const char *in
)
181 bptr
= out
= g_malloc (strlen (in
) + 2);
186 g_assert (*out
== '/');
188 /* move past slashes */
192 /* Handle ./ ../ .\0 ..\0 */
195 /* If this is ../ or ..\0 move up */
196 if (in
[1] == '.' && (in
[2] == '/' || in
[2] == 0))
198 pop_to_previous_part (bptr
, &out
);
203 /* If this is ./ skip past it */
204 if (in
[1] == '/' || in
[1] == 0)
211 /* Scan to the next path piece */
212 while (*in
!= 0 && *in
!= '/')
215 /* Add trailing /, compress the rest on the next go round. */
220 /* Trim trailing / from path */
221 if (out
> bptr
&& *out
== '/')
230 g_resource_file_new_for_path (const char *path
)
232 GResourceFile
*resource
= g_object_new (G_TYPE_RESOURCE_FILE
, NULL
);
234 resource
->path
= canonicalize_filename (path
);
236 return G_FILE (resource
);
240 _g_resource_file_new (const char *uri
)
245 path
= g_uri_unescape_string (uri
+ strlen ("resource:"), NULL
);
246 resource
= g_resource_file_new_for_path (path
);
249 return G_FILE (resource
);
253 g_resource_file_is_native (GFile
*file
)
259 g_resource_file_has_uri_scheme (GFile
*file
,
260 const char *uri_scheme
)
262 return g_ascii_strcasecmp (uri_scheme
, "resource") == 0;
266 g_resource_file_get_uri_scheme (GFile
*file
)
268 return g_strdup ("resource");
272 g_resource_file_get_basename (GFile
*file
)
276 base
= strrchr (G_RESOURCE_FILE (file
)->path
, '/');
277 return g_strdup (base
+ 1);
281 g_resource_file_get_path (GFile
*file
)
287 g_resource_file_get_uri (GFile
*file
)
290 escaped
= g_uri_escape_string (G_RESOURCE_FILE (file
)->path
, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH
, FALSE
);
291 res
= g_strconcat ("resource://", escaped
, NULL
);
297 g_resource_file_get_parse_name (GFile
*file
)
299 return g_resource_file_get_uri (file
);
303 g_resource_file_get_parent (GFile
*file
)
305 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
306 GResourceFile
*parent
;
309 end
= strrchr (resource
->path
, '/');
311 if (end
== G_RESOURCE_FILE (file
)->path
)
314 parent
= g_object_new (G_TYPE_RESOURCE_FILE
, NULL
);
315 parent
->path
= g_strndup (resource
->path
,
316 end
- resource
->path
);
318 return G_FILE (parent
);
322 g_resource_file_dup (GFile
*file
)
324 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
326 return g_resource_file_new_for_path (resource
->path
);
330 g_resource_file_hash (GFile
*file
)
332 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
334 return g_str_hash (resource
->path
);
338 g_resource_file_equal (GFile
*file1
,
341 GResourceFile
*resource1
= G_RESOURCE_FILE (file1
);
342 GResourceFile
*resource2
= G_RESOURCE_FILE (file2
);
344 return g_str_equal (resource1
->path
, resource2
->path
);
348 match_prefix (const char *path
,
353 prefix_len
= strlen (prefix
);
354 if (strncmp (path
, prefix
, prefix_len
) != 0)
357 /* Handle the case where prefix is the root, so that
358 * the IS_DIR_SEPRARATOR check below works */
359 if (prefix_len
> 0 &&
360 prefix
[prefix_len
-1] == '/')
363 return path
+ prefix_len
;
367 g_resource_file_prefix_matches (GFile
*parent
,
370 GResourceFile
*parent_resource
= G_RESOURCE_FILE (parent
);
371 GResourceFile
*descendant_resource
= G_RESOURCE_FILE (descendant
);
372 const char *remainder
;
374 remainder
= match_prefix (descendant_resource
->path
, parent_resource
->path
);
375 if (remainder
!= NULL
&& *remainder
== '/')
381 g_resource_file_get_relative_path (GFile
*parent
,
384 GResourceFile
*parent_resource
= G_RESOURCE_FILE (parent
);
385 GResourceFile
*descendant_resource
= G_RESOURCE_FILE (descendant
);
386 const char *remainder
;
388 remainder
= match_prefix (descendant_resource
->path
, parent_resource
->path
);
390 if (remainder
!= NULL
&& *remainder
== '/')
391 return g_strdup (remainder
+ 1);
396 g_resource_file_resolve_relative_path (GFile
*file
,
397 const char *relative_path
)
399 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
403 if (relative_path
[0] == '/')
404 return g_resource_file_new_for_path (relative_path
);
406 filename
= g_build_path ("/", resource
->path
, relative_path
, NULL
);
407 child
= g_resource_file_new_for_path (filename
);
413 static GFileEnumerator
*
414 g_resource_file_enumerate_children (GFile
*file
,
415 const char *attributes
,
416 GFileQueryInfoFlags flags
,
417 GCancellable
*cancellable
,
420 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
421 return _g_resource_file_enumerator_new (resource
,
427 g_resource_file_get_child_for_display_name (GFile
*file
,
428 const char *display_name
,
433 new_file
= g_file_get_child (file
, display_name
);
439 g_resource_file_query_info (GFile
*file
,
440 const char *attributes
,
441 GFileQueryInfoFlags flags
,
442 GCancellable
*cancellable
,
445 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
446 GError
*my_error
= NULL
;
448 GFileAttributeMatcher
*matcher
;
451 guint32 resource_flags
;
457 children
= g_resources_enumerate_children (resource
->path
, 0, NULL
);
458 if (children
!= NULL
)
460 g_strfreev (children
);
464 /* root is always there */
465 if (strcmp ("/", resource
->path
) == 0)
470 res
= g_resources_get_info (resource
->path
, 0, &size
, &resource_flags
, &my_error
);
473 if (g_error_matches (my_error
, G_RESOURCE_ERROR
, G_RESOURCE_ERROR_NOT_FOUND
))
475 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
,
476 _("The resource at “%s” does not exist"),
480 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
482 g_clear_error (&my_error
);
487 matcher
= g_file_attribute_matcher_new (attributes
);
489 info
= g_file_info_new ();
490 base
= g_resource_file_get_basename (file
);
491 g_file_info_set_name (info
, base
);
492 g_file_info_set_display_name (info
, base
);
494 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ
, TRUE
);
495 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE
, FALSE
);
496 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE
, FALSE
);
497 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME
, FALSE
);
498 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE
, FALSE
);
499 _g_file_info_set_attribute_boolean_by_id (info
, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH
, FALSE
);
503 g_file_info_set_file_type (info
, G_FILE_TYPE_DIRECTORY
);
510 g_file_info_set_file_type (info
, G_FILE_TYPE_REGULAR
);
511 g_file_info_set_size (info
, size
);
513 if ((_g_file_attribute_matcher_matches_id (matcher
, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE
) ||
514 ((~resource_flags
& G_RESOURCE_FLAGS_COMPRESSED
) &&
515 _g_file_attribute_matcher_matches_id (matcher
, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE
))) &&
516 (bytes
= g_resources_lookup_data (resource
->path
, 0, NULL
)))
521 data
= g_bytes_get_data (bytes
, &data_size
);
522 content_type
= g_content_type_guess (base
, data
, data_size
, NULL
);
524 g_bytes_unref (bytes
);
531 _g_file_info_set_attribute_string_by_id (info
, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE
, content_type
);
532 _g_file_info_set_attribute_string_by_id (info
, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE
, content_type
);
534 g_free (content_type
);
539 g_file_attribute_matcher_unref (matcher
);
545 g_resource_file_query_filesystem_info (GFile
*file
,
546 const char *attributes
,
547 GCancellable
*cancellable
,
551 GFileAttributeMatcher
*matcher
;
553 info
= g_file_info_new ();
555 matcher
= g_file_attribute_matcher_new (attributes
);
556 if (g_file_attribute_matcher_matches (matcher
, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE
))
557 g_file_info_set_attribute_string (info
, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE
, "resource");
559 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
);
561 g_file_attribute_matcher_unref (matcher
);
566 static GFileAttributeInfoList
*
567 g_resource_file_query_settable_attributes (GFile
*file
,
568 GCancellable
*cancellable
,
571 return g_file_attribute_info_list_ref (resource_writable_attributes
);
574 static GFileAttributeInfoList
*
575 g_resource_file_query_writable_namespaces (GFile
*file
,
576 GCancellable
*cancellable
,
579 return g_file_attribute_info_list_ref (resource_writable_namespaces
);
582 static GFileInputStream
*
583 g_resource_file_read (GFile
*file
,
584 GCancellable
*cancellable
,
587 GResourceFile
*resource
= G_RESOURCE_FILE (file
);
588 GError
*my_error
= NULL
;
589 GInputStream
*stream
;
590 GFileInputStream
*res
;
592 stream
= g_resources_open_stream (resource
->path
, 0, &my_error
);
596 if (g_error_matches (my_error
, G_RESOURCE_ERROR
, G_RESOURCE_ERROR_NOT_FOUND
))
598 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
,
599 _("The resource at “%s” does not exist"),
603 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
605 g_clear_error (&my_error
);
609 res
= _g_resource_file_input_stream_new (stream
, file
);
610 g_object_unref (stream
);
614 typedef GFileMonitor GResourceFileMonitor
;
615 typedef GFileMonitorClass GResourceFileMonitorClass
;
617 GType
g_resource_file_monitor_get_type (void);
619 G_DEFINE_TYPE (GResourceFileMonitor
, g_resource_file_monitor
, G_TYPE_FILE_MONITOR
)
622 g_resource_file_monitor_cancel (GFileMonitor
*monitor
)
628 g_resource_file_monitor_init (GResourceFileMonitor
*monitor
)
633 g_resource_file_monitor_class_init (GResourceFileMonitorClass
*class)
635 class->cancel
= g_resource_file_monitor_cancel
;
638 static GFileMonitor
*
639 g_resource_file_monitor_file (GFile
*file
,
640 GFileMonitorFlags flags
,
641 GCancellable
*cancellable
,
644 return g_object_new (g_resource_file_monitor_get_type (), NULL
);
648 g_resource_file_file_iface_init (GFileIface
*iface
)
650 iface
->dup
= g_resource_file_dup
;
651 iface
->hash
= g_resource_file_hash
;
652 iface
->equal
= g_resource_file_equal
;
653 iface
->is_native
= g_resource_file_is_native
;
654 iface
->has_uri_scheme
= g_resource_file_has_uri_scheme
;
655 iface
->get_uri_scheme
= g_resource_file_get_uri_scheme
;
656 iface
->get_basename
= g_resource_file_get_basename
;
657 iface
->get_path
= g_resource_file_get_path
;
658 iface
->get_uri
= g_resource_file_get_uri
;
659 iface
->get_parse_name
= g_resource_file_get_parse_name
;
660 iface
->get_parent
= g_resource_file_get_parent
;
661 iface
->prefix_matches
= g_resource_file_prefix_matches
;
662 iface
->get_relative_path
= g_resource_file_get_relative_path
;
663 iface
->resolve_relative_path
= g_resource_file_resolve_relative_path
;
664 iface
->get_child_for_display_name
= g_resource_file_get_child_for_display_name
;
665 iface
->enumerate_children
= g_resource_file_enumerate_children
;
666 iface
->query_info
= g_resource_file_query_info
;
667 iface
->query_filesystem_info
= g_resource_file_query_filesystem_info
;
668 iface
->query_settable_attributes
= g_resource_file_query_settable_attributes
;
669 iface
->query_writable_namespaces
= g_resource_file_query_writable_namespaces
;
670 iface
->read_fn
= g_resource_file_read
;
671 iface
->monitor_file
= g_resource_file_monitor_file
;
673 iface
->supports_thread_contexts
= TRUE
;
676 static GFileInfo
*g_resource_file_enumerator_next_file (GFileEnumerator
*enumerator
,
677 GCancellable
*cancellable
,
679 static gboolean
g_resource_file_enumerator_close (GFileEnumerator
*enumerator
,
680 GCancellable
*cancellable
,
684 g_resource_file_enumerator_finalize (GObject
*object
)
686 GResourceFileEnumerator
*resource
;
688 resource
= G_RESOURCE_FILE_ENUMERATOR (object
);
690 g_strfreev (resource
->children
);
691 g_free (resource
->path
);
692 g_free (resource
->attributes
);
694 G_OBJECT_CLASS (g_resource_file_enumerator_parent_class
)->finalize (object
);
698 g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass
*klass
)
700 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
701 GFileEnumeratorClass
*enumerator_class
= G_FILE_ENUMERATOR_CLASS (klass
);
703 gobject_class
->finalize
= g_resource_file_enumerator_finalize
;
705 enumerator_class
->next_file
= g_resource_file_enumerator_next_file
;
706 enumerator_class
->close_fn
= g_resource_file_enumerator_close
;
710 g_resource_file_enumerator_init (GResourceFileEnumerator
*resource
)
714 static GFileEnumerator
*
715 _g_resource_file_enumerator_new (GResourceFile
*file
,
716 const char *attributes
,
717 GFileQueryInfoFlags flags
,
718 GCancellable
*cancellable
,
721 GResourceFileEnumerator
*resource
;
725 children
= g_resources_enumerate_children (file
->path
, 0, NULL
);
726 if (children
== NULL
&&
727 strcmp ("/", file
->path
) != 0)
729 res
= g_resources_get_info (file
->path
, 0, NULL
, NULL
, NULL
);
731 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_DIRECTORY
,
732 _("The resource at “%s” is not a directory"),
735 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
,
736 _("The resource at “%s” does not exist"),
741 resource
= g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR
,
745 resource
->children
= children
;
746 resource
->path
= g_strdup (file
->path
);
747 resource
->attributes
= g_strdup (attributes
);
748 resource
->flags
= flags
;
750 return G_FILE_ENUMERATOR (resource
);
754 g_resource_file_enumerator_next_file (GFileEnumerator
*enumerator
,
755 GCancellable
*cancellable
,
758 GResourceFileEnumerator
*resource
= G_RESOURCE_FILE_ENUMERATOR (enumerator
);
763 if (resource
->children
== NULL
||
764 resource
->children
[resource
->index
] == NULL
)
767 path
= g_build_path ("/", resource
->path
, resource
->children
[resource
->index
++], NULL
);
768 file
= g_resource_file_new_for_path (path
);
771 info
= g_file_query_info (file
,
772 resource
->attributes
,
777 g_object_unref (file
);
783 g_resource_file_enumerator_close (GFileEnumerator
*enumerator
,
784 GCancellable
*cancellable
,
791 struct _GResourceFileInputStream
793 GFileInputStream parent_instance
;
794 GInputStream
*stream
;
798 struct _GResourceFileInputStreamClass
800 GFileInputStreamClass parent_class
;
803 #define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
804 G_DEFINE_TYPE (GResourceFileInputStream
, g_resource_file_input_stream
, G_TYPE_FILE_INPUT_STREAM
)
806 static gssize
g_resource_file_input_stream_read (GInputStream
*stream
,
809 GCancellable
*cancellable
,
811 static gssize
g_resource_file_input_stream_skip (GInputStream
*stream
,
813 GCancellable
*cancellable
,
815 static gboolean
g_resource_file_input_stream_close (GInputStream
*stream
,
816 GCancellable
*cancellable
,
818 static goffset
g_resource_file_input_stream_tell (GFileInputStream
*stream
);
819 static gboolean
g_resource_file_input_stream_can_seek (GFileInputStream
*stream
);
820 static gboolean
g_resource_file_input_stream_seek (GFileInputStream
*stream
,
823 GCancellable
*cancellable
,
825 static GFileInfo
*g_resource_file_input_stream_query_info (GFileInputStream
*stream
,
826 const char *attributes
,
827 GCancellable
*cancellable
,
831 g_resource_file_input_stream_finalize (GObject
*object
)
833 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (object
);
835 g_object_unref (file
->stream
);
836 g_object_unref (file
->file
);
837 G_OBJECT_CLASS (g_resource_file_input_stream_parent_class
)->finalize (object
);
841 g_resource_file_input_stream_class_init (GResourceFileInputStreamClass
*klass
)
843 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
844 GInputStreamClass
*stream_class
= G_INPUT_STREAM_CLASS (klass
);
845 GFileInputStreamClass
*file_stream_class
= G_FILE_INPUT_STREAM_CLASS (klass
);
847 gobject_class
->finalize
= g_resource_file_input_stream_finalize
;
849 stream_class
->read_fn
= g_resource_file_input_stream_read
;
850 stream_class
->skip
= g_resource_file_input_stream_skip
;
851 stream_class
->close_fn
= g_resource_file_input_stream_close
;
852 file_stream_class
->tell
= g_resource_file_input_stream_tell
;
853 file_stream_class
->can_seek
= g_resource_file_input_stream_can_seek
;
854 file_stream_class
->seek
= g_resource_file_input_stream_seek
;
855 file_stream_class
->query_info
= g_resource_file_input_stream_query_info
;
859 g_resource_file_input_stream_init (GResourceFileInputStream
*info
)
863 static GFileInputStream
*
864 _g_resource_file_input_stream_new (GInputStream
*in_stream
, GFile
*file
)
866 GResourceFileInputStream
*stream
;
868 stream
= g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM
, NULL
);
869 stream
->stream
= g_object_ref (in_stream
);
870 stream
->file
= g_object_ref (file
);
872 return G_FILE_INPUT_STREAM (stream
);
876 g_resource_file_input_stream_read (GInputStream
*stream
,
879 GCancellable
*cancellable
,
882 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
883 return g_input_stream_read (file
->stream
,
884 buffer
, count
, cancellable
, error
);
888 g_resource_file_input_stream_skip (GInputStream
*stream
,
890 GCancellable
*cancellable
,
893 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
894 return g_input_stream_skip (file
->stream
,
895 count
, cancellable
, error
);
899 g_resource_file_input_stream_close (GInputStream
*stream
,
900 GCancellable
*cancellable
,
903 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
904 return g_input_stream_close (file
->stream
,
910 g_resource_file_input_stream_tell (GFileInputStream
*stream
)
912 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
914 if (!G_IS_SEEKABLE (file
->stream
))
917 return g_seekable_tell (G_SEEKABLE (file
->stream
));
921 g_resource_file_input_stream_can_seek (GFileInputStream
*stream
)
923 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
925 return G_IS_SEEKABLE (file
->stream
) && g_seekable_can_seek (G_SEEKABLE (file
->stream
));
929 g_resource_file_input_stream_seek (GFileInputStream
*stream
,
932 GCancellable
*cancellable
,
935 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
937 if (!G_IS_SEEKABLE (file
->stream
))
939 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NOT_SUPPORTED
,
940 _("Input stream doesn’t implement seek"));
944 return g_seekable_seek (G_SEEKABLE (file
->stream
),
945 offset
, type
, cancellable
, error
);
949 g_resource_file_input_stream_query_info (GFileInputStream
*stream
,
950 const char *attributes
,
951 GCancellable
*cancellable
,
954 GResourceFileInputStream
*file
= G_RESOURCE_FILE_INPUT_STREAM (stream
);
956 return g_file_query_info (file
->file
, attributes
, 0, cancellable
, error
);