mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
bytereader: add gst_byte_reader_masked_scan_uint32()
Add a pattern scan function similar to the one recently added to GstAdapter, and a unit test (based on the adapter one). Fixes #585592. API: add gst_byte_reader_masked_scan_uint32()
This commit is contained in:
parent
c403e4b7f0
commit
674447fafe
5 changed files with 179 additions and 0 deletions
|
@ -446,6 +446,8 @@ gst_byte_reader_peek_float64_be
|
|||
|
||||
gst_byte_reader_get_data
|
||||
gst_byte_reader_peek_data
|
||||
|
||||
gst_byte_reader_masked_scan_uint32
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
|
|
@ -1207,3 +1207,81 @@ gst_byte_reader_peek_data (GstByteReader * reader, guint size,
|
|||
*val = reader->data + reader->byte;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_byte_reader_masked_scan_uint32:
|
||||
* @reader: a #GstByteReader
|
||||
* @mask: mask to apply to data before matching against @pattern
|
||||
* @pattern: pattern to match (after mask is applied)
|
||||
* @offset: offset into the adapter data from which to start scanning
|
||||
* @size: number of bytes to scan from offset
|
||||
*
|
||||
* Scan for pattern @pattern with applied mask @mask in the adapter data,
|
||||
* starting from offset @offset.
|
||||
*
|
||||
* The bytes in @pattern and @mask are interpreted left-to-right, regardless
|
||||
* of endianness. All four bytes of the pattern must be present in the
|
||||
* adapter for it to match, even if the first or last bytes are masked out.
|
||||
*
|
||||
* It is an error to call this function without making sure that there is
|
||||
* enough data (offset+size bytes) in the byte reader.
|
||||
*
|
||||
* Returns: offset of the first match, or -1 if no match was found.
|
||||
*
|
||||
* Example:
|
||||
* <programlisting>
|
||||
* // Assume the reader contains 0x00 0x01 0x02 ... 0xfe 0xff
|
||||
*
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x00010203, 0xffffffff, 0, 256);
|
||||
* // -> returns 0
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x00010203, 0xffffffff, 1, 255);
|
||||
* // -> returns -1
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x01020304, 0xffffffff, 1, 255);
|
||||
* // -> returns 1
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x0001, 0xffff, 0, 256);
|
||||
* // -> returns -1
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x0203, 0xffff, 0, 256);
|
||||
* // -> returns 0
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x02030000, 0xffff0000, 0, 256);
|
||||
* // -> returns 2
|
||||
* gst_byte_reader_masked_scan_uint32 (reader, 0x02030000, 0xffff0000, 0, 4);
|
||||
* // -> returns -1
|
||||
* </programlisting>
|
||||
*
|
||||
* Since: 0.10.24
|
||||
*/
|
||||
guint
|
||||
gst_byte_reader_masked_scan_uint32 (GstByteReader * reader, guint32 mask,
|
||||
guint32 pattern, guint offset, guint size)
|
||||
{
|
||||
const guint8 *data;
|
||||
guint32 state;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (size > 0, -1);
|
||||
g_return_val_if_fail (offset + size <= reader->size, -1);
|
||||
|
||||
/* we can't find the pattern with less than 4 bytes */
|
||||
if (G_UNLIKELY (size < 4))
|
||||
return -1;
|
||||
|
||||
data = reader->data + reader->byte + offset;
|
||||
|
||||
/* set the state to something that does not match */
|
||||
state = ~pattern;
|
||||
|
||||
/* now find data */
|
||||
for (i = 0; i < size; i++) {
|
||||
/* throw away one byte and move in the next byte */
|
||||
state = ((state << 8) | data[i]);
|
||||
if (G_UNLIKELY ((state & mask) == pattern)) {
|
||||
/* we have a match but we need to have skipped at
|
||||
* least 4 bytes to fill the state. */
|
||||
if (G_LIKELY (i >= 3))
|
||||
return offset + i - 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* nothing found */
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -105,6 +105,12 @@ gboolean gst_byte_reader_peek_float64_be (GstByteReader *reader, gdouble *val);
|
|||
gboolean gst_byte_reader_get_data (GstByteReader *reader, guint size, const guint8 **val);
|
||||
gboolean gst_byte_reader_peek_data (GstByteReader *reader, guint size, const guint8 **val);
|
||||
|
||||
guint gst_byte_reader_masked_scan_uint32 (GstByteReader * reader,
|
||||
guint32 mask,
|
||||
guint32 pattern,
|
||||
guint offset,
|
||||
guint size);
|
||||
|
||||
/**
|
||||
* GST_BYTE_READER_INIT:
|
||||
* @data: Data from which the #GstByteReader should read
|
||||
|
|
|
@ -460,6 +460,97 @@ GST_START_TEST (test_position_tracking)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
#define do_scan(r,m,p,o,s,x) \
|
||||
fail_unless_equals_int (gst_byte_reader_masked_scan_uint32 (r,m,p,o,s), x);
|
||||
|
||||
GST_START_TEST (test_scan)
|
||||
{
|
||||
GstByteReader reader;
|
||||
guint8 data[200];
|
||||
guint i;
|
||||
|
||||
/* fill half the buffer with a pattern */
|
||||
for (i = 0; i < 100; i++)
|
||||
data[i] = i;
|
||||
|
||||
gst_byte_reader_init (&reader, data, 100);
|
||||
|
||||
/* find first bytes */
|
||||
do_scan (&reader, 0xffffffff, 0x00010203, 0, 100, 0);
|
||||
do_scan (&reader, 0xffffffff, 0x01020304, 0, 100, 1);
|
||||
do_scan (&reader, 0xffffffff, 0x01020304, 1, 99, 1);
|
||||
/* offset is past the pattern start */
|
||||
do_scan (&reader, 0xffffffff, 0x01020304, 2, 98, -1);
|
||||
/* not enough bytes to find the pattern */
|
||||
do_scan (&reader, 0xffffffff, 0x02030405, 2, 3, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x02030405, 2, 4, 2);
|
||||
/* size does not include the last scanned byte */
|
||||
do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x41, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x43, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x40414243, 0, 0x44, 0x40);
|
||||
/* past the start */
|
||||
do_scan (&reader, 0xffffffff, 0x40414243, 65, 10, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x40414243, 64, 5, 64);
|
||||
do_scan (&reader, 0xffffffff, 0x60616263, 65, 35, 0x60);
|
||||
do_scan (&reader, 0xffffffff, 0x60616263, 0x60, 4, 0x60);
|
||||
/* past the start */
|
||||
do_scan (&reader, 0xffffffff, 0x60616263, 0x61, 3, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x60616263, 99, 1, -1);
|
||||
|
||||
/* add more data to the buffer */
|
||||
for (i = 100; i < 200; i++)
|
||||
data[i] = i;
|
||||
gst_byte_reader_init (&reader, data, 200);
|
||||
|
||||
/* past the start */
|
||||
do_scan (&reader, 0xffffffff, 0x60616263, 0x61, 6, -1);
|
||||
/* this should work */
|
||||
do_scan (&reader, 0xffffffff, 0x61626364, 0x61, 4, 0x61);
|
||||
/* not enough data */
|
||||
do_scan (&reader, 0xffffffff, 0x62636465, 0x61, 4, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x62636465, 0x61, 5, 0x62);
|
||||
do_scan (&reader, 0xffffffff, 0x62636465, 0, 120, 0x62);
|
||||
|
||||
/* border conditions */
|
||||
do_scan (&reader, 0xffffffff, 0x62636465, 0, 200, 0x62);
|
||||
do_scan (&reader, 0xffffffff, 0x63646566, 0, 200, 0x63);
|
||||
/* we completely searched the first list */
|
||||
do_scan (&reader, 0xffffffff, 0x64656667, 0, 200, 0x64);
|
||||
/* skip first buffer */
|
||||
do_scan (&reader, 0xffffffff, 0x64656667, 0x64, 100, 0x64);
|
||||
/* past the start */
|
||||
do_scan (&reader, 0xffffffff, 0x64656667, 0x65, 10, -1);
|
||||
/* not enough data to scan */
|
||||
do_scan (&reader, 0xffffffff, 0x64656667, 0x63, 4, -1);
|
||||
do_scan (&reader, 0xffffffff, 0x64656667, 0x63, 5, 0x64);
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0, 199, -1);
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x62, 102, 0xc4);
|
||||
/* different masks */
|
||||
do_scan (&reader, 0x00ffffff, 0x00656667, 0x64, 100, 0x64);
|
||||
do_scan (&reader, 0x000000ff, 0x00000000, 0, 100, -1);
|
||||
do_scan (&reader, 0x000000ff, 0x00000003, 0, 100, 0);
|
||||
do_scan (&reader, 0x000000ff, 0x00000061, 0x61, 100, -1);
|
||||
do_scan (&reader, 0xff000000, 0x61000000, 0, 0x62, -1);
|
||||
/* does not even exist */
|
||||
do_scan (&reader, 0x00ffffff, 0xffffffff, 0x65, 99, -1);
|
||||
|
||||
/* flush some bytes */
|
||||
gst_byte_reader_skip (&reader, 0x20);
|
||||
|
||||
do_scan (&reader, 0xffffffff, 0x20212223, 0, 100, 0);
|
||||
do_scan (&reader, 0xffffffff, 0x20212223, 0, 4, 0);
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x62, 70, 0xa4);
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0, 168, 0xa4);
|
||||
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 164, 4, 0xa4);
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x44, 100, 0xa4);
|
||||
|
||||
/* not enough bytes */
|
||||
do_scan (&reader, 0xffffffff, 0xc4c5c6c7, 0x44, 99, -1);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_byte_reader_suite (void)
|
||||
{
|
||||
|
@ -476,6 +567,7 @@ gst_byte_reader_suite (void)
|
|||
tcase_add_test (tc_chain, test_get_float_le);
|
||||
tcase_add_test (tc_chain, test_get_float_be);
|
||||
tcase_add_test (tc_chain, test_position_tracking);
|
||||
tcase_add_test (tc_chain, test_scan);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ EXPORTS
|
|||
gst_byte_reader_get_uint8
|
||||
gst_byte_reader_init
|
||||
gst_byte_reader_init_from_buffer
|
||||
gst_byte_reader_masked_scan_uint32
|
||||
gst_byte_reader_new
|
||||
gst_byte_reader_new_from_buffer
|
||||
gst_byte_reader_peek_data
|
||||
|
|
Loading…
Reference in a new issue