diff --git a/libfprint/fpi-byte-reader.c b/libfprint/fpi-byte-reader.c new file mode 100644 index 0000000..aecbe5b --- /dev/null +++ b/libfprint/fpi-byte-reader.c @@ -0,0 +1,1259 @@ +/* GStreamer byte reader + * + * Copyright (C) 2008 Sebastian Dröge . + * Copyright (C) 2009,2014 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define FPI_BYTE_READER_DISABLE_INLINES +#include "fpi-byte-reader.h" + +#include + +/** + * SECTION:fpi-byte-reader + * @title: FpiByteReader + * @short_description: Reads different integer, string and floating point + * types from a memory buffer + * + * #FpiByteReader provides a byte reader that can read different integer and + * floating point types from a memory buffer. It provides functions for reading + * signed/unsigned, little/big endian integers of 8, 16, 24, 32 and 64 bits + * and functions for reading little/big endian floating points numbers of + * 32 and 64 bits. It also provides functions to read NUL-terminated strings + * in various character encodings. + */ + +/** + * fpi_byte_reader_new: (skip) + * @data: (in) (transfer none) (array length=size): data from which the + * #FpiByteReader should read + * @size: Size of @data in bytes + * + * Create a new #FpiByteReader instance, which will read from @data. + * + * Free-function: fpi_byte_reader_free + * + * Returns: (transfer full): a new #FpiByteReader instance + */ +FpiByteReader * +fpi_byte_reader_new (const guint8 * data, guint size) +{ + FpiByteReader *ret = g_slice_new0 (FpiByteReader); + + ret->data = data; + ret->size = size; + + return ret; +} + +/** + * fpi_byte_reader_free: + * @reader: (in) (transfer full): a #FpiByteReader instance + * + * Frees a #FpiByteReader instance, which was previously allocated by + * fpi_byte_reader_new(). + */ +void +fpi_byte_reader_free (FpiByteReader * reader) +{ + g_return_if_fail (reader != NULL); + + g_slice_free (FpiByteReader, reader); +} + +/** + * fpi_byte_reader_init: + * @reader: a #FpiByteReader instance + * @data: (in) (transfer none) (array length=size): data from which + * the #FpiByteReader should read + * @size: Size of @data in bytes + * + * Initializes a #FpiByteReader instance to read from @data. This function + * can be called on already initialized instances. + */ +void +fpi_byte_reader_init (FpiByteReader * reader, const guint8 * data, guint size) +{ + g_return_if_fail (reader != NULL); + + reader->data = data; + reader->size = size; + reader->byte = 0; +} + +/** + * fpi_byte_reader_peek_sub_reader: (skip) + * @reader: an existing and initialized #FpiByteReader instance + * @sub_reader: a #FpiByteReader instance to initialize as sub-reader + * @size: size of @sub_reader in bytes + * + * Initializes a #FpiByteReader 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 fpi_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 +fpi_byte_reader_peek_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + return fpi_byte_reader_peek_sub_reader_inline (reader, sub_reader, size); +} + +/** + * fpi_byte_reader_get_sub_reader: (skip) + * @reader: an existing and initialized #FpiByteReader instance + * @sub_reader: a #FpiByteReader instance to initialize as sub-reader + * @size: size of @sub_reader in bytes + * + * Initializes a #FpiByteReader 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 fpi_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 +fpi_byte_reader_get_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + return fpi_byte_reader_get_sub_reader_inline (reader, sub_reader, size); +} + +/** + * fpi_byte_reader_set_pos: + * @reader: a #FpiByteReader instance + * @pos: The new position in bytes + * + * Sets the new position of a #FpiByteReader instance to @pos in bytes. + * + * Returns: %TRUE if the position could be set successfully, %FALSE + * otherwise. + */ +gboolean +fpi_byte_reader_set_pos (FpiByteReader * reader, guint pos) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (pos > reader->size) + return FALSE; + + reader->byte = pos; + + return TRUE; +} + +/** + * fpi_byte_reader_get_pos: + * @reader: a #FpiByteReader instance + * + * Returns the current position of a #FpiByteReader instance in bytes. + * + * Returns: The current position of @reader in bytes. + */ +guint +fpi_byte_reader_get_pos (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_pos_inline (reader); +} + +/** + * fpi_byte_reader_get_remaining: + * @reader: a #FpiByteReader instance + * + * Returns the remaining number of bytes of a #FpiByteReader instance. + * + * Returns: The remaining number of bytes of @reader instance. + */ +guint +fpi_byte_reader_get_remaining (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_remaining_inline (reader); +} + +/** + * fpi_byte_reader_get_size: + * @reader: a #FpiByteReader instance + * + * Returns the total number of bytes of a #FpiByteReader instance. + * + * Returns: The total number of bytes of @reader instance. + */ +guint +fpi_byte_reader_get_size (const FpiByteReader * reader) +{ + return fpi_byte_reader_get_size_inline (reader); +} + +#define fpi_byte_reader_get_remaining fpi_byte_reader_get_remaining_inline +#define fpi_byte_reader_get_size fpi_byte_reader_get_size_inline + +/** + * fpi_byte_reader_skip: + * @reader: a #FpiByteReader instance + * @nbytes: the number of bytes to skip + * + * Skips @nbytes bytes of the #FpiByteReader instance. + * + * Returns: %TRUE if @nbytes bytes could be skipped, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_skip (FpiByteReader * reader, guint nbytes) +{ + return fpi_byte_reader_skip_inline (reader, nbytes); +} + +/** + * fpi_byte_reader_get_uint8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint8 to store the result + * + * Read an unsigned 8 bit integer into @val and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint8 to store the result + * + * Read a signed 8 bit integer into @val and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint8 to store the result + * + * Read an unsigned 8 bit integer into @val but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int8: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint8 to store the result + * + * Read a signed 8 bit integer into @val but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int16_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint16 to store the result + * + * Read an unsigned 16 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int16_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint16 to store the result + * + * Read a signed 16 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int24_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 24 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int24_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 24 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + + +/** + * fpi_byte_reader_get_uint32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint32 to store the result + * + * Read an unsigned 32 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint32 to store the result + * + * Read a signed 32 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit little endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit little endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_uint64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_int64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit big endian integer into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_uint64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #guint64 to store the result + * + * Read an unsigned 64 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_int64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gint64 to store the result + * + * Read a signed 64 bit big endian integer into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +#define FPI_BYTE_READER_PEEK_GET(bits,type,name) \ +gboolean \ +fpi_byte_reader_get_##name (FpiByteReader * reader, type * val) \ +{ \ + return fpi_byte_reader_get_##name##_inline (reader, val); \ +} \ +\ +gboolean \ +fpi_byte_reader_peek_##name (const FpiByteReader * reader, type * val) \ +{ \ + return fpi_byte_reader_peek_##name##_inline (reader, val); \ +} + +/* *INDENT-OFF* */ + +FPI_BYTE_READER_PEEK_GET(8,guint8,uint8) +FPI_BYTE_READER_PEEK_GET(8,gint8,int8) + +FPI_BYTE_READER_PEEK_GET(16,guint16,uint16_le) +FPI_BYTE_READER_PEEK_GET(16,guint16,uint16_be) +FPI_BYTE_READER_PEEK_GET(16,gint16,int16_le) +FPI_BYTE_READER_PEEK_GET(16,gint16,int16_be) + +FPI_BYTE_READER_PEEK_GET(24,guint32,uint24_le) +FPI_BYTE_READER_PEEK_GET(24,guint32,uint24_be) +FPI_BYTE_READER_PEEK_GET(24,gint32,int24_le) +FPI_BYTE_READER_PEEK_GET(24,gint32,int24_be) + +FPI_BYTE_READER_PEEK_GET(32,guint32,uint32_le) +FPI_BYTE_READER_PEEK_GET(32,guint32,uint32_be) +FPI_BYTE_READER_PEEK_GET(32,gint32,int32_le) +FPI_BYTE_READER_PEEK_GET(32,gint32,int32_be) + +FPI_BYTE_READER_PEEK_GET(64,guint64,uint64_le) +FPI_BYTE_READER_PEEK_GET(64,guint64,uint64_be) +FPI_BYTE_READER_PEEK_GET(64,gint64,int64_le) +FPI_BYTE_READER_PEEK_GET(64,gint64,int64_be) + +/** + * fpi_byte_reader_get_float32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit little endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float32_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit little endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit big endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float32_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gfloat to store the result + * + * Read a 32 bit big endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit little endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float64_le: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit little endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_get_float64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit big endian floating point value into @val + * and update the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +/** + * fpi_byte_reader_peek_float64_be: + * @reader: a #FpiByteReader instance + * @val: (out): Pointer to a #gdouble to store the result + * + * Read a 64 bit big endian floating point value into @val + * but keep the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ + +FPI_BYTE_READER_PEEK_GET(32,gfloat,float32_le) +FPI_BYTE_READER_PEEK_GET(32,gfloat,float32_be) +FPI_BYTE_READER_PEEK_GET(64,gdouble,float64_le) +FPI_BYTE_READER_PEEK_GET(64,gdouble,float64_be) + +/* *INDENT-ON* */ + +/** + * fpi_byte_reader_get_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer none) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Returns a constant pointer to the current data + * position if at least @size bytes are left and + * updates the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_get_data (FpiByteReader * reader, guint size, + const guint8 ** val) +{ + return fpi_byte_reader_get_data_inline (reader, size, val); +} + +/** + * fpi_byte_reader_peek_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer none) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Returns a constant pointer to the current data + * position if at least @size bytes are left and + * keeps the current position. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, + const guint8 ** val) +{ + return fpi_byte_reader_peek_data_inline (reader, size, val); +} + +/** + * fpi_byte_reader_dup_data: + * @reader: a #FpiByteReader instance + * @size: Size in bytes + * @val: (out) (transfer full) (array length=size): address of a + * #guint8 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data + * position if at least @size bytes are left and + * updates the current position. Free with g_free() when no longer needed. + * + * Returns: %TRUE if successful, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_dup_data (FpiByteReader * reader, guint size, guint8 ** val) +{ + return fpi_byte_reader_dup_data_inline (reader, size, val); +} + +/* Special optimized scan for mask 0xffffff00 and pattern 0x00000100 */ +static inline gint +_scan_for_start_code (const guint8 * data, guint size) +{ + guint8 *pdata = (guint8 *) data; + guint8 *pend = (guint8 *) (data + size - 4); + + while (pdata <= pend) { + if (pdata[2] > 1) { + pdata += 3; + } else if (pdata[1]) { + pdata += 2; + } else if (pdata[0] || pdata[2] != 1) { + pdata++; + } else { + return (pdata - data); + } + } + + /* nothing found */ + return -1; +} + +static inline guint +_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value) +{ + const guint8 *data; + guint32 state; + guint i; + + g_return_val_if_fail (size > 0, -1); + g_return_val_if_fail ((guint64) offset + size <= reader->size - reader->byte, + -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; + + /* Handle special case found in MPEG and H264 */ + if ((pattern == 0x00000100) && (mask == 0xffffff00)) { + gint ret = _scan_for_start_code (data, size); + + if (ret == -1) + return ret; + + if (value != NULL) + *value = (1 << 8) | data[ret + 3]; + + return ret + 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)) { + if (value) + *value = state; + return offset + i - 3; + } + } + } + + /* nothing found */ + return -1; +} + + +/** + * fpi_byte_reader_masked_scan_uint32: + * @reader: a #FpiByteReader + * @mask: mask to apply to data before matching against @pattern + * @pattern: pattern to match (after mask is applied) + * @offset: offset from which to start scanning, relative to the current + * position + * @size: number of bytes to scan from offset + * + * Scan for pattern @pattern with applied mask @mask in the byte reader data, + * starting from offset @offset relative to the current position. + * + * 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 + * byte reader data 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: + * |[ + * // Assume the reader contains 0x00 0x01 0x02 ... 0xfe 0xff + * + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x00010203, 0, 256); + * // -> returns 0 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x00010203, 1, 255); + * // -> returns -1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffffffff, 0x01020304, 1, 255); + * // -> returns 1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff, 0x0001, 0, 256); + * // -> returns -1 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff, 0x0203, 0, 256); + * // -> returns 0 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff0000, 0x02030000, 0, 256); + * // -> returns 2 + * fpi_byte_reader_masked_scan_uint32 (reader, 0xffff0000, 0x02030000, 0, 4); + * // -> returns -1 + * ]| + */ +guint +fpi_byte_reader_masked_scan_uint32 (const FpiByteReader * reader, guint32 mask, + guint32 pattern, guint offset, guint size) +{ + return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, NULL); +} + +/** + * fpi_byte_reader_masked_scan_uint32_peek: + * @reader: a #FpiByteReader + * @mask: mask to apply to data before matching against @pattern + * @pattern: pattern to match (after mask is applied) + * @offset: offset from which to start scanning, relative to the current + * position + * @size: number of bytes to scan from offset + * @value: (out): pointer to uint32 to return matching data + * + * Scan for pattern @pattern with applied mask @mask in the byte reader data, + * starting from offset @offset relative to the current position. + * + * 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 + * byte reader data 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. + * + * Since: 1.6 + */ +guint +fpi_byte_reader_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, guint32 pattern, guint offset, guint size, guint32 * value) +{ + return _masked_scan_uint32_peek (reader, mask, pattern, offset, size, value); +} + +#define FPI_BYTE_READER_SCAN_STRING(bits) \ +static guint \ +fpi_byte_reader_scan_string_utf##bits (const FpiByteReader * reader) \ +{ \ + guint len, off, max_len; \ + \ + max_len = (reader->size - reader->byte) / sizeof (guint##bits); \ + \ + /* need at least a single NUL terminator */ \ + if (max_len < 1) \ + return 0; \ + \ + len = 0; \ + off = reader->byte; \ + /* endianness does not matter if we are looking for a NUL terminator */ \ + while (FP_READ_UINT##bits##_LE (&reader->data[off]) != 0) { \ + ++len; \ + off += sizeof (guint##bits); \ + /* have we reached the end without finding a NUL terminator? */ \ + if (len == max_len) \ + return 0; \ + } \ + /* return size in bytes including the NUL terminator (hence the +1) */ \ + return (len + 1) * sizeof (guint##bits); \ +} + +#define FP_READ_UINT8_LE FP_READ_UINT8 +FPI_BYTE_READER_SCAN_STRING (8); +#undef FP_READ_UINT8_LE +FPI_BYTE_READER_SCAN_STRING (16); +FPI_BYTE_READER_SCAN_STRING (32); + +#define FPI_BYTE_READER_SKIP_STRING(bits) \ +gboolean \ +fpi_byte_reader_skip_string_utf##bits (FpiByteReader * reader) \ +{ \ + guint size; /* size in bytes including the terminator */ \ + \ + g_return_val_if_fail (reader != NULL, FALSE); \ + \ + size = fpi_byte_reader_scan_string_utf##bits (reader); \ + reader->byte += size; \ + return (size > 0); \ +} + +/** + * fpi_byte_reader_skip_string: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated string in the #FpiByteReader instance, advancing + * the current position to the byte after the string. This will work for + * any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +/** + * fpi_byte_reader_skip_string_utf8: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated string in the #FpiByteReader instance, advancing + * the current position to the byte after the string. This will work for + * any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (8); + +/** + * fpi_byte_reader_skip_string_utf16: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated UTF-16 string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. + * + * No input checking for valid UTF-16 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (16); + +/** + * fpi_byte_reader_skip_string_utf32: + * @reader: a #FpiByteReader instance + * + * Skips a NUL-terminated UTF-32 string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. + * + * No input checking for valid UTF-32 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +FPI_BYTE_READER_SKIP_STRING (32); + +/** + * fpi_byte_reader_peek_string: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator). + * The current position will be maintained. This will work for any + * NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +/** + * fpi_byte_reader_peek_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator). + * The current position will be maintained. This will work for any + * NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be skipped, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_peek_string_utf8 (const FpiByteReader * reader, + const gchar ** str) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + if (fpi_byte_reader_scan_string_utf8 (reader) > 0) { + *str = (const gchar *) (reader->data + reader->byte); + } else { + *str = NULL; + } + return (*str != NULL); +} + +/** + * fpi_byte_reader_get_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer none) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Returns a constant pointer to the current data position if there is + * a NUL-terminated string in the data (this could be just a NUL terminator), + * advancing the current position to the byte after the string. This will work + * for any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. + * + * No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be found, %FALSE otherwise. + */ +gboolean +fpi_byte_reader_get_string_utf8 (FpiByteReader * reader, const gchar ** str) +{ + guint size; /* size in bytes including the terminator */ + + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (str != NULL, FALSE); + + size = fpi_byte_reader_scan_string_utf8 (reader); + if (size == 0) { + *str = NULL; + return FALSE; + } + + *str = (const gchar *) (reader->data + reader->byte); + reader->byte += size; + return TRUE; +} + +#define FPI_BYTE_READER_DUP_STRING(bits,type) \ +gboolean \ +fpi_byte_reader_dup_string_utf##bits (FpiByteReader * reader, type ** str) \ +{ \ + guint size; /* size in bytes including the terminator */ \ + \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (str != NULL, FALSE); \ + \ + size = fpi_byte_reader_scan_string_utf##bits (reader); \ + if (size == 0) { \ + *str = NULL; \ + return FALSE; \ + } \ + *str = g_memdup (reader->data + reader->byte, size); \ + reader->byte += size; \ + return TRUE; \ +} + +/** + * fpi_byte_reader_dup_string_utf8: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #gchar pointer variable in which to store the result + * + * Free-function: g_free + * + * FIXME:Reads (copies) a NUL-terminated string in the #FpiByteReader instance, + * advancing the current position to the byte after the string. This will work + * for any NUL-terminated string with a character width of 8 bits, so ASCII, + * UTF-8, ISO-8859-N etc. No input checking for valid UTF-8 is done. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Returns: %TRUE if a string could be read into @str, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (8, gchar); + +/** + * fpi_byte_reader_dup_string_utf16: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #guint16 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data position if there is + * a NUL-terminated UTF-16 string in the data (this could be an empty string + * as well), and advances the current position. + * + * No input checking for valid UTF-16 is done. This function is endianness + * agnostic - you should not assume the UTF-16 characters are in host + * endianness. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Note: there is no peek or get variant of this function to ensure correct + * byte alignment of the UTF-16 string. + * + * Returns: %TRUE if a string could be read, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (16, guint16); + +/** + * fpi_byte_reader_dup_string_utf32: + * @reader: a #FpiByteReader instance + * @str: (out) (transfer full) (array zero-terminated=1): address of a + * #guint32 pointer variable in which to store the result + * + * Free-function: g_free + * + * Returns a newly-allocated copy of the current data position if there is + * a NUL-terminated UTF-32 string in the data (this could be an empty string + * as well), and advances the current position. + * + * No input checking for valid UTF-32 is done. This function is endianness + * agnostic - you should not assume the UTF-32 characters are in host + * endianness. + * + * This function will fail if no NUL-terminator was found in in the data. + * + * Note: there is no peek or get variant of this function to ensure correct + * byte alignment of the UTF-32 string. + * + * Returns: %TRUE if a string could be read, %FALSE otherwise. The + * string put into @str must be freed with g_free() when no longer needed. + */ +FPI_BYTE_READER_DUP_STRING (32, guint32); diff --git a/libfprint/fpi-byte-reader.h b/libfprint/fpi-byte-reader.h new file mode 100644 index 0000000..0a661c6 --- /dev/null +++ b/libfprint/fpi-byte-reader.h @@ -0,0 +1,680 @@ +/* GStreamer byte reader + * + * Copyright (C) 2008 Sebastian Dröge . + * Copyright (C) 2009 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FPI_BYTE_READER_H__ +#define __FPI_BYTE_READER_H__ + +#include +#include "fpi-byte-utils.h" + +G_BEGIN_DECLS + +#define FPI_BYTE_READER(reader) ((FpiByteReader *) (reader)) + +/** + * FpiByteReader: + * @data: (array length=size): Data from which the bit reader will + * read + * @size: Size of @data in bytes + * @byte: Current byte position + * + * A byte reader instance. + */ +typedef struct { + const guint8 *data; + guint size; + + guint byte; /* Byte position */ + + /* < private > */ +} FpiByteReader; + + +FpiByteReader * fpi_byte_reader_new (const guint8 *data, guint size) G_GNUC_MALLOC; + + +void fpi_byte_reader_free (FpiByteReader *reader); + + +void fpi_byte_reader_init (FpiByteReader *reader, const guint8 *data, guint size); + + +gboolean fpi_byte_reader_peek_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, + guint size); + +gboolean fpi_byte_reader_get_sub_reader (FpiByteReader * reader, + FpiByteReader * sub_reader, + guint size); + +gboolean fpi_byte_reader_set_pos (FpiByteReader *reader, guint pos); + + +guint fpi_byte_reader_get_pos (const FpiByteReader *reader); + + +guint fpi_byte_reader_get_remaining (const FpiByteReader *reader); + + +guint fpi_byte_reader_get_size (const FpiByteReader *reader); + + +gboolean fpi_byte_reader_skip (FpiByteReader *reader, guint nbytes); + + +gboolean fpi_byte_reader_get_uint8 (FpiByteReader *reader, guint8 *val); + + +gboolean fpi_byte_reader_get_int8 (FpiByteReader *reader, gint8 *val); + + +gboolean fpi_byte_reader_get_uint16_le (FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_get_int16_le (FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_get_uint16_be (FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_get_int16_be (FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_get_uint24_le (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int24_le (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint24_be (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int24_be (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint32_le (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int32_le (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint32_be (FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_get_int32_be (FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_get_uint64_le (FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_get_int64_le (FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_get_uint64_be (FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_get_int64_be (FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_peek_uint8 (const FpiByteReader *reader, guint8 *val); + + +gboolean fpi_byte_reader_peek_int8 (const FpiByteReader *reader, gint8 *val); + + +gboolean fpi_byte_reader_peek_uint16_le (const FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_peek_int16_le (const FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_peek_uint16_be (const FpiByteReader *reader, guint16 *val); + + +gboolean fpi_byte_reader_peek_int16_be (const FpiByteReader *reader, gint16 *val); + + +gboolean fpi_byte_reader_peek_uint24_le (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int24_le (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint24_be (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int24_be (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint32_le (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int32_le (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint32_be (const FpiByteReader *reader, guint32 *val); + + +gboolean fpi_byte_reader_peek_int32_be (const FpiByteReader *reader, gint32 *val); + + +gboolean fpi_byte_reader_peek_uint64_le (const FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_peek_int64_le (const FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_peek_uint64_be (const FpiByteReader *reader, guint64 *val); + + +gboolean fpi_byte_reader_peek_int64_be (const FpiByteReader *reader, gint64 *val); + + +gboolean fpi_byte_reader_get_float32_le (FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_get_float32_be (FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_get_float64_le (FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_get_float64_be (FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_peek_float32_le (const FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_peek_float32_be (const FpiByteReader *reader, gfloat *val); + + +gboolean fpi_byte_reader_peek_float64_le (const FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_peek_float64_be (const FpiByteReader *reader, gdouble *val); + + +gboolean fpi_byte_reader_dup_data (FpiByteReader * reader, guint size, guint8 ** val); + + +gboolean fpi_byte_reader_get_data (FpiByteReader * reader, guint size, const guint8 ** val); + + +gboolean fpi_byte_reader_peek_data (const FpiByteReader * reader, guint size, const guint8 ** val); + +#define fpi_byte_reader_dup_string(reader,str) \ + fpi_byte_reader_dup_string_utf8(reader,str) + + +gboolean fpi_byte_reader_dup_string_utf8 (FpiByteReader * reader, gchar ** str); + + +gboolean fpi_byte_reader_dup_string_utf16 (FpiByteReader * reader, guint16 ** str); + + +gboolean fpi_byte_reader_dup_string_utf32 (FpiByteReader * reader, guint32 ** str); + +#define fpi_byte_reader_skip_string(reader) \ + fpi_byte_reader_skip_string_utf8(reader) + + +gboolean fpi_byte_reader_skip_string_utf8 (FpiByteReader * reader); + + +gboolean fpi_byte_reader_skip_string_utf16 (FpiByteReader * reader); + + +gboolean fpi_byte_reader_skip_string_utf32 (FpiByteReader * reader); + +#define fpi_byte_reader_get_string(reader,str) \ + fpi_byte_reader_get_string_utf8(reader,str) + +#define fpi_byte_reader_peek_string(reader,str) \ + fpi_byte_reader_peek_string_utf8(reader,str) + + +gboolean fpi_byte_reader_get_string_utf8 (FpiByteReader * reader, const gchar ** str); + + +gboolean fpi_byte_reader_peek_string_utf8 (const FpiByteReader * reader, const gchar ** str); + + +guint fpi_byte_reader_masked_scan_uint32 (const FpiByteReader * reader, + guint32 mask, + guint32 pattern, + guint offset, + guint size); + +guint fpi_byte_reader_masked_scan_uint32_peek (const FpiByteReader * reader, + guint32 mask, + guint32 pattern, + guint offset, + guint size, + guint32 * value); + +/** + * FPI_BYTE_READER_INIT: + * @data: Data from which the #FpiByteReader should read + * @size: Size of @data in bytes + * + * A #FpiByteReader must be initialized with this macro, before it can be + * used. This macro can used be to initialize a variable, but it cannot + * be assigned to a variable. In that case you have to use + * fpi_byte_reader_init(). + */ +#define FPI_BYTE_READER_INIT(data, size) {data, size, 0} + +/* unchecked variants */ +static inline void +fpi_byte_reader_skip_unchecked (FpiByteReader * reader, guint nbytes) +{ + reader->byte += nbytes; +} + +#define __FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(bits,type,lower,upper,adj) \ +\ +static inline type \ +fpi_byte_reader_peek_##lower##_unchecked (const FpiByteReader * reader) \ +{ \ + type val = (type) FP_READ_##upper (reader->data + reader->byte); \ + adj \ + return val; \ +} \ +\ +static inline type \ +fpi_byte_reader_get_##lower##_unchecked (FpiByteReader * reader) \ +{ \ + type val = fpi_byte_reader_peek_##lower##_unchecked (reader); \ + reader->byte += bits / 8; \ + return val; \ +} + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(8,guint8,uint8,UINT8,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(8,gint8,int8,UINT8,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,guint16,uint16_le,UINT16_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,guint16,uint16_be,UINT16_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,gint16,int16_le,UINT16_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(16,gint16,int16_be,UINT16_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,guint32,uint32_le,UINT32_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,guint32,uint32_be,UINT32_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gint32,int32_le,UINT32_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gint32,int32_be,UINT32_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,guint32,uint24_le,UINT24_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,guint32,uint24_be,UINT24_BE,/* */) + +/* fix up the sign for 24-bit signed ints stored in 32-bit signed ints */ +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,gint32,int24_le,UINT24_LE, + if (val & 0x00800000) val |= 0xff000000;) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(24,gint32,int24_be,UINT24_BE, + if (val & 0x00800000) val |= 0xff000000;) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,guint64,uint64_le,UINT64_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,guint64,uint64_be,UINT64_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gint64,int64_le,UINT64_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gint64,int64_be,UINT64_BE,/* */) + +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gfloat,float32_le,FLOAT_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(32,gfloat,float32_be,FLOAT_BE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gdouble,float64_le,DOUBLE_LE,/* */) +__FPI_BYTE_READER_GET_PEEK_BITS_UNCHECKED(64,gdouble,float64_be,DOUBLE_BE,/* */) + +#undef __GET_PEEK_BITS_UNCHECKED + +static inline const guint8 * +fpi_byte_reader_peek_data_unchecked (const FpiByteReader * reader) +{ + return (const guint8 *) (reader->data + reader->byte); +} + +static inline const guint8 * +fpi_byte_reader_get_data_unchecked (FpiByteReader * reader, guint size) +{ + const guint8 *data; + + data = fpi_byte_reader_peek_data_unchecked (reader); + fpi_byte_reader_skip_unchecked (reader, size); + return data; +} + +static inline guint8 * +fpi_byte_reader_dup_data_unchecked (FpiByteReader * reader, guint size) +{ + gconstpointer data = fpi_byte_reader_get_data_unchecked (reader, size); + return (guint8 *) g_memdup (data, size); +} + +/* Unchecked variants that should not be used */ +static inline guint +fpi_byte_reader_get_pos_unchecked (const FpiByteReader * reader) +{ + return reader->byte; +} + +static inline guint +fpi_byte_reader_get_remaining_unchecked (const FpiByteReader * reader) +{ + return reader->size - reader->byte; +} + +static inline guint +fpi_byte_reader_get_size_unchecked (const FpiByteReader * reader) +{ + return reader->size; +} + +/* inlined variants (do not use directly) */ + +static inline guint +fpi_byte_reader_get_remaining_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_remaining_unchecked (reader); +} + +static inline guint +fpi_byte_reader_get_size_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_size_unchecked (reader); +} + +#define __FPI_BYTE_READER_GET_PEEK_BITS_INLINE(bits,type,name) \ +\ +static inline gboolean \ +fpi_byte_reader_peek_##name##_inline (const FpiByteReader * reader, type * val) \ +{ \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (val != NULL, FALSE); \ + \ + if (fpi_byte_reader_get_remaining_unchecked (reader) < (bits / 8)) \ + return FALSE; \ +\ + *val = fpi_byte_reader_peek_##name##_unchecked (reader); \ + return TRUE; \ +} \ +\ +static inline gboolean \ +fpi_byte_reader_get_##name##_inline (FpiByteReader * reader, type * val) \ +{ \ + g_return_val_if_fail (reader != NULL, FALSE); \ + g_return_val_if_fail (val != NULL, FALSE); \ + \ + if (fpi_byte_reader_get_remaining_unchecked (reader) < (bits / 8)) \ + return FALSE; \ +\ + *val = fpi_byte_reader_get_##name##_unchecked (reader); \ + return TRUE; \ +} + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(8,guint8,uint8) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(8,gint8,int8) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,guint16,uint16_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,guint16,uint16_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,gint16,int16_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(16,gint16,int16_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,guint32,uint32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,guint32,uint32_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gint32,int32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gint32,int32_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,guint32,uint24_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,guint32,uint24_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,gint32,int24_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(24,gint32,int24_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,guint64,uint64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,guint64,uint64_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gint64,int64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gint64,int64_be) + +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gfloat,float32_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(32,gfloat,float32_be) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_le) +__FPI_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_be) + +#undef __FPI_BYTE_READER_GET_PEEK_BITS_INLINE + +#ifndef FPI_BYTE_READER_DISABLE_INLINES + +#define fpi_byte_reader_init(reader,data,size) \ + fpi_byte_reader_init_inline(reader,data,size) + +#define fpi_byte_reader_get_remaining(reader) \ + fpi_byte_reader_get_remaining_inline(reader) + +#define fpi_byte_reader_get_size(reader) \ + fpi_byte_reader_get_size_inline(reader) + +#define fpi_byte_reader_get_pos(reader) \ + fpi_byte_reader_get_pos_inline(reader) + +/* we use defines here so we can add the G_LIKELY() */ +#define fpi_byte_reader_get_uint8(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint8_inline(reader,val)) +#define fpi_byte_reader_get_int8(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int8_inline(reader,val)) +#define fpi_byte_reader_get_uint16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint16_le_inline(reader,val)) +#define fpi_byte_reader_get_int16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int16_le_inline(reader,val)) +#define fpi_byte_reader_get_uint16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint16_be_inline(reader,val)) +#define fpi_byte_reader_get_int16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int16_be_inline(reader,val)) +#define fpi_byte_reader_get_uint24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint24_le_inline(reader,val)) +#define fpi_byte_reader_get_int24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int24_le_inline(reader,val)) +#define fpi_byte_reader_get_uint24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint24_be_inline(reader,val)) +#define fpi_byte_reader_get_int24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int24_be_inline(reader,val)) +#define fpi_byte_reader_get_uint32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint32_le_inline(reader,val)) +#define fpi_byte_reader_get_int32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int32_le_inline(reader,val)) +#define fpi_byte_reader_get_uint32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint32_be_inline(reader,val)) +#define fpi_byte_reader_get_int32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int32_be_inline(reader,val)) +#define fpi_byte_reader_get_uint64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint64_le_inline(reader,val)) +#define fpi_byte_reader_get_int64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int64_le_inline(reader,val)) +#define fpi_byte_reader_get_uint64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_uint64_be_inline(reader,val)) +#define fpi_byte_reader_get_int64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_int64_be_inline(reader,val)) + +#define fpi_byte_reader_peek_uint8(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint8_inline(reader,val)) +#define fpi_byte_reader_peek_int8(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int8_inline(reader,val)) +#define fpi_byte_reader_peek_uint16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint16_le_inline(reader,val)) +#define fpi_byte_reader_peek_int16_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int16_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint16_be_inline(reader,val)) +#define fpi_byte_reader_peek_int16_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int16_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint24_le_inline(reader,val)) +#define fpi_byte_reader_peek_int24_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int24_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint24_be_inline(reader,val)) +#define fpi_byte_reader_peek_int24_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int24_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint32_le_inline(reader,val)) +#define fpi_byte_reader_peek_int32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int32_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint32_be_inline(reader,val)) +#define fpi_byte_reader_peek_int32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int32_be_inline(reader,val)) +#define fpi_byte_reader_peek_uint64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint64_le_inline(reader,val)) +#define fpi_byte_reader_peek_int64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int64_le_inline(reader,val)) +#define fpi_byte_reader_peek_uint64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_uint64_be_inline(reader,val)) +#define fpi_byte_reader_peek_int64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_int64_be_inline(reader,val)) + +#define fpi_byte_reader_get_float32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float32_le_inline(reader,val)) +#define fpi_byte_reader_get_float32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float32_be_inline(reader,val)) +#define fpi_byte_reader_get_float64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float64_le_inline(reader,val)) +#define fpi_byte_reader_get_float64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_get_float64_be_inline(reader,val)) +#define fpi_byte_reader_peek_float32_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float32_le_inline(reader,val)) +#define fpi_byte_reader_peek_float32_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float32_be_inline(reader,val)) +#define fpi_byte_reader_peek_float64_le(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float64_le_inline(reader,val)) +#define fpi_byte_reader_peek_float64_be(reader,val) \ + G_LIKELY(fpi_byte_reader_peek_float64_be_inline(reader,val)) + +#endif /* FPI_BYTE_READER_DISABLE_INLINES */ + +static inline void +fpi_byte_reader_init_inline (FpiByteReader * reader, const guint8 * data, guint size) +{ + g_return_if_fail (reader != NULL); + + reader->data = data; + reader->size = size; + reader->byte = 0; +} + +static inline gboolean +fpi_byte_reader_peek_sub_reader_inline (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (sub_reader != NULL, FALSE); + + if (fpi_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 +fpi_byte_reader_get_sub_reader_inline (FpiByteReader * reader, + FpiByteReader * sub_reader, guint size) +{ + if (!fpi_byte_reader_peek_sub_reader_inline (reader, sub_reader, size)) + return FALSE; + fpi_byte_reader_skip_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_dup_data_inline (FpiByteReader * reader, guint size, guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_dup_data_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_get_data_inline (FpiByteReader * reader, guint size, const guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_get_data_unchecked (reader, size); + return TRUE; +} + +static inline gboolean +fpi_byte_reader_peek_data_inline (const FpiByteReader * reader, guint size, const guint8 ** val) +{ + g_return_val_if_fail (reader != NULL, FALSE); + g_return_val_if_fail (val != NULL, FALSE); + + if (G_UNLIKELY (size > reader->size || fpi_byte_reader_get_remaining_unchecked (reader) < size)) + return FALSE; + + *val = fpi_byte_reader_peek_data_unchecked (reader); + return TRUE; +} + +static inline guint +fpi_byte_reader_get_pos_inline (const FpiByteReader * reader) +{ + g_return_val_if_fail (reader != NULL, 0); + + return fpi_byte_reader_get_pos_unchecked (reader); +} + +static inline gboolean +fpi_byte_reader_skip_inline (FpiByteReader * reader, guint nbytes) +{ + g_return_val_if_fail (reader != NULL, FALSE); + + if (G_UNLIKELY (fpi_byte_reader_get_remaining_unchecked (reader) < nbytes)) + return FALSE; + + reader->byte += nbytes; + return TRUE; +} + +#ifndef FPI_BYTE_READER_DISABLE_INLINES + +#define fpi_byte_reader_dup_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_dup_data_inline(reader,size,val)) +#define fpi_byte_reader_get_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_get_data_inline(reader,size,val)) +#define fpi_byte_reader_peek_data(reader,size,val) \ + G_LIKELY(fpi_byte_reader_peek_data_inline(reader,size,val)) +#define fpi_byte_reader_skip(reader,nbytes) \ + G_LIKELY(fpi_byte_reader_skip_inline(reader,nbytes)) + +#endif /* FPI_BYTE_READER_DISABLE_INLINES */ + +G_END_DECLS + +#endif /* __FPI_BYTE_READER_H__ */ diff --git a/libfprint/fpi-byte-utils.h b/libfprint/fpi-byte-utils.h new file mode 100644 index 0000000..8a99121 --- /dev/null +++ b/libfprint/fpi-byte-utils.h @@ -0,0 +1,488 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2002 Thomas Vander Stichele + * + * gstutils.h: Header for various utility functions + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __FP_UTILS_H__ +#define __FP_UTILS_H__ + +#include + +G_BEGIN_DECLS + +/* Define PUT and GET functions for unaligned memory */ +#define _FP_GET(__data, __idx, __size, __shift) \ + (((guint##__size) (((const guint8 *) (__data))[__idx])) << (__shift)) + +#define _FP_PUT(__data, __idx, __size, __shift, __num) \ + (((guint8 *) (__data))[__idx] = (((guint##__size) (__num)) >> (__shift)) & 0xff) + +#ifndef __GTK_DOC_IGNORE__ + +/** + * FP_READ_UINT64_BE: + * @data: memory location + * + * Read a 64 bit unsigned integer value in big endian format from the memory buffer. + */ + +/** + * FP_READ_UINT64_LE: + * @data: memory location + * + * Read a 64 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT64_BE(data) (_FP_GET (data, 0, 64, 56) | \ + _FP_GET (data, 1, 64, 48) | \ + _FP_GET (data, 2, 64, 40) | \ + _FP_GET (data, 3, 64, 32) | \ + _FP_GET (data, 4, 64, 24) | \ + _FP_GET (data, 5, 64, 16) | \ + _FP_GET (data, 6, 64, 8) | \ + _FP_GET (data, 7, 64, 0)) + +#define _FP_READ_UINT64_LE(data) (_FP_GET (data, 7, 64, 56) | \ + _FP_GET (data, 6, 64, 48) | \ + _FP_GET (data, 5, 64, 40) | \ + _FP_GET (data, 4, 64, 32) | \ + _FP_GET (data, 3, 64, 24) | \ + _FP_GET (data, 2, 64, 16) | \ + _FP_GET (data, 1, 64, 8) | \ + _FP_GET (data, 0, 64, 0)) + +#define FP_READ_UINT64_BE(data) _fpi_slow_read64_be((const guint8 *)(data)) +static inline guint64 _fpi_slow_read64_be (const guint8 * data) { + return _FP_READ_UINT64_BE (data); +} +#define FP_READ_UINT64_LE(data) _fpi_slow_read64_le((const guint8 *)(data)) +static inline guint64 _fpi_slow_read64_le (const guint8 * data) { + return _FP_READ_UINT64_LE (data); +} + +/** + * FP_READ_UINT32_BE: + * @data: memory location + * + * Read a 32 bit unsigned integer value in big endian format from the memory buffer. + */ + +/** + * FP_READ_UINT32_LE: + * @data: memory location + * + * Read a 32 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT32_BE(data) (_FP_GET (data, 0, 32, 24) | \ + _FP_GET (data, 1, 32, 16) | \ + _FP_GET (data, 2, 32, 8) | \ + _FP_GET (data, 3, 32, 0)) + +#define _FP_READ_UINT32_LE(data) (_FP_GET (data, 3, 32, 24) | \ + _FP_GET (data, 2, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 0, 32, 0)) + +#define FP_READ_UINT32_BE(data) _fpi_slow_read32_be((const guint8 *)(data)) +static inline guint32 _fpi_slow_read32_be (const guint8 * data) { + return _FP_READ_UINT32_BE (data); +} +#define FP_READ_UINT32_LE(data) _fpi_slow_read32_le((const guint8 *)(data)) +static inline guint32 _fpi_slow_read32_le (const guint8 * data) { + return _FP_READ_UINT32_LE (data); +} + +/** + * FP_READ_UINT24_BE: + * @data: memory location + * + * Read a 24 bit unsigned integer value in big endian format from the memory buffer. + */ +#define _FP_READ_UINT24_BE(data) (_FP_GET (data, 0, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 2, 32, 0)) + +#define FP_READ_UINT24_BE(data) _fpi_slow_read24_be((const guint8 *)(data)) +static inline guint32 _fpi_slow_read24_be (const guint8 * data) { + return _FP_READ_UINT24_BE (data); +} + +/** + * FP_READ_UINT24_LE: + * @data: memory location + * + * Read a 24 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT24_LE(data) (_FP_GET (data, 2, 32, 16) | \ + _FP_GET (data, 1, 32, 8) | \ + _FP_GET (data, 0, 32, 0)) + +#define FP_READ_UINT24_LE(data) _fpi_slow_read24_le((const guint8 *)(data)) +static inline guint32 _fpi_slow_read24_le (const guint8 * data) { + return _FP_READ_UINT24_LE (data); +} + +/** + * FP_READ_UINT16_BE: + * @data: memory location + * + * Read a 16 bit unsigned integer value in big endian format from the memory buffer. + */ +/** + * FP_READ_UINT16_LE: + * @data: memory location + * + * Read a 16 bit unsigned integer value in little endian format from the memory buffer. + */ +#define _FP_READ_UINT16_BE(data) (_FP_GET (data, 0, 16, 8) | \ + _FP_GET (data, 1, 16, 0)) + +#define _FP_READ_UINT16_LE(data) (_FP_GET (data, 1, 16, 8) | \ + _FP_GET (data, 0, 16, 0)) + +#define FP_READ_UINT16_BE(data) _fpi_slow_read16_be((const guint8 *)(data)) +static inline guint16 _fpi_slow_read16_be (const guint8 * data) { + return _FP_READ_UINT16_BE (data); +} +#define FP_READ_UINT16_LE(data) _fpi_slow_read16_le((const guint8 *)(data)) +static inline guint16 _fpi_slow_read16_le (const guint8 * data) { + return _FP_READ_UINT16_LE (data); +} + +/** + * FP_READ_UINT8: + * @data: memory location + * + * Read an 8 bit unsigned integer value from the memory buffer. + */ +#define FP_READ_UINT8(data) (_FP_GET (data, 0, 8, 0)) + +/** + * FP_WRITE_UINT64_BE: + * @data: memory location + * @val: value to store + * + * Store a 64 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT64_LE: + * @data: memory location + * @val: value to store + * + * Store a 64 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT64_BE(data,val) do { \ + gpointer __put_data = data; \ + guint64 __put_val = val; \ + _FP_PUT (__put_data, 0, 64, 56, __put_val); \ + _FP_PUT (__put_data, 1, 64, 48, __put_val); \ + _FP_PUT (__put_data, 2, 64, 40, __put_val); \ + _FP_PUT (__put_data, 3, 64, 32, __put_val); \ + _FP_PUT (__put_data, 4, 64, 24, __put_val); \ + _FP_PUT (__put_data, 5, 64, 16, __put_val); \ + _FP_PUT (__put_data, 6, 64, 8, __put_val); \ + _FP_PUT (__put_data, 7, 64, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT64_LE(data,val) do { \ + gpointer __put_data = data; \ + guint64 __put_val = val; \ + _FP_PUT (__put_data, 0, 64, 0, __put_val); \ + _FP_PUT (__put_data, 1, 64, 8, __put_val); \ + _FP_PUT (__put_data, 2, 64, 16, __put_val); \ + _FP_PUT (__put_data, 3, 64, 24, __put_val); \ + _FP_PUT (__put_data, 4, 64, 32, __put_val); \ + _FP_PUT (__put_data, 5, 64, 40, __put_val); \ + _FP_PUT (__put_data, 6, 64, 48, __put_val); \ + _FP_PUT (__put_data, 7, 64, 56, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT32_BE: + * @data: memory location + * @val: value to store + * + * Store a 32 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT32_LE: + * @data: memory location + * @val: value to store + * + * Store a 32 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT32_BE(data,val) do { \ + gpointer __put_data = data; \ + guint32 __put_val = val; \ + _FP_PUT (__put_data, 0, 32, 24, __put_val); \ + _FP_PUT (__put_data, 1, 32, 16, __put_val); \ + _FP_PUT (__put_data, 2, 32, 8, __put_val); \ + _FP_PUT (__put_data, 3, 32, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT32_LE(data,val) do { \ + gpointer __put_data = data; \ + guint32 __put_val = val; \ + _FP_PUT (__put_data, 0, 32, 0, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 16, __put_val); \ + _FP_PUT (__put_data, 3, 32, 24, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT24_BE: + * @data: memory location + * @num: value to store + * + * Store a 24 bit unsigned integer value in big endian format into the memory buffer. + */ +#define FP_WRITE_UINT24_BE(data, num) do { \ + gpointer __put_data = data; \ + guint32 __put_val = num; \ + _FP_PUT (__put_data, 0, 32, 16, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 0, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT24_LE: + * @data: memory location + * @num: value to store + * + * Store a 24 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT24_LE(data, num) do { \ + gpointer __put_data = data; \ + guint32 __put_val = num; \ + _FP_PUT (__put_data, 0, 32, 0, __put_val); \ + _FP_PUT (__put_data, 1, 32, 8, __put_val); \ + _FP_PUT (__put_data, 2, 32, 16, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT16_BE: + * @data: memory location + * @val: value to store + * + * Store a 16 bit unsigned integer value in big endian format into the memory buffer. + */ +/** + * FP_WRITE_UINT16_LE: + * @data: memory location + * @val: value to store + * + * Store a 16 bit unsigned integer value in little endian format into the memory buffer. + */ +#define FP_WRITE_UINT16_BE(data,val) do { \ + gpointer __put_data = data; \ + guint16 __put_val = val; \ + _FP_PUT (__put_data, 0, 16, 8, __put_val); \ + _FP_PUT (__put_data, 1, 16, 0, __put_val); \ + } while (0) + +#define FP_WRITE_UINT16_LE(data,val) do { \ + gpointer __put_data = data; \ + guint16 __put_val = val; \ + _FP_PUT (__put_data, 0, 16, 0, __put_val); \ + _FP_PUT (__put_data, 1, 16, 8, __put_val); \ + } while (0) + +/** + * FP_WRITE_UINT8: + * @data: memory location + * @num: value to store + * + * Store an 8 bit unsigned integer value into the memory buffer. + */ +#define FP_WRITE_UINT8(data, num) do { \ + _FP_PUT (data, 0, 8, 0, num); \ + } while (0) + +/* Float endianness conversion macros */ + +/** + * FP_READ_FLOAT_LE: + * @data: memory location + * + * Read a 32 bit float value in little endian format from the memory buffer. + * + * Returns: The floating point value read from @data + */ +static inline gfloat +FP_READ_FLOAT_LE(const guint8 *data) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.i = FP_READ_UINT32_LE (data); + return u.f; +} + +/** + * FP_READ_FLOAT_BE: + * @data: memory location + * + * Read a 32 bit float value in big endian format from the memory buffer. + * + * Returns: The floating point value read from @data + */ +static inline gfloat +FP_READ_FLOAT_BE(const guint8 *data) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.i = FP_READ_UINT32_BE (data); + return u.f; +} + +/** + * FP_READ_DOUBLE_LE: + * @data: memory location + * + * Read a 64 bit double value in little endian format from the memory buffer. + * + * Returns: The double-precision floating point value read from @data + */ +static inline gdouble +FP_READ_DOUBLE_LE(const guint8 *data) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.i = FP_READ_UINT64_LE (data); + return u.d; +} + +/** + * FP_READ_DOUBLE_BE: + * @data: memory location + * + * Read a 64 bit double value in big endian format from the memory buffer. + * + * Returns: The double-precision floating point value read from @data + */ +static inline gdouble +FP_READ_DOUBLE_BE(const guint8 *data) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.i = FP_READ_UINT64_BE (data); + return u.d; +} + +/** + * FP_WRITE_FLOAT_LE: + * @data: memory location + * @num: value to store + * + * Store a 32 bit float value in little endian format into the memory buffer. + */ +static inline void +FP_WRITE_FLOAT_LE(guint8 *data, gfloat num) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.f = num; + FP_WRITE_UINT32_LE (data, u.i); +} + +/** + * FP_WRITE_FLOAT_BE: + * @data: memory location + * @num: value to store + * + * Store a 32 bit float value in big endian format into the memory buffer. + */ +static inline void +FP_WRITE_FLOAT_BE(guint8 *data, gfloat num) +{ + union + { + guint32 i; + gfloat f; + } u; + + u.f = num; + FP_WRITE_UINT32_BE (data, u.i); +} + +/** + * FP_WRITE_DOUBLE_LE: + * @data: memory location + * @num: value to store + * + * Store a 64 bit double value in little endian format into the memory buffer. + */ +static inline void +FP_WRITE_DOUBLE_LE(guint8 *data, gdouble num) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.d = num; + FP_WRITE_UINT64_LE (data, u.i); +} + +/** + * FP_WRITE_DOUBLE_BE: + * @data: memory location + * @num: value to store + * + * Store a 64 bit double value in big endian format into the memory buffer. + */ +static inline void +FP_WRITE_DOUBLE_BE(guint8 *data, gdouble num) +{ + union + { + guint64 i; + gdouble d; + } u; + + u.d = num; + FP_WRITE_UINT64_BE (data, u.i); +} + +G_END_DECLS + +#endif /* __GTK_DOC_IGNORE__ */ +#endif /* __FP_UTILS_H__ */ diff --git a/libfprint/fpi-byte-writer.c b/libfprint/fpi-byte-writer.c new file mode 100644 index 0000000..4ee67ff --- /dev/null +++ b/libfprint/fpi-byte-writer.c @@ -0,0 +1,614 @@ +/* GStreamer byte writer + * + * Copyright (C) 2009 Sebastian Dröge . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define FPI_BYTE_WRITER_DISABLE_INLINES +#include "fpi-byte-writer.h" + +/** + * SECTION:fpi-byte-writer + * @title: FpiByteWriter + * @short_description: Writes different integer, string and floating point + * types to a memory buffer and allows reading + * + * #FpiByteWriter provides a byte writer and reader that can write/read different + * integer and floating point types to/from a memory buffer. It provides functions + * for writing/reading signed/unsigned, little/big endian integers of 8, 16, 24, + * 32 and 64 bits and functions for reading little/big endian floating points numbers of + * 32 and 64 bits. It also provides functions to write/read NUL-terminated strings + * in various character encodings. + */ + +/** + * fpi_byte_writer_new: (skip) + * + * Creates a new, empty #FpiByteWriter instance + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new, empty #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new (void) +{ + FpiByteWriter *ret = g_slice_new0 (FpiByteWriter); + + ret->owned = TRUE; + return ret; +} + +/** + * fpi_byte_writer_new_with_size: (skip) + * @size: Initial size of data + * @fixed: If %TRUE the data can't be reallocated + * + * Creates a new #FpiByteWriter instance with the given + * initial data size. + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new_with_size (guint size, gboolean fixed) +{ + FpiByteWriter *ret = fpi_byte_writer_new (); + + ret->alloc_size = size; + ret->parent.data = g_malloc (ret->alloc_size); + ret->fixed = fixed; + ret->owned = TRUE; + + return ret; +} + +/** + * fpi_byte_writer_new_with_data: (skip) + * @data: Memory area for writing + * @size: Size of @data in bytes + * @initialized: If %TRUE the complete data can be read from the beginning + * + * Creates a new #FpiByteWriter instance with the given + * memory area. If @initialized is %TRUE it is possible to + * read @size bytes from the #FpiByteWriter from the beginning. + * + * Free-function: fpi_byte_writer_free + * + * Returns: (transfer full): a new #FpiByteWriter instance + */ +FpiByteWriter * +fpi_byte_writer_new_with_data (guint8 * data, guint size, gboolean initialized) +{ + FpiByteWriter *ret = fpi_byte_writer_new (); + + ret->parent.data = data; + ret->parent.size = (initialized) ? size : 0; + ret->alloc_size = size; + ret->fixed = TRUE; + ret->owned = FALSE; + + return ret; +} + +/** + * fpi_byte_writer_init: + * @writer: #FpiByteWriter instance + * + * Initializes @writer to an empty instance + */ +void +fpi_byte_writer_init (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + memset (writer, 0, sizeof (FpiByteWriter)); + + writer->owned = TRUE; +} + +/** + * fpi_byte_writer_init_with_size: + * @writer: #FpiByteWriter instance + * @size: Initial size of data + * @fixed: If %TRUE the data can't be reallocated + * + * Initializes @writer with the given initial data size. + */ +void +fpi_byte_writer_init_with_size (FpiByteWriter * writer, guint size, + gboolean fixed) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_init (writer); + + writer->parent.data = g_malloc (size); + writer->alloc_size = size; + writer->fixed = fixed; + writer->owned = TRUE; +} + +/** + * fpi_byte_writer_init_with_data: + * @writer: #FpiByteWriter instance + * @data: (array length=size) (transfer none): Memory area for writing + * @size: Size of @data in bytes + * @initialized: If %TRUE the complete data can be read from the beginning + * + * Initializes @writer with the given + * memory area. If @initialized is %TRUE it is possible to + * read @size bytes from the #FpiByteWriter from the beginning. + */ +void +fpi_byte_writer_init_with_data (FpiByteWriter * writer, guint8 * data, + guint size, gboolean initialized) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_init (writer); + + writer->parent.data = data; + writer->parent.size = (initialized) ? size : 0; + writer->alloc_size = size; + writer->fixed = TRUE; + writer->owned = FALSE; +} + +/** + * fpi_byte_writer_reset: + * @writer: #FpiByteWriter instance + * + * Resets @writer and frees the data if it's + * owned by @writer. + */ +void +fpi_byte_writer_reset (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + if (writer->owned) + g_free ((guint8 *) writer->parent.data); + memset (writer, 0, sizeof (FpiByteWriter)); +} + +/** + * fpi_byte_writer_reset_and_get_data: + * @writer: #FpiByteWriter instance + * + * Resets @writer and returns the current data. + * + * Free-function: g_free + * + * Returns: (array) (transfer full): the current data. g_free() after + * usage. + */ +guint8 * +fpi_byte_writer_reset_and_get_data (FpiByteWriter * writer) +{ + guint8 *data; + + g_return_val_if_fail (writer != NULL, NULL); + + data = (guint8 *) writer->parent.data; + if (!writer->owned) + data = g_memdup (data, writer->parent.size); + writer->parent.data = NULL; + fpi_byte_writer_reset (writer); + + return data; +} + +/** + * fpi_byte_writer_free: + * @writer: (in) (transfer full): #FpiByteWriter instance + * + * Frees @writer and all memory allocated by it. + */ +void +fpi_byte_writer_free (FpiByteWriter * writer) +{ + g_return_if_fail (writer != NULL); + + fpi_byte_writer_reset (writer); + g_slice_free (FpiByteWriter, writer); +} + +/** + * fpi_byte_writer_free_and_get_data: + * @writer: (in) (transfer full): #FpiByteWriter instance + * + * Frees @writer and all memory allocated by it except + * the current data, which is returned. + * + * Free-function: g_free + * + * Returns: (transfer full): the current data. g_free() after usage. + */ +guint8 * +fpi_byte_writer_free_and_get_data (FpiByteWriter * writer) +{ + guint8 *data; + + g_return_val_if_fail (writer != NULL, NULL); + + data = fpi_byte_writer_reset_and_get_data (writer); + g_slice_free (FpiByteWriter, writer); + + return data; +} + +/** + * fpi_byte_writer_get_remaining: + * @writer: #FpiByteWriter instance + * + * Returns the remaining size of data that can still be written. If + * -1 is returned the remaining size is only limited by system resources. + * + * Returns: the remaining size of data that can still be written + */ +guint +fpi_byte_writer_get_remaining (const FpiByteWriter * writer) +{ + g_return_val_if_fail (writer != NULL, -1); + + if (!writer->fixed) + return -1; + else + return writer->alloc_size - writer->parent.byte; +} + +/** + * fpi_byte_writer_ensure_free_space: + * @writer: #FpiByteWriter instance + * @size: Number of bytes that should be available + * + * Checks if enough free space from the current write cursor is + * available and reallocates if necessary. + * + * Returns: %TRUE if at least @size bytes are still available + */ +gboolean +fpi_byte_writer_ensure_free_space (FpiByteWriter * writer, guint size) +{ + return fpi_byte_writer_ensure_free_space_inline (writer, size); +} + + +#define CREATE_WRITE_FUNC(bits,type,name,write_func) \ +gboolean \ +fpi_byte_writer_put_##name (FpiByteWriter *writer, type val) \ +{ \ + return fpi_byte_writer_put_##name##_inline (writer, val); \ +} + +CREATE_WRITE_FUNC (8, guint8, uint8, GST_WRITE_UINT8); +CREATE_WRITE_FUNC (8, gint8, int8, GST_WRITE_UINT8); +CREATE_WRITE_FUNC (16, guint16, uint16_le, GST_WRITE_UINT16_LE); +CREATE_WRITE_FUNC (16, guint16, uint16_be, GST_WRITE_UINT16_BE); +CREATE_WRITE_FUNC (16, gint16, int16_le, GST_WRITE_UINT16_LE); +CREATE_WRITE_FUNC (16, gint16, int16_be, GST_WRITE_UINT16_BE); +CREATE_WRITE_FUNC (24, guint32, uint24_le, GST_WRITE_UINT24_LE); +CREATE_WRITE_FUNC (24, guint32, uint24_be, GST_WRITE_UINT24_BE); +CREATE_WRITE_FUNC (24, gint32, int24_le, GST_WRITE_UINT24_LE); +CREATE_WRITE_FUNC (24, gint32, int24_be, GST_WRITE_UINT24_BE); +CREATE_WRITE_FUNC (32, guint32, uint32_le, GST_WRITE_UINT32_LE); +CREATE_WRITE_FUNC (32, guint32, uint32_be, GST_WRITE_UINT32_BE); +CREATE_WRITE_FUNC (32, gint32, int32_le, GST_WRITE_UINT32_LE); +CREATE_WRITE_FUNC (32, gint32, int32_be, GST_WRITE_UINT32_BE); +CREATE_WRITE_FUNC (64, guint64, uint64_le, GST_WRITE_UINT64_LE); +CREATE_WRITE_FUNC (64, guint64, uint64_be, GST_WRITE_UINT64_BE); +CREATE_WRITE_FUNC (64, gint64, int64_le, GST_WRITE_UINT64_LE); +CREATE_WRITE_FUNC (64, gint64, int64_be, GST_WRITE_UINT64_BE); + +CREATE_WRITE_FUNC (32, gfloat, float32_be, GST_WRITE_FLOAT_BE); +CREATE_WRITE_FUNC (32, gfloat, float32_le, GST_WRITE_FLOAT_LE); +CREATE_WRITE_FUNC (64, gdouble, float64_be, GST_WRITE_DOUBLE_BE); +CREATE_WRITE_FUNC (64, gdouble, float64_le, GST_WRITE_DOUBLE_LE); + +gboolean +fpi_byte_writer_put_data (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + return fpi_byte_writer_put_data_inline (writer, data, size); +} + +gboolean +fpi_byte_writer_fill (FpiByteWriter * writer, guint8 value, guint size) +{ + return fpi_byte_writer_fill_inline (writer, value, size); +} + +#define CREATE_WRITE_STRING_FUNC(bits,type) \ +gboolean \ +fpi_byte_writer_put_string_utf##bits (FpiByteWriter *writer, const type * data) \ +{ \ + guint size = 0; \ + \ + g_return_val_if_fail (writer != NULL, FALSE); \ + \ + /* endianness does not matter if we are looking for a NUL terminator */ \ + while (data[size] != 0) { \ + /* have prevent overflow */ \ + if (G_UNLIKELY (size == G_MAXUINT)) \ + return FALSE; \ + ++size; \ + } \ + ++size; \ + \ + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline(writer, size * (bits / 8)))) \ + return FALSE; \ + \ + fpi_byte_writer_put_data_inline (writer, (const guint8 *) data, size * (bits / 8)); \ + \ + return TRUE; \ +} + +CREATE_WRITE_STRING_FUNC (8, gchar); +CREATE_WRITE_STRING_FUNC (16, guint16); +CREATE_WRITE_STRING_FUNC (32, guint32); +/** + * fpi_byte_writer_put_uint8: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned 8 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint16_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint24_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned big endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint16_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint24_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_uint64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a unsigned little endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int8: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed 8 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int16_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int24_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed big endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int16_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 16 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int24_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 24 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 32 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_int64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a signed little endian 64 bit integer to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float32_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a big endian 32 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float64_be: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a big endian 64 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float32_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a little endian 32 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_float64_le: + * @writer: #FpiByteWriter instance + * @val: Value to write + * + * Writes a little endian 64 bit float to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf8: + * @writer: #FpiByteWriter instance + * @data: (transfer none): UTF8 string to write + * + * Writes a NUL-terminated UTF8 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf16: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array zero-terminated=1): UTF16 string to write + * + * Writes a NUL-terminated UTF16 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_string_utf32: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array zero-terminated=1): UTF32 string to write + * + * Writes a NUL-terminated UTF32 string to @writer (including the terminator). + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_put_data: + * @writer: #FpiByteWriter instance + * @data: (transfer none) (array length=size): Data to write + * @size: Size of @data in bytes + * + * Writes @size bytes of @data to @writer. + * + * Returns: %TRUE if the value could be written + */ +/** + * fpi_byte_writer_fill: + * @writer: #FpiByteWriter instance + * @value: Value to be written + * @size: Number of bytes to be written + * + * Writes @size bytes containing @value to @writer. + * + * Returns: %TRUE if the value could be written + */ + diff --git a/libfprint/fpi-byte-writer.h b/libfprint/fpi-byte-writer.h new file mode 100644 index 0000000..b15a9a1 --- /dev/null +++ b/libfprint/fpi-byte-writer.h @@ -0,0 +1,413 @@ +/* GStreamer byte writer + * + * Copyright (C) 2009 Sebastian Dröge . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __FPI_BYTE_WRITER_H__ +#define __FPI_BYTE_WRITER_H__ + +#include "fpi-byte-reader.h" +#include + +G_BEGIN_DECLS + +#define FPI_BYTE_WRITER(writer) ((FpiByteWriter *) (writer)) + +/** + * FpiByteWriter: + * @parent: #FpiByteReader parent + * @alloc_size: Allocation size of the data + * @fixed: If %TRUE no reallocations are allowed + * @owned: If %FALSE no reallocations are allowed and copies of data are returned + * + * A byte writer instance. + */ +typedef struct { + FpiByteReader parent; + + guint alloc_size; + + gboolean fixed; + gboolean owned; + + /* < private > */ +} FpiByteWriter; + + +FpiByteWriter * fpi_byte_writer_new (void) G_GNUC_MALLOC; + + +FpiByteWriter * fpi_byte_writer_new_with_size (guint size, gboolean fixed) G_GNUC_MALLOC; + + +FpiByteWriter * fpi_byte_writer_new_with_data (guint8 *data, guint size, gboolean initialized) G_GNUC_MALLOC; + + +void fpi_byte_writer_init (FpiByteWriter *writer); + + +void fpi_byte_writer_init_with_size (FpiByteWriter *writer, guint size, gboolean fixed); + + +void fpi_byte_writer_init_with_data (FpiByteWriter *writer, guint8 *data, + guint size, gboolean initialized); + +void fpi_byte_writer_free (FpiByteWriter *writer); + + +guint8 * fpi_byte_writer_free_and_get_data (FpiByteWriter *writer); + + +void fpi_byte_writer_reset (FpiByteWriter *writer); + + +guint8 * fpi_byte_writer_reset_and_get_data (FpiByteWriter *writer); + +/** + * fpi_byte_writer_get_pos: + * @writer: #FpiByteWriter instance + * + * Returns: The current position of the read/write cursor + */ +/** + * fpi_byte_writer_set_pos: + * @writer: #FpiByteWriter instance + * @pos: new position + * + * Sets the current read/write cursor of @writer. The new position + * can only be between 0 and the current size. + * + * Returns: %TRUE if the new position could be set + */ +/** + * fpi_byte_writer_get_size: + * @writer: #FpiByteWriter instance + * + * Returns: The current, initialized size of the data + */ +static inline guint +fpi_byte_writer_get_pos (const FpiByteWriter *writer) +{ + return fpi_byte_reader_get_pos ((const FpiByteReader *) writer); +} + +static inline gboolean +fpi_byte_writer_set_pos (FpiByteWriter *writer, guint pos) +{ + return fpi_byte_reader_set_pos (FPI_BYTE_READER (writer), pos); +} + +static inline guint +fpi_byte_writer_get_size (const FpiByteWriter *writer) +{ + return fpi_byte_reader_get_size ((const FpiByteReader *) writer); +} + + +guint fpi_byte_writer_get_remaining (const FpiByteWriter *writer); + + +gboolean fpi_byte_writer_ensure_free_space (FpiByteWriter *writer, guint size); + + +gboolean fpi_byte_writer_put_uint8 (FpiByteWriter *writer, guint8 val); + + +gboolean fpi_byte_writer_put_int8 (FpiByteWriter *writer, gint8 val); + + +gboolean fpi_byte_writer_put_uint16_be (FpiByteWriter *writer, guint16 val); + + +gboolean fpi_byte_writer_put_uint16_le (FpiByteWriter *writer, guint16 val); + + +gboolean fpi_byte_writer_put_int16_be (FpiByteWriter *writer, gint16 val); + + +gboolean fpi_byte_writer_put_int16_le (FpiByteWriter *writer, gint16 val); + + +gboolean fpi_byte_writer_put_uint24_be (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_uint24_le (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_int24_be (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_int24_le (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_uint32_be (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_uint32_le (FpiByteWriter *writer, guint32 val); + + +gboolean fpi_byte_writer_put_int32_be (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_int32_le (FpiByteWriter *writer, gint32 val); + + +gboolean fpi_byte_writer_put_uint64_be (FpiByteWriter *writer, guint64 val); + + +gboolean fpi_byte_writer_put_uint64_le (FpiByteWriter *writer, guint64 val); + + +gboolean fpi_byte_writer_put_int64_be (FpiByteWriter *writer, gint64 val); + + +gboolean fpi_byte_writer_put_int64_le (FpiByteWriter *writer, gint64 val); + + +gboolean fpi_byte_writer_put_float32_be (FpiByteWriter *writer, gfloat val); + + +gboolean fpi_byte_writer_put_float32_le (FpiByteWriter *writer, gfloat val); + + +gboolean fpi_byte_writer_put_float64_be (FpiByteWriter *writer, gdouble val); + + +gboolean fpi_byte_writer_put_float64_le (FpiByteWriter *writer, gdouble val); + + +gboolean fpi_byte_writer_put_data (FpiByteWriter *writer, const guint8 *data, guint size); + + +gboolean fpi_byte_writer_fill (FpiByteWriter *writer, guint8 value, guint size); + + +gboolean fpi_byte_writer_put_string_utf8 (FpiByteWriter *writer, const gchar *data); + + +gboolean fpi_byte_writer_put_string_utf16 (FpiByteWriter *writer, const guint16 *data); + + +gboolean fpi_byte_writer_put_string_utf32 (FpiByteWriter *writer, const guint32 *data); + +/** + * fpi_byte_writer_put_string: + * @writer: #FpiByteWriter instance + * @data: (in) (array zero-terminated=1): Null terminated string + * + * Write a NUL-terminated string to @writer (including the terminator). The + * string is assumed to be in an 8-bit encoding (e.g. ASCII,UTF-8 or + * ISO-8859-1). + * + * Returns: %TRUE if the string could be written + */ +#define fpi_byte_writer_put_string(writer, data) \ + fpi_byte_writer_put_string_utf8(writer, data) + +static inline guint +fpi_byte_writer_next_pow2 (guint n) +{ + guint ret = 16; + + /* We start with 16, smaller allocations make no sense */ + + while (ret < n && ret > 0) + ret <<= 1; + + return ret ? ret : n; +} + +static inline gboolean +fpi_byte_writer_ensure_free_space_inline (FpiByteWriter * writer, guint size) +{ + gpointer data; + + if (G_LIKELY (size <= writer->alloc_size - writer->parent.byte)) + return TRUE; + if (G_UNLIKELY (writer->fixed || !writer->owned)) + return FALSE; + if (G_UNLIKELY (writer->parent.byte > G_MAXUINT - size)) + return FALSE; + + writer->alloc_size = fpi_byte_writer_next_pow2 (writer->parent.byte + size); + data = g_try_realloc ((guint8 *) writer->parent.data, writer->alloc_size); + if (G_UNLIKELY (data == NULL)) + return FALSE; + + writer->parent.data = (guint8 *) data; + + return TRUE; +} + +#define __FPI_BYTE_WRITER_CREATE_WRITE_FUNC(bits,type,name,write_func) \ +static inline void \ +fpi_byte_writer_put_##name##_unchecked (FpiByteWriter *writer, type val) \ +{ \ + guint8 *write_data; \ + \ + write_data = (guint8 *) writer->parent.data + writer->parent.byte; \ + write_func (write_data, val); \ + writer->parent.byte += bits/8; \ + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); \ +} \ +\ +static inline gboolean \ +fpi_byte_writer_put_##name##_inline (FpiByteWriter *writer, type val) \ +{ \ + g_return_val_if_fail (writer != NULL, FALSE); \ + \ + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline(writer, bits/8))) \ + return FALSE; \ + \ + fpi_byte_writer_put_##name##_unchecked (writer, val); \ + \ + return TRUE; \ +} + +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (8, guint8, uint8, FP_WRITE_UINT8) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (8, gint8, int8, FP_WRITE_UINT8) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, guint16, uint16_le, FP_WRITE_UINT16_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, guint16, uint16_be, FP_WRITE_UINT16_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, gint16, int16_le, FP_WRITE_UINT16_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (16, gint16, int16_be, FP_WRITE_UINT16_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, guint32, uint24_le, FP_WRITE_UINT24_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, guint32, uint24_be, FP_WRITE_UINT24_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, gint32, int24_le, FP_WRITE_UINT24_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (24, gint32, int24_be, FP_WRITE_UINT24_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, guint32, uint32_le, FP_WRITE_UINT32_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, guint32, uint32_be, FP_WRITE_UINT32_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gint32, int32_le, FP_WRITE_UINT32_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gint32, int32_be, FP_WRITE_UINT32_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, guint64, uint64_le, FP_WRITE_UINT64_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, guint64, uint64_be, FP_WRITE_UINT64_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gint64, int64_le, FP_WRITE_UINT64_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gint64, int64_be, FP_WRITE_UINT64_BE) + +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gfloat, float32_be, FP_WRITE_FLOAT_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (32, gfloat, float32_le, FP_WRITE_FLOAT_LE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gdouble, float64_be, FP_WRITE_DOUBLE_BE) +__FPI_BYTE_WRITER_CREATE_WRITE_FUNC (64, gdouble, float64_le, FP_WRITE_DOUBLE_LE) + +#undef __FPI_BYTE_WRITER_CREATE_WRITE_FUNC + +static inline void +fpi_byte_writer_put_data_unchecked (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + memcpy ((guint8 *) & writer->parent.data[writer->parent.byte], data, size); + writer->parent.byte += size; + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); +} + +static inline gboolean +fpi_byte_writer_put_data_inline (FpiByteWriter * writer, const guint8 * data, + guint size) +{ + g_return_val_if_fail (writer != NULL, FALSE); + + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline (writer, size))) + return FALSE; + + fpi_byte_writer_put_data_unchecked (writer, data, size); + + return TRUE; +} + +static inline void +fpi_byte_writer_fill_unchecked (FpiByteWriter * writer, guint8 value, guint size) +{ + memset ((guint8 *) & writer->parent.data[writer->parent.byte], value, size); + writer->parent.byte += size; + writer->parent.size = MAX (writer->parent.size, writer->parent.byte); +} + +static inline gboolean +fpi_byte_writer_fill_inline (FpiByteWriter * writer, guint8 value, guint size) +{ + g_return_val_if_fail (writer != NULL, FALSE); + + if (G_UNLIKELY (!fpi_byte_writer_ensure_free_space_inline (writer, size))) + return FALSE; + + fpi_byte_writer_fill_unchecked (writer, value, size); + + return TRUE; +} + +#ifndef FPI_BYTE_WRITER_DISABLE_INLINES + +/* we use defines here so we can add the G_LIKELY() */ + +#define fpi_byte_writer_ensure_free_space(writer, size) \ + G_LIKELY (fpi_byte_writer_ensure_free_space_inline (writer, size)) +#define fpi_byte_writer_put_uint8(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint8_inline (writer, val)) +#define fpi_byte_writer_put_int8(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int8_inline (writer, val)) +#define fpi_byte_writer_put_uint16_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint16_be_inline (writer, val)) +#define fpi_byte_writer_put_uint16_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint16_le_inline (writer, val)) +#define fpi_byte_writer_put_int16_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int16_be_inline (writer, val)) +#define fpi_byte_writer_put_int16_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int16_le_inline (writer, val)) +#define fpi_byte_writer_put_uint24_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint24_be_inline (writer, val)) +#define fpi_byte_writer_put_uint24_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint24_le_inline (writer, val)) +#define fpi_byte_writer_put_int24_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int24_be_inline (writer, val)) +#define fpi_byte_writer_put_int24_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int24_le_inline (writer, val)) +#define fpi_byte_writer_put_uint32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint32_be_inline (writer, val)) +#define fpi_byte_writer_put_uint32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint32_le_inline (writer, val)) +#define fpi_byte_writer_put_int32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int32_be_inline (writer, val)) +#define fpi_byte_writer_put_int32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int32_le_inline (writer, val)) +#define fpi_byte_writer_put_uint64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint64_be_inline (writer, val)) +#define fpi_byte_writer_put_uint64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_uint64_le_inline (writer, val)) +#define fpi_byte_writer_put_int64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int64_be_inline (writer, val)) +#define fpi_byte_writer_put_int64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_int64_le_inline (writer, val)) + +#define fpi_byte_writer_put_float32_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float32_be_inline (writer, val)) +#define fpi_byte_writer_put_float32_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float32_le_inline (writer, val)) +#define fpi_byte_writer_put_float64_be(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float64_be_inline (writer, val)) +#define fpi_byte_writer_put_float64_le(writer, val) \ + G_LIKELY (fpi_byte_writer_put_float64_le_inline (writer, val)) + +#define fpi_byte_writer_put_data(writer, data, size) \ + G_LIKELY (fpi_byte_writer_put_data_inline (writer, data, size)) +#define fpi_byte_writer_fill(writer, val, size) \ + G_LIKELY (fpi_byte_writer_fill_inline (writer, val, size)) + +#endif + +G_END_DECLS + +#endif /* __FPI_BYTE_WRITER_H__ */ diff --git a/libfprint/meson.build b/libfprint/meson.build index 6e4eb79..f2a2e4d 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -7,6 +7,8 @@ libfprint_sources = [ 'fpi-assembling.c', 'fpi-ssm.c', 'fpi-usb-transfer.c', + 'fpi-byte-reader.c', + 'fpi-byte-writer.c', ] libfprint_public_headers = [ @@ -22,6 +24,9 @@ libfprint_private_headers = [ 'fpi-image.h', 'fpi-image-device.h', 'fpi-print.h', + 'fpi-byte-reader.h', + 'fpi-byte-writer.h', + 'fpi-byte-utils.h', ] nbis_sources = [