/* * Copyright (C) 2006-2007 Red Hat, Inc * Copyright (C) 2016 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include "plover/inputstream.h" /** * SECTION:ploverrazorinputstream * @short_description: Streaming input operations on razor files * @include: plover/inputstream.h * @see_also: #GMemoryInputStream * * #PloverRazorInputStream provides input streams that get their * content via razor's URI input routines. */ struct _PloverRazorInputStreamPrivate { void *buf; gsize len; gsize pos; }; static gssize plover_razor_input_stream_read(GInputStream *stream,void *buffer, gsize count,GCancellable *cancellable,GError **error); static gssize plover_razor_input_stream_skip(GInputStream *stream,gsize count, GCancellable *cancellable,GError **error); static gboolean plover_razor_input_stream_close(GInputStream *stream, GCancellable *cancellable,GError **error); static void plover_razor_input_stream_skip_async(GInputStream *stream, gsize count,int io_priority,GCancellable *cancellable, GAsyncReadyCallback callback,gpointer data); static gssize plover_razor_input_stream_skip_finish(GInputStream *stream, GAsyncResult *result,GError **error); static void plover_razor_input_stream_close_async(GInputStream *stream, int io_priority,GCancellable *cancellable,GAsyncReadyCallback callback, gpointer data); static gboolean plover_razor_input_stream_close_finish(GInputStream *stream, GAsyncResult *result,GError **error); static void plover_razor_input_stream_seekable_iface_init(GSeekableIface *iface); static goffset plover_razor_input_stream_tell(GSeekable *seekable); static gboolean plover_razor_input_stream_can_seek(GSeekable *seekable); static gboolean plover_razor_input_stream_seek(GSeekable *seekable, goffset offset,GSeekType type,GCancellable *cancellable,GError **error); static gboolean plover_razor_input_stream_can_truncate(GSeekable *seekable); static gboolean plover_razor_input_stream_truncate(GSeekable *seekable, goffset offset,GCancellable *cancellable,GError **error); static void plover_razor_input_stream_pollable_iface_init( GPollableInputStreamInterface *iface); static gboolean plover_razor_input_stream_is_readable(GPollableInputStream *stream); static GSource * plover_razor_input_stream_create_source(GPollableInputStream *stream, GCancellable *cancellable); static void plover_razor_input_stream_finalize(GObject *object); G_DEFINE_TYPE_WITH_CODE(PloverRazorInputStream,plover_razor_input_stream, G_TYPE_INPUT_STREAM, G_IMPLEMENT_INTERFACE(G_TYPE_SEEKABLE, plover_razor_input_stream_seekable_iface_init); G_IMPLEMENT_INTERFACE(G_TYPE_POLLABLE_INPUT_STREAM, plover_razor_input_stream_pollable_iface_init); ) static void plover_razor_input_stream_class_init(PloverRazorInputStreamClass *klass) { GObjectClass *object_class; GInputStreamClass *istream_class; g_type_class_add_private(klass,sizeof(PloverRazorInputStreamPrivate)); object_class=G_OBJECT_CLASS(klass); object_class->finalize=plover_razor_input_stream_finalize; istream_class=G_INPUT_STREAM_CLASS(klass); istream_class->read_fn=plover_razor_input_stream_read; istream_class->skip=plover_razor_input_stream_skip; istream_class->close_fn=plover_razor_input_stream_close; istream_class->skip_async=plover_razor_input_stream_skip_async; istream_class->skip_finish=plover_razor_input_stream_skip_finish; istream_class->close_async=plover_razor_input_stream_close_async; istream_class->close_finish=plover_razor_input_stream_close_finish; } static void plover_razor_input_stream_finalize(GObject *object) { PloverRazorInputStream *razor_stream; PloverRazorInputStreamPrivate *priv; razor_stream=PLOVER_RAZOR_INPUT_STREAM(object); priv=razor_stream->priv; razor_uri_free_contents(priv->buf,priv->len); G_OBJECT_CLASS(plover_razor_input_stream_parent_class)->finalize(object); } static void plover_razor_input_stream_seekable_iface_init(GSeekableIface *iface) { iface->tell=plover_razor_input_stream_tell; iface->can_seek=plover_razor_input_stream_can_seek; iface->seek=plover_razor_input_stream_seek; iface->can_truncate=plover_razor_input_stream_can_truncate; iface->truncate_fn=plover_razor_input_stream_truncate; } static void plover_razor_input_stream_pollable_iface_init( GPollableInputStreamInterface *iface) { iface->is_readable=plover_razor_input_stream_is_readable; iface->create_source=plover_razor_input_stream_create_source; } static void plover_razor_input_stream_init(PloverRazorInputStream *stream) { stream->priv=G_TYPE_INSTANCE_GET_PRIVATE(stream, PLOVER_TYPE_RAZOR_INPUT_STREAM,PloverRazorInputStreamPrivate); } GInputStream *plover_razor_input_stream_new(const char *uri,GError **error) { void *buf; size_t len; struct razor_error *tmp_error=NULL; GInputStream *stream; PloverRazorInputStreamPrivate *priv; g_return_val_if_fail(plover__uri_validate(uri),NULL); buf=razor_uri_get_contents(uri,&len,FALSE,&tmp_error); if (!buf) { plover_propagate_razor_error(error,tmp_error); return NULL; } stream=g_object_new(PLOVER_TYPE_RAZOR_INPUT_STREAM,NULL); priv=PLOVER_RAZOR_INPUT_STREAM(stream)->priv; priv->buf=buf; priv->len=len; return stream; } static gssize plover_razor_input_stream_read(GInputStream *stream,void *buffer, gsize count,GCancellable *cancellable,GError **error) { PloverRazorInputStream *razor_stream; PloverRazorInputStreamPrivate *priv; razor_stream=PLOVER_RAZOR_INPUT_STREAM(stream); priv=razor_stream->priv; count=MIN(count,priv->len-priv->pos); memcpy(buffer,(guint8 *)priv->buf+priv->pos,count); priv->pos+=count; return count; } static gssize plover_razor_input_stream_skip(GInputStream *stream,gsize count, GCancellable *cancellable,GError **error) { PloverRazorInputStream *razor_stream; PloverRazorInputStreamPrivate *priv; razor_stream=PLOVER_RAZOR_INPUT_STREAM(stream); priv=razor_stream->priv; count=MIN(count,priv->len-priv->pos); priv->pos+=count; return count; } static gboolean plover_razor_input_stream_close(GInputStream *stream, GCancellable *cancellable,GError **error) { return TRUE; } static void plover_razor_input_stream_skip_async(GInputStream *stream, gsize count,int io_priority,GCancellable *cancellable, GAsyncReadyCallback callback,gpointer user_data) { GTask *task; gssize nskipped; GError *error=NULL; nskipped=G_INPUT_STREAM_GET_CLASS(stream)->skip(stream,count,cancellable, &error); task=g_task_new(stream,cancellable,callback,user_data); if (error) g_task_return_error(task,error); else g_task_return_int(task,nskipped); g_object_unref(task); } static gssize plover_razor_input_stream_skip_finish(GInputStream *stream, GAsyncResult *result,GError **error) { g_return_val_if_fail(g_task_is_valid(result,stream),-1); return g_task_propagate_int(G_TASK(result),error); } static void plover_razor_input_stream_close_async(GInputStream *stream, int io_priority,GCancellable *cancellable,GAsyncReadyCallback callback, gpointer user_data) { GTask *task; task=g_task_new(stream,cancellable,callback,user_data); g_task_return_boolean(task,TRUE); g_object_unref (task); } static gboolean plover_razor_input_stream_close_finish(GInputStream *stream, GAsyncResult *result,GError **error) { return TRUE; } static goffset plover_razor_input_stream_tell(GSeekable *seekable) { PloverRazorInputStream *razor_stream; PloverRazorInputStreamPrivate *priv; razor_stream=PLOVER_RAZOR_INPUT_STREAM(seekable); priv=razor_stream->priv; return priv->pos; } static gboolean plover_razor_input_stream_can_seek(GSeekable *seekable) { return TRUE; } static gboolean plover_razor_input_stream_seek(GSeekable *seekable, goffset offset,GSeekType type,GCancellable *cancellable,GError **error) { PloverRazorInputStream *razor_stream; PloverRazorInputStreamPrivate *priv; goffset absolute; razor_stream=PLOVER_RAZOR_INPUT_STREAM(seekable); priv=razor_stream->priv; switch(type) { case G_SEEK_CUR: absolute=priv->pos+offset; break; case G_SEEK_SET: absolute=offset; break; case G_SEEK_END: absolute=priv->len+offset; break; default: g_set_error_literal(error,G_IO_ERROR,G_IO_ERROR_INVALID_ARGUMENT, _("Invalid GSeekType supplied")); return FALSE; } if (absolute<0 || absolute>priv->len) { g_set_error_literal(error,G_IO_ERROR,G_IO_ERROR_INVALID_ARGUMENT, _("Invalid seek request")); return FALSE; } priv->pos=absolute; return TRUE; } static gboolean plover_razor_input_stream_can_truncate(GSeekable *seekable) { return FALSE; } static gboolean plover_razor_input_stream_truncate(GSeekable *seekable, goffset offset,GCancellable *cancellable,GError **error) { g_set_error_literal(error,G_IO_ERROR,G_IO_ERROR_NOT_SUPPORTED, _("Cannot truncate PloverRazorInputStream")); return FALSE; } static gboolean plover_razor_input_stream_is_readable(GPollableInputStream *stream) { return TRUE; } static GSource * plover_razor_input_stream_create_source(GPollableInputStream *stream, GCancellable *cancellable) { GSource *base_source,*pollable_source; base_source=g_timeout_source_new(0); pollable_source=g_pollable_source_new_full(stream,base_source,cancellable); g_source_unref(base_source); return pollable_source; }