bytereader: add gst_byte_reader_peek_sub_reader() and _get_sub_reader()
authorTim-Philipp Müller <tim@centricular.com>
Wed, 6 Aug 2014 13:01:09 +0000 (14:01 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Fri, 15 Aug 2014 09:03:26 +0000 (10:03 +0100)
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()

docs/libs/gstreamer-libs-sections.txt
libs/gst/base/gstbytereader.c
libs/gst/base/gstbytereader.h
tests/check/libs/bytereader.c
win32/common/libgstbase.def

index 83b19db..a27b372 100644 (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
index 6931841..75dfd08 100644 (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
@@ -100,6 +100,56 @@ gst_byte_reader_init (GstByteReader * reader, const guint8 * data, guint size)
 }
 
 /**
+ * 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
  * @pos: The new position in bytes
index 5b68837..dd66011 100644 (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);
 
@@ -456,6 +464,32 @@ _gst_byte_reader_init_inline (GstByteReader * reader, const guint8 * data, guint
 }
 
 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)
 {
   g_return_val_if_fail (reader != NULL, FALSE);
index d2a63cc..471e6a6 100644 (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;
 }
index bd31d95..92c3500 100644 (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