glib/gio/gresourcefile.c

958 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
*/
#include "config.h"
#include <string.h>
#include "gresource.h"
#include "gresourcefile.h"
#include "gfileattribute.h"
#include <gfileattribute-priv.h>
#include <gfileinfo-priv.h>
#include "gfile.h"
#include "gfilemonitor.h"
#include "gseekable.h"
#include "gfileinputstream.h"
#include "gfileinfo.h"
#include "gfileenumerator.h"
#include "gcontenttype.h"
#include "gioerror.h"
#include <glib/gstdio.h>
#include "glibintl.h"
struct _GResourceFile
{
GObject parent_instance;
char *path;
};
struct _GResourceFileEnumerator
{
GFileEnumerator parent;
GFileAttributeMatcher *matcher;
char *path;
char *attributes;
GFileQueryInfoFlags flags;
int index;
char **children;
};
struct _GResourceFileEnumeratorClass
{
GFileEnumeratorClass parent_class;
};
typedef struct _GResourceFileEnumerator GResourceFileEnumerator;
typedef struct _GResourceFileEnumeratorClass GResourceFileEnumeratorClass;
static void g_resource_file_file_iface_init (GFileIface *iface);
static GFileAttributeInfoList *resource_writable_attributes = NULL;
static GFileAttributeInfoList *resource_writable_namespaces = NULL;
static GType _g_resource_file_enumerator_get_type (void);
#define G_TYPE_RESOURCE_FILE_ENUMERATOR (_g_resource_file_enumerator_get_type ())
#define G_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumerator))
#define G_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
#define G_IS_RESOURCE_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR))
#define G_IS_RESOURCE_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_ENUMERATOR))
#define G_RESOURCE_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_ENUMERATOR, GResourceFileEnumeratorClass))
#define G_TYPE_RESOURCE_FILE_INPUT_STREAM (_g_resource_file_input_stream_get_type ())
#define G_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStream))
#define G_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
#define G_IS_RESOURCE_FILE_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
#define G_IS_RESOURCE_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOURCE_FILE_INPUT_STREAM))
#define G_RESOURCE_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOURCE_FILE_INPUT_STREAM, GResourceFileInputStreamClass))
typedef struct _GResourceFileInputStream GResourceFileInputStream;
typedef struct _GResourceFileInputStreamClass GResourceFileInputStreamClass;
#define g_resource_file_get_type _g_resource_file_get_type
G_DEFINE_TYPE_WITH_CODE (GResourceFile, g_resource_file, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
g_resource_file_file_iface_init))
#define g_resource_file_enumerator_get_type _g_resource_file_enumerator_get_type
G_DEFINE_TYPE (GResourceFileEnumerator, g_resource_file_enumerator, G_TYPE_FILE_ENUMERATOR)
static GFileEnumerator *_g_resource_file_enumerator_new (GResourceFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error);
static GType _g_resource_file_input_stream_get_type (void) G_GNUC_CONST;
static GFileInputStream *_g_resource_file_input_stream_new (GInputStream *stream, GFile *file);
static void
g_resource_file_finalize (GObject *object)
{
GResourceFile *resource;
resource = G_RESOURCE_FILE (object);
g_free (resource->path);
G_OBJECT_CLASS (g_resource_file_parent_class)->finalize (object);
}
static void
g_resource_file_class_init (GResourceFileClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = g_resource_file_finalize;
resource_writable_attributes = g_file_attribute_info_list_new ();
resource_writable_namespaces = g_file_attribute_info_list_new ();
}
static void
g_resource_file_init (GResourceFile *resource)
{
}
static inline gchar *
scan_backwards (const gchar *begin,
const gchar *end,
gchar c)
{
while (end >= begin)
{
if (*end == c)
return (gchar *)end;
end--;
}
return NULL;
}
static inline void
pop_to_previous_part (const gchar *begin,
gchar **out)
{
if (*out > begin)
*out = scan_backwards (begin, *out - 1, '/');
}
/*
* canonicalize_filename:
* @in: the path to be canonicalized
*
* The path @in may contain non-canonical path pieces such as "../"
* or duplicated "/". This will resolve those into a form that only
* contains a single / at a time and resolves all "../". The resulting
* path must also start with a /.
*
* Returns: the canonical form of the path
*/
static char *
canonicalize_filename (const char *in)
{
gchar *bptr;
char *out;
bptr = out = g_malloc (strlen (in) + 2);
*out = '/';
while (*in != 0)
{
g_assert (*out == '/');
/* move past slashes */
while (*in == '/')
in++;
/* Handle ./ ../ .\0 ..\0 */
if (*in == '.')
{
/* If this is ../ or ..\0 move up */
if (in[1] == '.' && (in[2] == '/' || in[2] == 0))
{
pop_to_previous_part (bptr, &out);
in += 2;
continue;
}
/* If this is ./ skip past it */
if (in[1] == '/' || in[1] == 0)
{
in += 1;
continue;
}
}
/* Scan to the next path piece */
while (*in != 0 && *in != '/')
*(++out) = *(in++);
/* Add trailing /, compress the rest on the next go round. */
if (*in == '/')
*(++out) = *(in++);
}
/* Trim trailing / from path */
if (out > bptr && *out == '/')
*out = 0;
else
*(++out) = 0;
return bptr;
}
static GFile *
g_resource_file_new_for_path (const char *path)
{
GResourceFile *resource = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
resource->path = canonicalize_filename (path);
return G_FILE (resource);
}
GFile *
_g_resource_file_new (const char *uri)
{
GFile *resource;
char *path;
path = g_uri_unescape_string (uri + strlen ("resource:"), NULL);
resource = g_resource_file_new_for_path (path);
g_free (path);
return G_FILE (resource);
}
static gboolean
g_resource_file_is_native (GFile *file)
{
return FALSE;
}
static gboolean
g_resource_file_has_uri_scheme (GFile *file,
const char *uri_scheme)
{
return g_ascii_strcasecmp (uri_scheme, "resource") == 0;
}
static char *
g_resource_file_get_uri_scheme (GFile *file)
{
return g_strdup ("resource");
}
static char *
g_resource_file_get_basename (GFile *file)
{
gchar *base;
base = strrchr (G_RESOURCE_FILE (file)->path, '/');
return g_strdup (base + 1);
}
static char *
g_resource_file_get_path (GFile *file)
{
return NULL;
}
static char *
g_resource_file_get_uri (GFile *file)
{
char *escaped, *res;
escaped = g_uri_escape_string (G_RESOURCE_FILE (file)->path, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, FALSE);
res = g_strconcat ("resource://", escaped, NULL);
g_free (escaped);
return res;
}
static char *
g_resource_file_get_parse_name (GFile *file)
{
return g_resource_file_get_uri (file);
}
static GFile *
g_resource_file_get_parent (GFile *file)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
GResourceFile *parent;
gchar *end;
end = strrchr (resource->path, '/');
if (end == G_RESOURCE_FILE (file)->path)
return NULL;
parent = g_object_new (G_TYPE_RESOURCE_FILE, NULL);
parent->path = g_strndup (resource->path,
end - resource->path);
return G_FILE (parent);
}
static GFile *
g_resource_file_dup (GFile *file)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
return g_resource_file_new_for_path (resource->path);
}
static guint
g_resource_file_hash (GFile *file)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
return g_str_hash (resource->path);
}
static gboolean
g_resource_file_equal (GFile *file1,
GFile *file2)
{
GResourceFile *resource1 = G_RESOURCE_FILE (file1);
GResourceFile *resource2 = G_RESOURCE_FILE (file2);
return g_str_equal (resource1->path, resource2->path);
}
static const char *
match_prefix (const char *path,
const char *prefix)
{
int prefix_len;
prefix_len = strlen (prefix);
if (strncmp (path, prefix, prefix_len) != 0)
return NULL;
/* Handle the case where prefix is the root, so that
* the IS_DIR_SEPRARATOR check below works */
if (prefix_len > 0 &&
prefix[prefix_len-1] == '/')
prefix_len--;
return path + prefix_len;
}
static gboolean
g_resource_file_prefix_matches (GFile *parent,
GFile *descendant)
{
GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
const char *remainder;
remainder = match_prefix (descendant_resource->path, parent_resource->path);
if (remainder != NULL && *remainder == '/')
return TRUE;
return FALSE;
}
static char *
g_resource_file_get_relative_path (GFile *parent,
GFile *descendant)
{
GResourceFile *parent_resource = G_RESOURCE_FILE (parent);
GResourceFile *descendant_resource = G_RESOURCE_FILE (descendant);
const char *remainder;
remainder = match_prefix (descendant_resource->path, parent_resource->path);
if (remainder != NULL && *remainder == '/')
return g_strdup (remainder + 1);
return NULL;
}
static GFile *
g_resource_file_resolve_relative_path (GFile *file,
const char *relative_path)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
char *filename;
GFile *child;
if (relative_path[0] == '/')
return g_resource_file_new_for_path (relative_path);
filename = g_build_path ("/", resource->path, relative_path, NULL);
child = g_resource_file_new_for_path (filename);
g_free (filename);
return child;
}
static GFileEnumerator *
g_resource_file_enumerate_children (GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
return _g_resource_file_enumerator_new (resource,
attributes, flags,
cancellable, error);
}
static GFile *
g_resource_file_get_child_for_display_name (GFile *file,
const char *display_name,
GError **error)
{
GFile *new_file;
new_file = g_file_get_child (file, display_name);
return new_file;
}
static GFileInfo *
g_resource_file_query_info (GFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
GError *my_error = NULL;
GFileInfo *info;
GFileAttributeMatcher *matcher;
gboolean res;
gsize size = 0;
guint32 resource_flags = 0;
char **children;
gboolean is_dir;
char *base;
is_dir = FALSE;
children = g_resources_enumerate_children (resource->path, 0, NULL);
if (children != NULL)
{
g_strfreev (children);
is_dir = TRUE;
}
/* root is always there */
if (strcmp ("/", resource->path) == 0)
is_dir = TRUE;
if (!is_dir)
{
res = g_resources_get_info (resource->path, 0, &size, &resource_flags, &my_error);
if (!res)
{
if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
_("The resource at “%s” does not exist"),
resource->path);
}
else
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
my_error->message);
g_clear_error (&my_error);
return FALSE;
}
}
matcher = g_file_attribute_matcher_new (attributes);
info = g_file_info_new ();
base = g_resource_file_get_basename (file);
g_file_info_set_name (info, base);
g_file_info_set_display_name (info, base);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ, TRUE);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE, FALSE);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE, FALSE);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME, FALSE);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, FALSE);
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, FALSE);
if (is_dir)
{
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
}
else
{
GBytes *bytes;
char *content_type;
g_file_info_set_file_type (info, G_FILE_TYPE_REGULAR);
g_file_info_set_size (info, size);
if ((_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
((~resource_flags & G_RESOURCE_FLAGS_COMPRESSED) &&
_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))) &&
(bytes = g_resources_lookup_data (resource->path, 0, NULL)))
{
const guchar *data;
gsize data_size;
data = g_bytes_get_data (bytes, &data_size);
content_type = g_content_type_guess (base, data, data_size, NULL);
g_bytes_unref (bytes);
}
else
content_type = NULL;
if (content_type)
{
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE, content_type);
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
g_free (content_type);
}
}
g_free (base);
g_file_attribute_matcher_unref (matcher);
return info;
}
static GFileInfo *
g_resource_file_query_filesystem_info (GFile *file,
const char *attributes,
GCancellable *cancellable,
GError **error)
{
GFileInfo *info;
GFileAttributeMatcher *matcher;
info = g_file_info_new ();
matcher = g_file_attribute_matcher_new (attributes);
if (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "resource");
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);
g_file_attribute_matcher_unref (matcher);
return info;
}
static GFileAttributeInfoList *
g_resource_file_query_settable_attributes (GFile *file,
GCancellable *cancellable,
GError **error)
{
return g_file_attribute_info_list_ref (resource_writable_attributes);
}
static GFileAttributeInfoList *
g_resource_file_query_writable_namespaces (GFile *file,
GCancellable *cancellable,
GError **error)
{
return g_file_attribute_info_list_ref (resource_writable_namespaces);
}
static GFileInputStream *
g_resource_file_read (GFile *file,
GCancellable *cancellable,
GError **error)
{
GResourceFile *resource = G_RESOURCE_FILE (file);
GError *my_error = NULL;
GInputStream *stream;
GFileInputStream *res;
stream = g_resources_open_stream (resource->path, 0, &my_error);
if (stream == NULL)
{
if (g_error_matches (my_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
_("The resource at “%s” does not exist"),
resource->path);
}
else
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
my_error->message);
g_clear_error (&my_error);
return NULL;
}
res = _g_resource_file_input_stream_new (stream, file);
g_object_unref (stream);
return res;
}
typedef GFileMonitor GResourceFileMonitor;
typedef GFileMonitorClass GResourceFileMonitorClass;
GType g_resource_file_monitor_get_type (void);
G_DEFINE_TYPE (GResourceFileMonitor, g_resource_file_monitor, G_TYPE_FILE_MONITOR)
static gboolean
g_resource_file_monitor_cancel (GFileMonitor *monitor)
{
return TRUE;
}
static void
g_resource_file_monitor_init (GResourceFileMonitor *monitor)
{
}
static void
g_resource_file_monitor_class_init (GResourceFileMonitorClass *class)
{
class->cancel = g_resource_file_monitor_cancel;
}
static GFileMonitor *
g_resource_file_monitor_file (GFile *file,
GFileMonitorFlags flags,
GCancellable *cancellable,
GError **error)
{
return g_object_new (g_resource_file_monitor_get_type (), NULL);
}
static void
g_resource_file_file_iface_init (GFileIface *iface)
{
iface->dup = g_resource_file_dup;
iface->hash = g_resource_file_hash;
iface->equal = g_resource_file_equal;
iface->is_native = g_resource_file_is_native;
iface->has_uri_scheme = g_resource_file_has_uri_scheme;
iface->get_uri_scheme = g_resource_file_get_uri_scheme;
iface->get_basename = g_resource_file_get_basename;
iface->get_path = g_resource_file_get_path;
iface->get_uri = g_resource_file_get_uri;
iface->get_parse_name = g_resource_file_get_parse_name;
iface->get_parent = g_resource_file_get_parent;
iface->prefix_matches = g_resource_file_prefix_matches;
iface->get_relative_path = g_resource_file_get_relative_path;
iface->resolve_relative_path = g_resource_file_resolve_relative_path;
iface->get_child_for_display_name = g_resource_file_get_child_for_display_name;
iface->enumerate_children = g_resource_file_enumerate_children;
iface->query_info = g_resource_file_query_info;
iface->query_filesystem_info = g_resource_file_query_filesystem_info;
iface->query_settable_attributes = g_resource_file_query_settable_attributes;
iface->query_writable_namespaces = g_resource_file_query_writable_namespaces;
iface->read_fn = g_resource_file_read;
iface->monitor_file = g_resource_file_monitor_file;
iface->supports_thread_contexts = TRUE;
}
static GFileInfo *g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
GCancellable *cancellable,
GError **error);
static gboolean g_resource_file_enumerator_close (GFileEnumerator *enumerator,
GCancellable *cancellable,
GError **error);
static void
g_resource_file_enumerator_finalize (GObject *object)
{
GResourceFileEnumerator *resource;
resource = G_RESOURCE_FILE_ENUMERATOR (object);
g_strfreev (resource->children);
g_free (resource->path);
g_free (resource->attributes);
G_OBJECT_CLASS (g_resource_file_enumerator_parent_class)->finalize (object);
}
static void
g_resource_file_enumerator_class_init (GResourceFileEnumeratorClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
gobject_class->finalize = g_resource_file_enumerator_finalize;
enumerator_class->next_file = g_resource_file_enumerator_next_file;
enumerator_class->close_fn = g_resource_file_enumerator_close;
}
static void
g_resource_file_enumerator_init (GResourceFileEnumerator *resource)
{
}
static GFileEnumerator *
_g_resource_file_enumerator_new (GResourceFile *file,
const char *attributes,
GFileQueryInfoFlags flags,
GCancellable *cancellable,
GError **error)
{
GResourceFileEnumerator *resource;
char **children;
gboolean res;
children = g_resources_enumerate_children (file->path, 0, NULL);
if (children == NULL &&
strcmp ("/", file->path) != 0)
{
res = g_resources_get_info (file->path, 0, NULL, NULL, NULL);
if (res)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,
_("The resource at “%s” is not a directory"),
file->path);
else
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
_("The resource at “%s” does not exist"),
file->path);
return NULL;
}
resource = g_object_new (G_TYPE_RESOURCE_FILE_ENUMERATOR,
"container", file,
NULL);
resource->children = children;
resource->path = g_strdup (file->path);
resource->attributes = g_strdup (attributes);
resource->flags = flags;
return G_FILE_ENUMERATOR (resource);
}
static GFileInfo *
g_resource_file_enumerator_next_file (GFileEnumerator *enumerator,
GCancellable *cancellable,
GError **error)
{
GResourceFileEnumerator *resource = G_RESOURCE_FILE_ENUMERATOR (enumerator);
char *path;
GFileInfo *info;
GFile *file;
if (resource->children == NULL ||
resource->children[resource->index] == NULL)
return NULL;
path = g_build_path ("/", resource->path, resource->children[resource->index++], NULL);
file = g_resource_file_new_for_path (path);
g_free (path);
info = g_file_query_info (file,
resource->attributes,
resource->flags,
cancellable,
error);
g_object_unref (file);
return info;
}
static gboolean
g_resource_file_enumerator_close (GFileEnumerator *enumerator,
GCancellable *cancellable,
GError **error)
{
return TRUE;
}
struct _GResourceFileInputStream
{
GFileInputStream parent_instance;
GInputStream *stream;
GFile *file;
};
struct _GResourceFileInputStreamClass
{
GFileInputStreamClass parent_class;
};
#define g_resource_file_input_stream_get_type _g_resource_file_input_stream_get_type
G_DEFINE_TYPE (GResourceFileInputStream, g_resource_file_input_stream, G_TYPE_FILE_INPUT_STREAM)
static gssize g_resource_file_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error);
static gssize g_resource_file_input_stream_skip (GInputStream *stream,
gsize count,
GCancellable *cancellable,
GError **error);
static gboolean g_resource_file_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error);
static goffset g_resource_file_input_stream_tell (GFileInputStream *stream);
static gboolean g_resource_file_input_stream_can_seek (GFileInputStream *stream);
static gboolean g_resource_file_input_stream_seek (GFileInputStream *stream,
goffset offset,
GSeekType type,
GCancellable *cancellable,
GError **error);
static GFileInfo *g_resource_file_input_stream_query_info (GFileInputStream *stream,
const char *attributes,
GCancellable *cancellable,
GError **error);
static void
g_resource_file_input_stream_finalize (GObject *object)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (object);
g_object_unref (file->stream);
g_object_unref (file->file);
G_OBJECT_CLASS (g_resource_file_input_stream_parent_class)->finalize (object);
}
static void
g_resource_file_input_stream_class_init (GResourceFileInputStreamClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
GFileInputStreamClass *file_stream_class = G_FILE_INPUT_STREAM_CLASS (klass);
gobject_class->finalize = g_resource_file_input_stream_finalize;
stream_class->read_fn = g_resource_file_input_stream_read;
stream_class->skip = g_resource_file_input_stream_skip;
stream_class->close_fn = g_resource_file_input_stream_close;
file_stream_class->tell = g_resource_file_input_stream_tell;
file_stream_class->can_seek = g_resource_file_input_stream_can_seek;
file_stream_class->seek = g_resource_file_input_stream_seek;
file_stream_class->query_info = g_resource_file_input_stream_query_info;
}
static void
g_resource_file_input_stream_init (GResourceFileInputStream *info)
{
}
static GFileInputStream *
_g_resource_file_input_stream_new (GInputStream *in_stream, GFile *file)
{
GResourceFileInputStream *stream;
stream = g_object_new (G_TYPE_RESOURCE_FILE_INPUT_STREAM, NULL);
stream->stream = g_object_ref (in_stream);
stream->file = g_object_ref (file);
return G_FILE_INPUT_STREAM (stream);
}
static gssize
g_resource_file_input_stream_read (GInputStream *stream,
void *buffer,
gsize count,
GCancellable *cancellable,
GError **error)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
return g_input_stream_read (file->stream,
buffer, count, cancellable, error);
}
static gssize
g_resource_file_input_stream_skip (GInputStream *stream,
gsize count,
GCancellable *cancellable,
GError **error)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
return g_input_stream_skip (file->stream,
count, cancellable, error);
}
static gboolean
g_resource_file_input_stream_close (GInputStream *stream,
GCancellable *cancellable,
GError **error)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
return g_input_stream_close (file->stream,
cancellable, error);
}
static goffset
g_resource_file_input_stream_tell (GFileInputStream *stream)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
if (!G_IS_SEEKABLE (file->stream))
return 0;
return g_seekable_tell (G_SEEKABLE (file->stream));
}
static gboolean
g_resource_file_input_stream_can_seek (GFileInputStream *stream)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
return G_IS_SEEKABLE (file->stream) && g_seekable_can_seek (G_SEEKABLE (file->stream));
}
static gboolean
g_resource_file_input_stream_seek (GFileInputStream *stream,
goffset offset,
GSeekType type,
GCancellable *cancellable,
GError **error)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
if (!G_IS_SEEKABLE (file->stream))
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Input stream doesnt implement seek"));
return FALSE;
}
return g_seekable_seek (G_SEEKABLE (file->stream),
offset, type, cancellable, error);
}
static GFileInfo *
g_resource_file_input_stream_query_info (GFileInputStream *stream,
const char *attributes,
GCancellable *cancellable,
GError **error)
{
GResourceFileInputStream *file = G_RESOURCE_FILE_INPUT_STREAM (stream);
return g_file_query_info (file->file, attributes, 0, cancellable, error);
}