--- /dev/null
+From ec66c7c584f0b41c98e93758d9b53bd6dd582df2 Mon Sep 17 00:00:00 2001
+From: Matthew Waters <matthew@centricular.com>
+Date: Tue, 22 Nov 2016 19:05:00 +1100
+Subject: [PATCH] flxdec: add some write bounds checking
+
+Without checking the bounds of the frame we are writing into, we can
+write off the end of the destination buffer.
+
+https://scarybeastsecurity.blogspot.dk/2016/11/0day-exploit-advancing-exploitation.html
+
+https://bugzilla.gnome.org/show_bug.cgi?id=774834
+Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
+---
+ gst/flx/gstflxdec.c | 116 +++++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 91 insertions(+), 25 deletions(-)
+
+diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
+index 604be2f..d51a8e6 100644
+--- a/gst/flx/gstflxdec.c
++++ b/gst/flx/gstflxdec.c
+@@ -74,9 +74,9 @@ static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+
+ static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
+-static void flx_decode_brun (GstFlxDec *, guchar *, guchar *);
+-static void flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
+-static void flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
++static gboolean flx_decode_brun (GstFlxDec *, guchar *, guchar *);
++static gboolean flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
++static gboolean flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
+
+ #define rndalign(off) ((off) + ((off) & 1))
+
+@@ -203,13 +203,14 @@ gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
+ return ret;
+ }
+
+-static void
++static gboolean
+ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
+ guchar * dest)
+ {
+ FlxFrameChunk *hdr;
++ gboolean ret = TRUE;
+
+- g_return_if_fail (data != NULL);
++ g_return_val_if_fail (data != NULL, FALSE);
+
+ while (count--) {
+ hdr = (FlxFrameChunk *) data;
+@@ -228,17 +229,17 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
+ break;
+
+ case FLX_BRUN:
+- flx_decode_brun (flxdec, data, dest);
++ ret = flx_decode_brun (flxdec, data, dest);
+ data += rndalign (hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_LC:
+- flx_decode_delta_fli (flxdec, data, dest);
++ ret = flx_decode_delta_fli (flxdec, data, dest);
+ data += rndalign (hdr->size) - FlxFrameChunkSize;
+ break;
+
+ case FLX_SS2:
+- flx_decode_delta_flc (flxdec, data, dest);
++ ret = flx_decode_delta_flc (flxdec, data, dest);
+ data += rndalign (hdr->size) - FlxFrameChunkSize;
+ break;
+
+@@ -256,7 +257,12 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
+ data += rndalign (hdr->size) - FlxFrameChunkSize;
+ break;
+ }
++
++ if (!ret)
++ break;
+ }
++
++ return ret;
+ }
+
+
+@@ -289,13 +295,13 @@ flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
+ }
+ }
+
+-static void
++static gboolean
+ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ {
+ gulong count, lines, row;
+ guchar x;
+
+- g_return_if_fail (flxdec != NULL);
++ g_return_val_if_fail (flxdec != NULL, FALSE);
+
+ lines = flxdec->hdr.height;
+ while (lines--) {
+@@ -313,12 +319,21 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ if (count > 0x7f) {
+ /* literal run */
+ count = 0x100 - count;
++ if ((glong) row - count < 0) {
++ GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
++ return FALSE;
++ }
+ row -= count;
+
+ while (count--)
+ *dest++ = *data++;
+
+ } else {
++ if ((glong) row - count < 0) {
++ GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
++ return FALSE;
++ }
++
+ /* replicate run */
+ row -= count;
+ x = *data++;
+@@ -328,22 +343,28 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ }
+ }
+ }
++
++ return TRUE;
+ }
+
+-static void
++static gboolean
+ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ {
+ gulong count, packets, lines, start_line;
+ guchar *start_p, x;
+
+- g_return_if_fail (flxdec != NULL);
+- g_return_if_fail (flxdec->delta_data != NULL);
++ g_return_val_if_fail (flxdec != NULL, FALSE);
++ g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+ /* use last frame for delta */
+ memcpy (dest, flxdec->delta_data, flxdec->size);
+
+ start_line = (data[0] + (data[1] << 8));
+ lines = (data[2] + (data[3] << 8));
++ if (start_line + lines > flxdec->hdr.height) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
++ return FALSE;
++ }
+ data += 4;
+
+ /* start position of delta */
+@@ -356,7 +377,8 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+
+ while (packets--) {
+ /* skip count */
+- dest += *data++;
++ guchar skip = *data++;
++ dest += skip;
+
+ /* RLE count */
+ count = *data++;
+@@ -364,12 +386,24 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ if (count > 0x7f) {
+ /* literal run */
+ count = 0x100 - count;
+- x = *data++;
+
++ if (skip + count > flxdec->hdr.width) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
++ "line too long.");
++ return FALSE;
++ }
++
++ x = *data++;
+ while (count--)
+ *dest++ = x;
+
+ } else {
++ if (skip + count > flxdec->hdr.width) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
++ "line too long.");
++ return FALSE;
++ }
++
+ /* replicate run */
+ while (count--)
+ *dest++ = *data++;
+@@ -378,21 +412,27 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ start_p += flxdec->hdr.width;
+ dest = start_p;
+ }
++
++ return TRUE;
+ }
+
+-static void
++static gboolean
+ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ {
+ gulong count, lines, start_l, opcode;
+ guchar *start_p;
+
+- g_return_if_fail (flxdec != NULL);
+- g_return_if_fail (flxdec->delta_data != NULL);
++ g_return_val_if_fail (flxdec != NULL, FALSE);
++ g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+ /* use last frame for delta */
+ memcpy (dest, flxdec->delta_data, flxdec->size);
+
+ lines = (data[0] + (data[1] << 8));
++ if (lines > flxdec->hdr.height) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
++ return FALSE;
++ }
+ data += 2;
+
+ start_p = dest;
+@@ -405,9 +445,15 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
+ data += 2;
+ if ((opcode & 0xc000) == 0xc000) {
+- /* skip count */
+- start_l += (0x10000 - opcode);
+- dest += flxdec->hdr.width * (0x10000 - opcode);
++ /* line skip count */
++ gulong skip = (0x10000 - opcode);
++ if (skip > flxdec->hdr.height) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
++ "skip line count too big.");
++ return FALSE;
++ }
++ start_l += skip;
++ dest += flxdec->hdr.width * skip;
+ } else {
+ /* last pixel */
+ dest += flxdec->hdr.width;
+@@ -419,7 +465,8 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ /* last opcode is the packet count */
+ while (opcode--) {
+ /* skip count */
+- dest += *data++;
++ guchar skip = *data++;
++ dest += skip;
+
+ /* RLE count */
+ count = *data++;
+@@ -427,12 +474,25 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ if (count > 0x7f) {
+ /* replicate word run */
+ count = 0x100 - count;
++
++ if (skip + count > flxdec->hdr.width) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
++ "line too long.");
++ return FALSE;
++ }
++
+ while (count--) {
+ *dest++ = data[0];
+ *dest++ = data[1];
+ }
+ data += 2;
+ } else {
++ if (skip + count > flxdec->hdr.width) {
++ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
++ "line too long.");
++ return FALSE;
++ }
++
+ /* literal word run */
+ while (count--) {
+ *dest++ = *data++;
+@@ -442,6 +502,8 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ }
+ lines--;
+ }
++
++ return TRUE;
+ }
+
+ static GstFlowReturn
+@@ -571,9 +633,13 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+ out = gst_buffer_new_and_alloc (flxdec->size * 4);
+
+ /* decode chunks */
+- flx_decode_chunks (flxdec,
+- ((FlxFrameType *) chunk)->chunks,
+- chunk + FlxFrameTypeSize, flxdec->frame_data);
++ if (!flx_decode_chunks (flxdec,
++ ((FlxFrameType *) chunk)->chunks,
++ chunk + FlxFrameTypeSize, flxdec->frame_data)) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Could not decode chunk"), NULL);
++ return GST_FLOW_ERROR;
++ }
+
+ /* save copy of the current frame for possible delta. */
+ memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
+--
+2.10.2
+
--- /dev/null
+From 7c7a9f8df1b545eec1ef4461b742c3696d4d0e9e Mon Sep 17 00:00:00 2001
+From: Matthew Waters <matthew@centricular.com>
+Date: Wed, 23 Nov 2016 07:09:06 +1100
+Subject: [PATCH] flxdec: rewrite logic based on GstByteReader/Writer
+
+Solves overreading/writing the given arrays and will error out if the
+streams asks to do that.
+
+Also does more error checking that the stream is valid and won't
+overrun any allocated arrays. Also mitigate integer overflow errors
+calculating allocation sizes.
+
+https://bugzilla.gnome.org/show_bug.cgi?id=774859
+Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
+---
+ gst/flx/flx_color.c | 1 -
+ gst/flx/flx_fmt.h | 72 -------
+ gst/flx/gstflxdec.c | 610 ++++++++++++++++++++++++++++++++++++----------------
+ gst/flx/gstflxdec.h | 4 +-
+ 4 files changed, 427 insertions(+), 260 deletions(-)
+
+diff --git a/gst/flx/flx_color.c b/gst/flx/flx_color.c
+index 047bfdf..3a58135 100644
+--- a/gst/flx/flx_color.c
++++ b/gst/flx/flx_color.c
+@@ -101,7 +101,6 @@ flx_set_palette_vector (FlxColorSpaceConverter * flxpal, guint start, guint num,
+ } else {
+ memcpy (&flxpal->palvec[start * 3], newpal, grab * 3);
+ }
+-
+ }
+
+ void
+diff --git a/gst/flx/flx_fmt.h b/gst/flx/flx_fmt.h
+index 9ab31ba..abff200 100644
+--- a/gst/flx/flx_fmt.h
++++ b/gst/flx/flx_fmt.h
+@@ -123,78 +123,6 @@ typedef struct _FlxFrameType
+ } FlxFrameType;
+ #define FlxFrameTypeSize 10
+
+-#if G_BYTE_ORDER == G_BIG_ENDIAN
+-#define LE_TO_BE_16(i16) ((guint16) (((i16) << 8) | ((i16) >> 8)))
+-#define LE_TO_BE_32(i32) \
+- (((guint32) (LE_TO_BE_16((guint16) (i32))) << 16) | (LE_TO_BE_16((i32) >> 16)))
+-
+-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p) \
+- do { \
+- (frm_type_p)->chunks = LE_TO_BE_16((frm_type_p)->chunks); \
+- (frm_type_p)->delay = LE_TO_BE_16((frm_type_p)->delay); \
+- } while(0)
+-
+-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p) \
+- do { \
+- (hffmn_table_p)->codelength = \
+- LE_TO_BE_16((hffmn_table_p)->codelength); \
+- (hffmn_table_p)->numcodes = LE_TO_BE_16((hffmn_table_p)->numcodes); \
+- } while(0)
+-
+-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p) \
+- ((sgmnt_table_p)->segments = LE_TO_BE_16((sgmnt_table_p)->segments))
+-
+-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p) \
+- do { \
+- (prfx_chnk_p)->chunks = LE_TO_BE_16((prfx_chnk_p)->chunks); \
+- } while(0)
+-
+-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p) \
+- do { \
+- (frm_chnk_p)->size = LE_TO_BE_32((frm_chnk_p)->size); \
+- (frm_chnk_p)->id = LE_TO_BE_16((frm_chnk_p)->id); \
+- } while(0)
+-
+-#define FLX_HDR_FIX_ENDIANNESS(hdr_p) \
+- do { \
+- (hdr_p)->size = LE_TO_BE_32((hdr_p)->size); \
+- (hdr_p)->type = LE_TO_BE_16((hdr_p)->type); \
+- (hdr_p)->frames = LE_TO_BE_16((hdr_p)->frames); \
+- (hdr_p)->width = LE_TO_BE_16((hdr_p)->width); \
+- (hdr_p)->height = LE_TO_BE_16((hdr_p)->height); \
+- (hdr_p)->depth = LE_TO_BE_16((hdr_p)->depth); \
+- (hdr_p)->flags = LE_TO_BE_16((hdr_p)->flags); \
+- (hdr_p)->speed = LE_TO_BE_32((hdr_p)->speed); \
+- (hdr_p)->reserved1 = LE_TO_BE_16((hdr_p)->reserved1); \
+- (hdr_p)->created = LE_TO_BE_32((hdr_p)->created); \
+- (hdr_p)->creator = LE_TO_BE_32((hdr_p)->creator); \
+- (hdr_p)->updated = LE_TO_BE_32((hdr_p)->updated); \
+- (hdr_p)->updater = LE_TO_BE_32((hdr_p)->updater); \
+- (hdr_p)->aspect_dx = LE_TO_BE_16((hdr_p)->aspect_dx); \
+- (hdr_p)->aspect_dy = LE_TO_BE_16((hdr_p)->aspect_dy); \
+- (hdr_p)->ext_flags = LE_TO_BE_16((hdr_p)->ext_flags); \
+- (hdr_p)->keyframes = LE_TO_BE_16((hdr_p)->keyframes); \
+- (hdr_p)->totalframes = LE_TO_BE_16((hdr_p)->totalframes); \
+- (hdr_p)->req_memory = LE_TO_BE_32((hdr_p)->req_memory); \
+- (hdr_p)->max_regions = LE_TO_BE_16((hdr_p)->max_regions); \
+- (hdr_p)->transp_num = LE_TO_BE_16((hdr_p)->transp_num); \
+- (hdr_p)->oframe1 = LE_TO_BE_32((hdr_p)->oframe1); \
+- (hdr_p)->oframe2 = LE_TO_BE_32((hdr_p)->oframe2); \
+- } while(0)
+-#else
+-
+-#define LE_TO_BE_16(i16) ((i16))
+-#define LE_TO_BE_32(i32) ((i32))
+-
+-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p)
+-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p)
+-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p)
+-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p)
+-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p)
+-#define FLX_HDR_FIX_ENDIANNESS(hdr_p)
+-
+-#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
+-
+ G_END_DECLS
+
+ #endif /* __GST_FLX_FMT_H__ */
+diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
+index a237976..aa1bed5 100644
+--- a/gst/flx/gstflxdec.c
++++ b/gst/flx/gstflxdec.c
+@@ -1,5 +1,6 @@
+ /* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
++ * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+@@ -24,6 +25,7 @@
+ /*
+ * http://www.coolutils.com/Formats/FLI
+ * http://woodshole.er.usgs.gov/operations/modeling/flc.html
++ * http://www.compuphase.com/flic.htm
+ */
+
+ #ifdef HAVE_CONFIG_H
+@@ -73,10 +75,14 @@ static GstStateChangeReturn gst_flxdec_change_state (GstElement * element,
+ static gboolean gst_flxdec_src_query_handler (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+
+-static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
+-static gboolean flx_decode_brun (GstFlxDec *, guchar *, guchar *);
+-static gboolean flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
+-static gboolean flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
++static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
++ GstByteWriter * writer, gint scale);
++static gboolean flx_decode_brun (GstFlxDec * flxdec,
++ GstByteReader * reader, GstByteWriter * writer);
++static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
++ GstByteReader * reader, GstByteWriter * writer);
++static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
++ GstByteReader * reader, GstByteWriter * writer);
+
+ #define rndalign(off) ((off) + ((off) & 1))
+
+@@ -204,57 +210,59 @@ gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
+ }
+
+ static gboolean
+-flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
+- guchar * dest)
++flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
++ GstByteWriter * writer)
+ {
+- FlxFrameChunk *hdr;
+ gboolean ret = TRUE;
+
+- g_return_val_if_fail (data != NULL, FALSE);
+-
+- while (count--) {
+- hdr = (FlxFrameChunk *) data;
+- FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
+- data += FlxFrameChunkSize;
++ while (n_chunks--) {
++ GstByteReader chunk;
++ guint32 size;
++ guint16 type;
++
++ if (!gst_byte_reader_get_uint32_le (reader, &size))
++ goto parse_error;
++ if (!gst_byte_reader_get_uint16_le (reader, &type))
++ goto parse_error;
++ GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
++
++ if (!gst_byte_reader_get_sub_reader (reader, &chunk,
++ size - FlxFrameChunkSize)) {
++ GST_ERROR_OBJECT (flxdec, "Incorrect size in the chunk header");
++ goto error;
++ }
+
+- switch (hdr->id) {
++ switch (type) {
+ case FLX_COLOR64:
+- flx_decode_color (flxdec, data, dest, 2);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ ret = flx_decode_color (flxdec, &chunk, writer, 2);
+ break;
+
+ case FLX_COLOR256:
+- flx_decode_color (flxdec, data, dest, 0);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ ret = flx_decode_color (flxdec, &chunk, writer, 0);
+ break;
+
+ case FLX_BRUN:
+- ret = flx_decode_brun (flxdec, data, dest);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ ret = flx_decode_brun (flxdec, &chunk, writer);
+ break;
+
+ case FLX_LC:
+- ret = flx_decode_delta_fli (flxdec, data, dest);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ ret = flx_decode_delta_fli (flxdec, &chunk, writer);
+ break;
+
+ case FLX_SS2:
+- ret = flx_decode_delta_flc (flxdec, data, dest);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ ret = flx_decode_delta_flc (flxdec, &chunk, writer);
+ break;
+
+ case FLX_BLACK:
+- memset (dest, 0, flxdec->size);
++ ret = gst_byte_writer_fill (writer, 0, flxdec->size);
+ break;
+
+ case FLX_MINI:
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
+ break;
+
+ default:
+- GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
+- hdr->id, hdr->size);
+- data += rndalign (hdr->size) - FlxFrameChunkSize;
++ GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
++ type, size);
+ break;
+ }
+
+@@ -263,43 +271,60 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
+ }
+
+ return ret;
++
++parse_error:
++ GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
++error:
++ return FALSE;
+ }
+
+
+-static void
+-flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
++static gboolean
++flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
++ GstByteWriter * writer, gint scale)
+ {
+- guint packs, count, indx;
++ guint8 count, indx;
++ guint16 packs;
+
+- g_return_if_fail (flxdec != NULL);
+-
+- packs = (data[0] + (data[1] << 8));
+-
+- data += 2;
++ if (!gst_byte_reader_get_uint16_le (reader, &packs))
++ goto error;
+ indx = 0;
+
+- GST_LOG ("GstFlxDec: cmap packs: %d", packs);
++ GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
+ while (packs--) {
++ const guint8 *data;
++ guint16 actual_count;
++
+ /* color map index + skip count */
+- indx += *data++;
++ if (!gst_byte_reader_get_uint8 (reader, &indx))
++ goto error;
+
+ /* number of rgb triplets */
+- count = *data++ & 0xff;
+- if (count == 0)
+- count = 256;
++ if (!gst_byte_reader_get_uint8 (reader, &count))
++ goto error;
+
+- GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
+- flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
++ actual_count = count == 0 ? 256 : count;
+
+- data += (count * 3);
++ if (!gst_byte_reader_get_data (reader, count * 3, &data))
++ goto error;
++
++ GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
++ flx_set_palette_vector (flxdec->converter, indx, actual_count,
++ (guchar *) data, scale);
+ }
++
++ return TRUE;
++
++error:
++ GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
++ return FALSE;
+ }
+
+ static gboolean
+-flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
++flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
++ GstByteWriter * writer)
+ {
+- gulong count, lines, row;
+- guchar x;
++ gulong lines, row;
+
+ g_return_val_if_fail (flxdec != NULL, FALSE);
+
+@@ -310,82 +335,125 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ * contain more then 255 RLE packets. we use the frame
+ * width instead.
+ */
+- data++;
++ if (!gst_byte_reader_skip (reader, 1))
++ goto error;
+
+ row = flxdec->hdr.width;
+ while (row) {
+- count = *data++;
++ gint8 count;
++
++ if (!gst_byte_reader_get_int8 (reader, &count))
++ goto error;
++
++ if (count <= 0) {
++ const guint8 *data;
+
+- if (count > 0x7f) {
+ /* literal run */
+- count = 0x100 - count;
+- if ((glong) row - (glong) count < 0) {
+- GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
++ count = ABS (count);
++
++ GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
++
++ if (count > row) {
++ GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
++ "bytes to write exceeds the end of the row");
+ return FALSE;
+ }
+ row -= count;
+
+- while (count--)
+- *dest++ = *data++;
+-
++ if (!gst_byte_reader_get_data (reader, count, &data))
++ goto error;
++ if (!gst_byte_writer_put_data (writer, data, count))
++ goto error;
+ } else {
+- if ((glong) row - (glong) count < 0) {
+- GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
++ guint8 x;
++
++ GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
++
++ if (count > row) {
++ GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
++ "bytes to write exceeds the end of the row");
+ return FALSE;
+ }
+
+ /* replicate run */
+ row -= count;
+- x = *data++;
+
+- while (count--)
+- *dest++ = x;
++ if (!gst_byte_reader_get_uint8 (reader, &x))
++ goto error;
++ if (!gst_byte_writer_fill (writer, x, count))
++ goto error;
+ }
+ }
+ }
+
+ return TRUE;
++
++error:
++ GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
++ return FALSE;
+ }
+
+ static gboolean
+-flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
++flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
++ GstByteWriter * writer)
+ {
+- gulong count, packets, lines, start_line;
+- guchar *start_p, x;
++ guint16 start_line, lines;
++ guint line_start_i;
+
+ g_return_val_if_fail (flxdec != NULL, FALSE);
+ g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+ /* use last frame for delta */
+- memcpy (dest, flxdec->delta_data, flxdec->size);
++ if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
++ goto error;
++
++ if (!gst_byte_reader_get_uint16_le (reader, &start_line))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &lines))
++ goto error;
++ GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
++ flxdec->hdr.height, start_line, lines);
+
+- start_line = (data[0] + (data[1] << 8));
+- lines = (data[2] + (data[3] << 8));
+ if (start_line + lines > flxdec->hdr.height) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
+ return FALSE;
+ }
+- data += 4;
+
+- /* start position of delta */
+- dest += (flxdec->hdr.width * start_line);
+- start_p = dest;
++ line_start_i = flxdec->hdr.width * start_line;
++ if (!gst_byte_writer_set_pos (writer, line_start_i))
++ goto error;
+
+ while (lines--) {
++ guint8 packets;
++
+ /* packet count */
+- packets = *data++;
++ if (!gst_byte_reader_get_uint8 (reader, &packets))
++ goto error;
++ GST_LOG_OBJECT (flxdec, "have %d packets", packets);
+
+ while (packets--) {
+ /* skip count */
+- guchar skip = *data++;
+- dest += skip;
++ guint8 skip;
++ gint8 count;
++ if (!gst_byte_reader_get_uint8 (reader, &skip))
++ goto error;
++
++ /* skip bytes */
++ if (!gst_byte_writer_set_pos (writer,
++ gst_byte_writer_get_pos (writer) + skip))
++ goto error;
+
+ /* RLE count */
+- count = *data++;
++ if (!gst_byte_reader_get_int8 (reader, &count))
++ goto error;
++
++ if (count < 0) {
++ guint8 x;
+
+- if (count > 0x7f) {
+ /* literal run */
+- count = 0x100 - count;
++ count = ABS (count);
++ GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
++ count, skip);
+
+ if (skip + count > flxdec->hdr.width) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
+@@ -393,11 +461,16 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ return FALSE;
+ }
+
+- x = *data++;
+- while (count--)
+- *dest++ = x;
+-
++ if (!gst_byte_reader_get_uint8 (reader, &x))
++ goto error;
++ if (!gst_byte_writer_fill (writer, x, count))
++ goto error;
+ } else {
++ const guint8 *data;
++
++ GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
++ count, skip);
++
+ if (skip + count > flxdec->hdr.width) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
+ "line too long.");
+@@ -405,45 +478,60 @@ flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ }
+
+ /* replicate run */
+- while (count--)
+- *dest++ = *data++;
++ if (!gst_byte_reader_get_data (reader, count, &data))
++ goto error;
++ if (!gst_byte_writer_put_data (writer, data, count))
++ goto error;
+ }
+ }
+- start_p += flxdec->hdr.width;
+- dest = start_p;
++ line_start_i += flxdec->hdr.width;
++ if (!gst_byte_writer_set_pos (writer, line_start_i))
++ goto error;
+ }
+
+ return TRUE;
++
++error:
++ GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
++ return FALSE;
+ }
+
+ static gboolean
+-flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
++flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
++ GstByteWriter * writer)
+ {
+- gulong count, lines, start_l, opcode;
+- guchar *start_p;
++ guint16 lines, start_l;
+
+ g_return_val_if_fail (flxdec != NULL, FALSE);
+ g_return_val_if_fail (flxdec->delta_data != NULL, FALSE);
+
+ /* use last frame for delta */
+- memcpy (dest, flxdec->delta_data, flxdec->size);
++ if (!gst_byte_writer_put_data (writer, flxdec->delta_data, flxdec->size))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &lines))
++ goto error;
+
+- lines = (data[0] + (data[1] << 8));
+ if (lines > flxdec->hdr.height) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
+ return FALSE;
+ }
+- data += 2;
+
+- start_p = dest;
+ start_l = lines;
+
+ while (lines) {
+- dest = start_p + (flxdec->hdr.width * (start_l - lines));
++ guint16 opcode;
++
++ if (!gst_byte_writer_set_pos (writer,
++ flxdec->hdr.width * (start_l - lines)))
++ goto error;
+
+ /* process opcode(s) */
+- while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
+- data += 2;
++ while (TRUE) {
++ if (!gst_byte_reader_get_uint16_le (reader, &opcode))
++ goto error;
++ if ((opcode & 0xc000) == 0)
++ break;
++
+ if ((opcode & 0xc000) == 0xc000) {
+ /* line skip count */
+ gulong skip = (0x10000 - opcode);
+@@ -453,27 +541,44 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ return FALSE;
+ }
+ start_l += skip;
+- dest += flxdec->hdr.width * skip;
++ if (!gst_byte_writer_set_pos (writer,
++ gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
++ goto error;
+ } else {
+ /* last pixel */
+- dest += flxdec->hdr.width;
+- *dest++ = (opcode & 0xff);
++ if (!gst_byte_writer_set_pos (writer,
++ gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
++ goto error;
++ if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
++ goto error;
+ }
+ }
+- data += 2;
+
+ /* last opcode is the packet count */
++ GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
+ while (opcode--) {
+ /* skip count */
+- guchar skip = *data++;
+- dest += skip;
++ guint8 skip;
++ gint8 count;
++
++ if (!gst_byte_reader_get_uint8 (reader, &skip))
++ goto error;
++ if (!gst_byte_writer_set_pos (writer,
++ gst_byte_writer_get_pos (writer) + skip))
++ goto error;
+
+ /* RLE count */
+- count = *data++;
++ if (!gst_byte_reader_get_int8 (reader, &count))
++ goto error;
++
++ if (count < 0) {
++ guint16 x;
+
+- if (count > 0x7f) {
+ /* replicate word run */
+- count = 0x100 - count;
++ count = ABS (count);
++
++ GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
++ count, skip);
+
+ if (skip + count > flxdec->hdr.width) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
+@@ -481,22 +586,31 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ return FALSE;
+ }
+
++ if (!gst_byte_reader_get_uint16_le (reader, &x))
++ goto error;
++
+ while (count--) {
+- *dest++ = data[0];
+- *dest++ = data[1];
++ if (!gst_byte_writer_put_uint16_le (writer, x)) {
++ goto error;
++ }
+ }
+- data += 2;
+ } else {
++ GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
++ count, skip);
++
+ if (skip + count > flxdec->hdr.width) {
+ GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
+ "line too long.");
+ return FALSE;
+ }
+
+- /* literal word run */
+ while (count--) {
+- *dest++ = *data++;
+- *dest++ = *data++;
++ guint16 x;
++
++ if (!gst_byte_reader_get_uint16_le (reader, &x))
++ goto error;
++ if (!gst_byte_writer_put_uint16_le (writer, x))
++ goto error;
+ }
+ }
+ }
+@@ -504,13 +618,91 @@ flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+ }
+
+ return TRUE;
++
++error:
++ GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
++ return FALSE;
++}
++
++static gboolean
++_read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
++{
++ memset (flxh, 0, sizeof (*flxh));
++
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
++ goto error;
++ if (flxh->size < FlxHeaderSize) {
++ GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
++ return FALSE;
++ }
++
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
++ goto error;
++ if (!gst_byte_reader_skip (reader, 2)) /* reserved */
++ goto error;
++ /* FLC */
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
++ goto error;
++ /* EGI */
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
++ goto error;
++ if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
++ goto error;
++ if (!gst_byte_reader_skip (reader, 24)) /* reserved */
++ goto error;
++ /* FLC */
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
++ goto error;
++ if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
++ goto error;
++ if (!gst_byte_reader_skip (reader, 40)) /* reserved */
++ goto error;
++
++ return TRUE;
++
++error:
++ GST_ERROR_OBJECT (flxdec, "Error reading file header");
++ return FALSE;
+ }
+
+ static GstFlowReturn
+ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+ {
++ GstByteReader reader;
++ GstBuffer *input;
++ GstMapInfo map_info;
+ GstCaps *caps;
+- guint avail;
++ guint available;
+ GstFlowReturn res = GST_FLOW_OK;
+
+ GstFlxDec *flxdec;
+@@ -521,31 +713,50 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+ g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
+
+ gst_adapter_push (flxdec->adapter, buf);
+- avail = gst_adapter_available (flxdec->adapter);
++ available = gst_adapter_available (flxdec->adapter);
++ input = gst_adapter_get_buffer (flxdec->adapter, available);
++ if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Failed to map buffer"), (NULL));
++ goto error;
++ }
++ gst_byte_reader_init (&reader, map_info.data, map_info.size);
+
+ if (flxdec->state == GST_FLXDEC_READ_HEADER) {
+- if (avail >= FlxHeaderSize) {
+- const guint8 *data = gst_adapter_map (flxdec->adapter, FlxHeaderSize);
++ if (available >= FlxHeaderSize) {
++ GstByteReader header;
+ GstCaps *templ;
+
+- memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize);
+- FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr));
+- gst_adapter_unmap (flxdec->adapter);
++ if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Could not read header"), (NULL));
++ goto unmap_input_error;
++ }
+ gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
++ available -= FlxHeaderSize;
++
++ if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Failed to parse header"), (NULL));
++ goto unmap_input_error;
++ }
+
+ flxh = &flxdec->hdr;
+
+ /* check header */
+ if (flxh->type != FLX_MAGICHDR_FLI &&
+- flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX)
+- goto wrong_type;
++ flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
++ ("not a flx file (type %x)", flxh->type));
++ goto unmap_input_error;
++ }
+
+- GST_LOG ("size : %d", flxh->size);
+- GST_LOG ("frames : %d", flxh->frames);
+- GST_LOG ("width : %d", flxh->width);
+- GST_LOG ("height : %d", flxh->height);
+- GST_LOG ("depth : %d", flxh->depth);
+- GST_LOG ("speed : %d", flxh->speed);
++ GST_INFO_OBJECT (flxdec, "size : %d", flxh->size);
++ GST_INFO_OBJECT (flxdec, "frames : %d", flxh->frames);
++ GST_INFO_OBJECT (flxdec, "width : %d", flxh->width);
++ GST_INFO_OBJECT (flxdec, "height : %d", flxh->height);
++ GST_INFO_OBJECT (flxdec, "depth : %d", flxh->depth);
++ GST_INFO_OBJECT (flxdec, "speed : %d", flxh->speed);
+
+ flxdec->next_time = 0;
+
+@@ -573,18 +784,32 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+ gst_pad_set_caps (flxdec->srcpad, caps);
+ gst_caps_unref (caps);
+
+- if (flxh->depth <= 8)
+- flxdec->converter =
+- flx_colorspace_converter_new (flxh->width, flxh->height);
++ /* zero means 8 */
++ if (flxh->depth == 0)
++ flxh->depth = 8;
++
++ if (flxh->depth != 8) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
++ ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
++ goto unmap_input_error;
++ }
++
++ flxdec->converter =
++ flx_colorspace_converter_new (flxh->width, flxh->height);
+
+ if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
+- GST_LOG ("(FLC) aspect_dx : %d", flxh->aspect_dx);
+- GST_LOG ("(FLC) aspect_dy : %d", flxh->aspect_dy);
+- GST_LOG ("(FLC) oframe1 : 0x%08x", flxh->oframe1);
+- GST_LOG ("(FLC) oframe2 : 0x%08x", flxh->oframe2);
++ GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx : %d", flxh->aspect_dx);
++ GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy : %d", flxh->aspect_dy);
++ GST_INFO_OBJECT (flxdec, "(FLC) oframe1 : 0x%08x", flxh->oframe1);
++ GST_INFO_OBJECT (flxdec, "(FLC) oframe2 : 0x%08x", flxh->oframe2);
+ }
+
+ flxdec->size = ((guint) flxh->width * (guint) flxh->height);
++ if (flxdec->size >= G_MAXSIZE / 4) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Cannot allocate required memory"), (NULL));
++ goto unmap_input_error;
++ }
+
+ /* create delta and output frame */
+ flxdec->frame_data = g_malloc (flxdec->size);
+@@ -596,55 +821,66 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+ GstBuffer *out;
+
+ /* while we have enough data in the adapter */
+- while (avail >= FlxFrameChunkSize && res == GST_FLOW_OK) {
+- FlxFrameChunk flxfh;
+- guchar *chunk;
+- const guint8 *data;
+- GstMapInfo map;
+-
+- chunk = NULL;
+- data = gst_adapter_map (flxdec->adapter, FlxFrameChunkSize);
+- memcpy (&flxfh, data, FlxFrameChunkSize);
+- FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh);
+- gst_adapter_unmap (flxdec->adapter);
+-
+- switch (flxfh.id) {
+- case FLX_FRAME_TYPE:
+- /* check if we have the complete frame */
+- if (avail < flxfh.size)
+- goto need_more_data;
+-
+- /* flush header */
+- gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize);
+-
+- chunk = gst_adapter_take (flxdec->adapter,
+- flxfh.size - FlxFrameChunkSize);
+- FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk);
+- if (((FlxFrameType *) chunk)->chunks == 0)
+- break;
++ while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
++ guint32 size;
++ guint16 type;
+
+- /* create 32 bits output frame */
+-// res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
+-// GST_BUFFER_OFFSET_NONE,
+-// flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
+-// if (res != GST_FLOW_OK)
+-// break;
++ if (!gst_byte_reader_get_uint32_le (&reader, &size))
++ goto parse_error;
++ if (available < size)
++ goto need_more_data;
+
+- out = gst_buffer_new_and_alloc (flxdec->size * 4);
++ available -= size;
++ gst_adapter_flush (flxdec->adapter, size);
++
++ if (!gst_byte_reader_get_uint16_le (&reader, &type))
++ goto parse_error;
++
++ switch (type) {
++ case FLX_FRAME_TYPE:{
++ GstByteReader chunks;
++ GstByteWriter writer;
++ guint16 n_chunks;
++ GstMapInfo map;
++
++ GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
++ size);
++
++ if (!gst_byte_reader_get_sub_reader (&reader, &chunks,
++ size - FlxFrameChunkSize))
++ goto parse_error;
++
++ if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks))
++ goto parse_error;
++ GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
++
++ if (n_chunks == 0)
++ break;
++ if (!gst_byte_reader_skip (&chunks, 8)) /* reserved */
++ goto parse_error;
++
++ gst_byte_writer_init_with_data (&writer, flxdec->frame_data,
++ flxdec->size, TRUE);
+
+ /* decode chunks */
+- if (!flx_decode_chunks (flxdec,
+- ((FlxFrameType *) chunk)->chunks,
+- chunk + FlxFrameTypeSize, flxdec->frame_data)) {
++ if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) {
+ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+ ("%s", "Could not decode chunk"), NULL);
+- return GST_FLOW_ERROR;
++ goto unmap_input_error;
+ }
++ gst_byte_writer_reset (&writer);
+
+ /* save copy of the current frame for possible delta. */
+ memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);
+
+- gst_buffer_map (out, &map, GST_MAP_WRITE);
++ out = gst_buffer_new_and_alloc (flxdec->size * 4);
++ if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) {
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Could not map output buffer"), NULL);
++ gst_buffer_unref (out);
++ goto unmap_input_error;
++ }
++
+ /* convert current frame. */
+ flx_colorspace_convert (flxdec->converter, flxdec->frame_data,
+ map.data);
+@@ -655,30 +891,32 @@ gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
+
+ res = gst_pad_push (flxdec->srcpad, out);
+ break;
++ }
+ default:
+- /* check if we have the complete frame */
+- if (avail < flxfh.size)
+- goto need_more_data;
+-
+- gst_adapter_flush (flxdec->adapter, flxfh.size);
++ GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d",
++ type, size);
++ if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize))
++ goto parse_error;
+ break;
+ }
+-
+- g_free (chunk);
+-
+- avail = gst_adapter_available (flxdec->adapter);
+ }
+ }
++
++ gst_buffer_unmap (input, &map_info);
++ gst_buffer_unref (input);
++
+ need_more_data:
+ return res;
+
+ /* ERRORS */
+-wrong_type:
+- {
+- GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
+- ("not a flx file (type %x)", flxh->type));
+- return GST_FLOW_ERROR;
+- }
++parse_error:
++ GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
++ ("%s", "Failed to parse stream"), (NULL));
++unmap_input_error:
++ gst_buffer_unmap (input, &map_info);
++ gst_buffer_unref (input);
++error:
++ return GST_FLOW_ERROR;
+ }
+
+ static GstStateChangeReturn
+diff --git a/gst/flx/gstflxdec.h b/gst/flx/gstflxdec.h
+index 3f9a0aa..4fd8dfd 100644
+--- a/gst/flx/gstflxdec.h
++++ b/gst/flx/gstflxdec.h
+@@ -23,6 +23,8 @@
+ #include <gst/gst.h>
+
+ #include <gst/base/gstadapter.h>
++#include <gst/base/gstbytereader.h>
++#include <gst/base/gstbytewriter.h>
+ #include "flx_color.h"
+
+ G_BEGIN_DECLS
+@@ -45,7 +47,7 @@ struct _GstFlxDec {
+
+ guint8 *delta_data, *frame_data;
+ GstAdapter *adapter;
+- gulong size;
++ gsize size;
+ GstFlxDecState state;
+ gint64 frame_time;
+ gint64 next_time;
+--
+2.10.2
+