#include "gcancellable.h"
#include "gasyncresult.h"
#include "gsimpleasyncresult.h"
+#include "gseekable.h"
#include "gioerror.h"
#include <string.h>
#include "glibintl.h"
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)
}
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,
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
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[])
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();