bytereader: add gst_byte_reader_peek_sub_reader() and _get_sub_reader()

Adds API to get or peek a sub-reader of a certain size from
a given byte reader. This is useful when parsing nested chunks,
one can easily get a byte reader for a sub-chunk and make
sure one never reads beyond the sub-chunk boundary.

API: gst_byte_reader_peek_sub_reader()
API: gst_byte_reader_get_sub_reader()
This commit is contained in:
Tim-Philipp Müller 2014-08-06 14:01:09 +01:00
parent b9fa37f074
commit 86d7a597f0
5 changed files with 172 additions and 1 deletions

View file

@ -442,6 +442,9 @@ gst_byte_reader_free
gst_byte_reader_init
gst_byte_reader_peek_sub_reader
gst_byte_reader_get_sub_reader
gst_byte_reader_get_pos
gst_byte_reader_get_remaining
gst_byte_reader_set_pos

View file

@ -1,7 +1,7 @@
/* GStreamer byte reader
*
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
* Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
* Copyright (C) 2009,2014 Tim-Philipp Müller <tim centricular net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -99,6 +99,56 @@ gst_byte_reader_init (GstByteReader * reader, const guint8 * data, guint size)
reader->byte = 0;
}
/**
* gst_byte_reader_peek_sub_reader: (skip)
* @reader: an existing and initialized #GstByteReader instance
* @sub_reader: a #GstByteReader instance to initialize as sub-reader
* @size: size of @sub_reader in bytes
*
* Initializes a #GstByteReader sub-reader instance to contain @size bytes of
* data from the current position of @reader. This is useful to read chunked
* formats and make sure that one doesn't read beyond the size of the sub-chunk.
*
* Unlike gst_byte_reader_get_sub_reader(), this function does not modify the
* current position of @reader.
*
* Returns: FALSE on error or if @reader does not contain @size more bytes from
* the current position, and otherwise TRUE
*
* Since: 1.6
*/
gboolean
gst_byte_reader_peek_sub_reader (GstByteReader * reader,
GstByteReader * sub_reader, guint size)
{
return _gst_byte_reader_peek_sub_reader_inline (reader, sub_reader, size);
}
/**
* gst_byte_reader_get_sub_reader: (skip)
* @reader: an existing and initialized #GstByteReader instance
* @sub_reader: a #GstByteReader instance to initialize as sub-reader
* @size: size of @sub_reader in bytes
*
* Initializes a #GstByteReader sub-reader instance to contain @size bytes of
* data from the current position of @reader. This is useful to read chunked
* formats and make sure that one doesn't read beyond the size of the sub-chunk.
*
* Unlike gst_byte_reader_peek_sub_reader(), this function also modifies the
* position of @reader and moves it forward by @size bytes.
*
* Returns: FALSE on error or if @reader does not contain @size more bytes from
* the current position, and otherwise TRUE
*
* Since: 1.6
*/
gboolean
gst_byte_reader_get_sub_reader (GstByteReader * reader,
GstByteReader * sub_reader, guint size)
{
return _gst_byte_reader_get_sub_reader_inline (reader, sub_reader, size);
}
/**
* gst_byte_reader_set_pos:
* @reader: a #GstByteReader instance

View file

@ -52,6 +52,14 @@ void gst_byte_reader_free (GstByteReader *reader);
void gst_byte_reader_init (GstByteReader *reader, const guint8 *data, guint size);
gboolean gst_byte_reader_peek_sub_reader (GstByteReader * reader,
GstByteReader * sub_reader,
guint size);
gboolean gst_byte_reader_get_sub_reader (GstByteReader * reader,
GstByteReader * sub_reader,
guint size);
gboolean gst_byte_reader_set_pos (GstByteReader *reader, guint pos);
guint gst_byte_reader_get_pos (const GstByteReader *reader);
@ -455,6 +463,32 @@ _gst_byte_reader_init_inline (GstByteReader * reader, const guint8 * data, guint
reader->byte = 0;
}
static inline gboolean
_gst_byte_reader_peek_sub_reader_inline (GstByteReader * reader,
GstByteReader * sub_reader, guint size)
{
g_return_val_if_fail (reader != NULL, FALSE);
g_return_val_if_fail (sub_reader != NULL, FALSE);
if (_gst_byte_reader_get_remaining_unchecked (reader) < size)
return FALSE;
sub_reader->data = reader->data + reader->byte;
sub_reader->byte = 0;
sub_reader->size = size;
return TRUE;
}
static inline gboolean
_gst_byte_reader_get_sub_reader_inline (GstByteReader * reader,
GstByteReader * sub_reader, guint size)
{
if (!_gst_byte_reader_peek_sub_reader_inline (reader, sub_reader, size))
return FALSE;
gst_byte_reader_skip_unchecked (reader, size);
return TRUE;
}
static inline gboolean
_gst_byte_reader_dup_data_inline (GstByteReader * reader, guint size, guint8 ** val)
{

View file

@ -696,6 +696,87 @@ GST_START_TEST (test_dup_string)
GST_END_TEST;
GST_START_TEST (test_sub_reader)
{
const guint8 memdata[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
GstByteReader reader = GST_BYTE_READER_INIT (memdata, sizeof (memdata));
GstByteReader sub;
const guint8 *data = NULL, *sub_data = NULL;
guint16 v = 0;
/* init sub reader */
fail_if (gst_byte_reader_peek_sub_reader (&reader, &sub, 17));
fail_unless (gst_byte_reader_peek_sub_reader (&reader, &sub, 16));
fail_unless_equals_int (gst_byte_reader_get_remaining (&sub), 16);
fail_unless (gst_byte_reader_peek_data (&reader, 16, &data));
fail_unless (gst_byte_reader_peek_data (&sub, 16, &sub_data));
fail_unless (memcmp (data, sub_data, 16) == 0);
fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 16);
fail_unless (gst_byte_reader_skip (&reader, 3));
fail_if (gst_byte_reader_peek_sub_reader (&reader, &sub, 14));
fail_unless (gst_byte_reader_peek_sub_reader (&reader, &sub, 13));
fail_unless_equals_int (gst_byte_reader_get_remaining (&sub), 13);
fail_unless (gst_byte_reader_peek_data (&reader, 13, &data));
fail_unless (gst_byte_reader_peek_data (&sub, 13, &sub_data));
fail_unless (memcmp (data, sub_data, 16) == 0);
fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 13);
fail_unless (gst_byte_reader_peek_sub_reader (&reader, &sub, 3));
fail_unless_equals_int (gst_byte_reader_get_remaining (&sub), 3);
fail_if (gst_byte_reader_peek_data (&sub, 10, &sub_data));
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0304);
fail_if (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (gst_byte_reader_get_remaining (&sub), 1);
fail_unless (gst_byte_reader_get_uint16_be (&reader, &v));
fail_unless_equals_int (v, 0x0304);
fail_unless (gst_byte_reader_get_uint16_be (&reader, &v));
fail_unless_equals_int (v, 0x0506);
fail_unless_equals_int (gst_byte_reader_get_remaining (&reader), 9);
/* get sub reader */
gst_byte_reader_init (&reader, memdata, sizeof (memdata));
fail_if (gst_byte_reader_get_sub_reader (&reader, &sub, 17));
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 16));
fail_if (gst_byte_reader_get_sub_reader (&reader, &sub, 1));
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 0));
gst_byte_reader_init (&reader, memdata, sizeof (memdata));
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 2));
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0001);
fail_if (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 3));
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0203);
fail_if (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (gst_byte_reader_get_uint8_unchecked (&sub), 0x04);
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 9));
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0506);
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0708);
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x090a);
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0b0c);
fail_if (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (gst_byte_reader_get_uint8_unchecked (&sub), 0x0d);
fail_if (gst_byte_reader_get_sub_reader (&reader, &sub, 3));
fail_unless (gst_byte_reader_get_sub_reader (&reader, &sub, 2));
fail_unless (gst_byte_reader_get_uint16_be (&sub, &v));
fail_unless_equals_int (v, 0x0e0f);
fail_if (gst_byte_reader_get_uint16_be (&sub, &v));
fail_if (gst_byte_reader_get_uint16_be (&reader, &v));
}
GST_END_TEST;
static Suite *
gst_byte_reader_suite (void)
{
@ -715,6 +796,7 @@ gst_byte_reader_suite (void)
tcase_add_test (tc_chain, test_scan);
tcase_add_test (tc_chain, test_string_funcs);
tcase_add_test (tc_chain, test_dup_string);
tcase_add_test (tc_chain, test_sub_reader);
return s;
}

View file

@ -142,6 +142,7 @@ EXPORTS
gst_byte_reader_get_remaining
gst_byte_reader_get_size
gst_byte_reader_get_string_utf8
gst_byte_reader_get_sub_reader
gst_byte_reader_get_uint16_be
gst_byte_reader_get_uint16_le
gst_byte_reader_get_uint24_be
@ -170,6 +171,7 @@ EXPORTS
gst_byte_reader_peek_int64_le
gst_byte_reader_peek_int8
gst_byte_reader_peek_string_utf8
gst_byte_reader_peek_sub_reader
gst_byte_reader_peek_uint16_be
gst_byte_reader_peek_uint16_le
gst_byte_reader_peek_uint24_be