mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-24 14:36:13 +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 "gcancellable.h"
|
||||||
#include "gasyncresult.h"
|
#include "gasyncresult.h"
|
||||||
#include "gsimpleasyncresult.h"
|
#include "gsimpleasyncresult.h"
|
||||||
|
#include "gseekable.h"
|
||||||
#include "gioerror.h"
|
#include "gioerror.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "glibintl.h"
|
#include "glibintl.h"
|
||||||
@ -114,12 +115,29 @@ static gssize g_buffered_input_stream_real_fill_finish (GBufferedInputStream *s
|
|||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
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);
|
static void compact_buffer (GBufferedInputStream *stream);
|
||||||
|
|
||||||
G_DEFINE_TYPE (GBufferedInputStream,
|
G_DEFINE_TYPE_WITH_CODE (GBufferedInputStream,
|
||||||
g_buffered_input_stream,
|
g_buffered_input_stream,
|
||||||
G_TYPE_FILTER_INPUT_STREAM)
|
G_TYPE_FILTER_INPUT_STREAM,
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
|
||||||
|
g_buffered_input_stream_seekable_iface_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
|
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);
|
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
|
static void
|
||||||
g_buffered_input_stream_init (GBufferedInputStream *stream)
|
g_buffered_input_stream_init (GBufferedInputStream *stream)
|
||||||
{
|
{
|
||||||
@ -826,6 +854,108 @@ g_buffered_input_stream_read (GInputStream *stream,
|
|||||||
return bytes_read;
|
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:
|
* g_buffered_input_stream_read_byte:
|
||||||
* @stream: a #GBufferedInputStream
|
* @stream: a #GBufferedInputStream
|
||||||
|
@ -283,6 +283,91 @@ test_close (void)
|
|||||||
g_object_unref (base);
|
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
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
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-byte", test_read_byte);
|
||||||
g_test_add_func ("/buffered-input-stream/read", test_read);
|
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/skip", test_skip);
|
||||||
|
g_test_add_func ("/buffered-input-stream/seek", test_seek);
|
||||||
g_test_add_func ("/filter-input-stream/close", test_close);
|
g_test_add_func ("/filter-input-stream/close", test_close);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
|
Loading…
Reference in New Issue
Block a user