[glib] Make GBufferedInputStream implement GSeekable
- From: Alexander Larsson <alexl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Make GBufferedInputStream implement GSeekable
- Date: Mon, 23 Apr 2012 08:58:02 +0000 (UTC)
commit 90739baec071f4bba19558a3e08a9f330f78070e
Author: Maciej Piechotka <uzytkownik2 gmail com>
Date: Wed Mar 28 14:12:44 2012 +0200
Make GBufferedInputStream implement GSeekable
https://bugzilla.gnome.org/show_bug.cgi?id=673034
gio/gbufferedinputstream.c | 138 +++++++++++++++++++++++++++++++++++-
gio/tests/buffered-input-stream.c | 86 +++++++++++++++++++++++
2 files changed, 220 insertions(+), 4 deletions(-)
---
diff --git a/gio/gbufferedinputstream.c b/gio/gbufferedinputstream.c
index e62a3de..166bd41 100644
--- a/gio/gbufferedinputstream.c
+++ b/gio/gbufferedinputstream.c
@@ -27,6 +27,7 @@
#include "gcancellable.h"
#include "gasyncresult.h"
#include "gsimpleasyncresult.h"
+#include "gseekable.h"
#include "gioerror.h"
#include <string.h>
#include "glibintl.h"
@@ -114,12 +115,29 @@ static gssize g_buffered_input_stream_real_fill_finish (GBufferedInputStream *s
GAsyncResult *result,
GError **error);
-static void compact_buffer (GBufferedInputStream *stream);
+static void g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface);
+static goffset g_buffered_input_stream_tell (GSeekable *seekable);
+static gboolean g_buffered_input_stream_can_seek (GSeekable *seekable);
+static gboolean g_buffered_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean g_buffered_input_stream_can_truncate (GSeekable *seekable);
+static gboolean g_buffered_input_stream_truncate (GSeekable *seekable,
+ goffset offset,
+ GCancellable *cancellable,
+ GError **error);
+
+static void g_buffered_input_stream_finalize (GObject *object);
-G_DEFINE_TYPE (GBufferedInputStream,
- g_buffered_input_stream,
- G_TYPE_FILTER_INPUT_STREAM)
+static void compact_buffer (GBufferedInputStream *stream);
+G_DEFINE_TYPE_WITH_CODE (GBufferedInputStream,
+ g_buffered_input_stream,
+ G_TYPE_FILTER_INPUT_STREAM,
+ G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
+ g_buffered_input_stream_seekable_iface_init))
static void
g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
@@ -287,6 +305,16 @@ g_buffered_input_stream_finalize (GObject *object)
}
static void
+g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface)
+{
+ iface->tell = g_buffered_input_stream_tell;
+ iface->can_seek = g_buffered_input_stream_can_seek;
+ iface->seek = g_buffered_input_stream_seek;
+ iface->can_truncate = g_buffered_input_stream_can_truncate;
+ iface->truncate_fn = g_buffered_input_stream_truncate;
+}
+
+static void
g_buffered_input_stream_init (GBufferedInputStream *stream)
{
stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
@@ -826,6 +854,108 @@ g_buffered_input_stream_read (GInputStream *stream,
return bytes_read;
}
+static goffset
+g_buffered_input_stream_tell (GSeekable *seekable)
+{
+ GBufferedInputStream *bstream;
+ GBufferedInputStreamPrivate *priv;
+ GInputStream *base_stream;
+ GSeekable *base_stream_seekable;
+ gsize available;
+ goffset base_offset;
+
+ bstream = G_BUFFERED_INPUT_STREAM (seekable);
+ priv = bstream->priv;
+
+ base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
+ if (!G_IS_SEEKABLE (base_stream))
+ return 0;
+ base_stream_seekable = G_SEEKABLE (base_stream);
+
+ available = priv->end - priv->pos;
+ base_offset = g_seekable_tell (base_stream_seekable);
+
+ return base_offset - available;
+}
+
+static gboolean
+g_buffered_input_stream_can_seek (GSeekable *seekable)
+{
+ GInputStream *base_stream;
+
+ base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
+ return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream));
+}
+
+static gboolean
+g_buffered_input_stream_seek (GSeekable *seekable,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GBufferedInputStream *bstream;
+ GBufferedInputStreamPrivate *priv;
+ GInputStream *base_stream;
+ GSeekable *base_stream_seekable;
+
+ bstream = G_BUFFERED_INPUT_STREAM (seekable);
+ priv = bstream->priv;
+
+ base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
+ if (!G_IS_SEEKABLE (base_stream))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Seek not supported on base stream"));
+ return FALSE;
+ }
+
+ base_stream_seekable = G_SEEKABLE (base_stream);
+
+ if (type == G_SEEK_CUR)
+ {
+ if (offset <= priv->end - priv->pos && offset >= -priv->pos)
+ {
+ priv->pos += offset;
+ return TRUE;
+ }
+ else
+ {
+ offset -= priv->end - priv->pos;
+ }
+ }
+
+ if (g_seekable_seek (base_stream_seekable, offset, type, cancellable, error))
+ {
+ priv->pos = 0;
+ priv->end = 0;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static gboolean
+g_buffered_input_stream_can_truncate (GSeekable *seekable)
+{
+ return FALSE;
+}
+
+static gboolean
+g_buffered_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 GBufferedInputStream"));
+ return FALSE;
+}
+
/**
* g_buffered_input_stream_read_byte:
* @stream: a #GBufferedInputStream
diff --git a/gio/tests/buffered-input-stream.c b/gio/tests/buffered-input-stream.c
index 8515351..7039367 100644
--- a/gio/tests/buffered-input-stream.c
+++ b/gio/tests/buffered-input-stream.c
@@ -283,6 +283,91 @@ test_close (void)
g_object_unref (base);
}
+static void
+test_seek (void)
+{
+ GInputStream *base;
+ GInputStream *in;
+ GError *error;
+ gint byte;
+ gboolean ret;
+
+ base = g_memory_input_stream_new_from_data ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ", -1, NULL);
+ in = g_buffered_input_stream_new_sized (base, 4);
+ error = NULL;
+
+ /* Seek by read */
+ g_assert_cmpstr (g_seekable_tell (G_SEEKABLE (in)), ==, 0);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'a');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 1);
+
+ /* Seek forward (in buffer) */
+ ret = g_seekable_seek (G_SEEKABLE (in), 1, G_SEEK_CUR, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 2);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'c');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 3);
+
+ /* Seek backward (in buffer) */
+ ret = g_seekable_seek (G_SEEKABLE (in), -2, G_SEEK_CUR, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 1);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'b');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 2);
+
+ /* Seek forward (outside buffer) */
+ ret = g_seekable_seek (G_SEEKABLE (in), 6, G_SEEK_CUR, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 8);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'i');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 9);
+
+ /* Seek backward (outside buffer) */
+ ret = g_seekable_seek (G_SEEKABLE (in), -6, G_SEEK_CUR, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 3);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'd');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 4);
+
+ /* Seek from beginning */
+ ret = g_seekable_seek (G_SEEKABLE (in), 8, G_SEEK_SET, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 8);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'i');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 9);
+
+ /* Seek from end */
+ ret = g_seekable_seek (G_SEEKABLE (in), -1, G_SEEK_END, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 50);
+ byte = g_buffered_input_stream_read_byte (G_BUFFERED_INPUT_STREAM (in), NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (byte, ==, 'Z');
+ g_assert_cmpint (g_seekable_tell (G_SEEKABLE (in)), ==, 51);
+
+ /* Cleanup */
+ g_object_unref (in);
+ g_object_unref (base);
+}
+
int
main (int argc,
char *argv[])
@@ -297,6 +382,7 @@ main (int argc,
g_test_add_func ("/buffered-input-stream/read-byte", test_read_byte);
g_test_add_func ("/buffered-input-stream/read", test_read);
g_test_add_func ("/buffered-input-stream/skip", test_skip);
+ g_test_add_func ("/buffered-input-stream/seek", test_seek);
g_test_add_func ("/filter-input-stream/close", test_close);
return g_test_run();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]