mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-23 22:16:16 +01:00
Make GBufferedInputStream implement GSeekable
https://bugzilla.gnome.org/show_bug.cgi?id=673034
This commit is contained in:
parent
86abe5163f
commit
90739baec0
@ -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 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);
|
||||
|
||||
static void compact_buffer (GBufferedInputStream *stream);
|
||||
|
||||
G_DEFINE_TYPE (GBufferedInputStream,
|
||||
g_buffered_input_stream,
|
||||
G_TYPE_FILTER_INPUT_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)
|
||||
@ -286,6 +304,16 @@ g_buffered_input_stream_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (g_buffered_input_stream_parent_class)->finalize (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)
|
||||
{
|
||||
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user