* gnu/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/gstreamer.scm (gst-plugins-good): Use it. --- gnu/local.mk | 1 + gnu/packages/gstreamer.scm | 1 + .../gst-plugins-good-flxdec-heap-overflow.patch | 1433 ++++++++++++++++++++ 3 files changed, 1435 insertions(+) create mode 100644 gnu/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch
diff --git a/gnu/local.mk b/gnu/local.mk index 4913727..885e393 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -585,6 +585,7 @@ dist_patch_DATA = \ %D%/packages/patches/grub-gets-undeclared.patch \ %D%/packages/patches/grub-freetype.patch \ %D%/packages/patches/gsl-test-i686.patch \ + %D%/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch \ %D%/packages/patches/guile-1.8-cpp-4.5.patch \ %D%/packages/patches/guile-arm-fixes.patch \ %D%/packages/patches/guile-default-utf8.patch \ diff --git a/gnu/packages/gstreamer.scm b/gnu/packages/gstreamer.scm index 5fe84ec..6c59ca2 100644 --- a/gnu/packages/gstreamer.scm +++ b/gnu/packages/gstreamer.scm @@ -207,6 +207,7 @@ for the GStreamer multimedia library.") (uri (string-append "https://gstreamer.freedesktop.org/src/" name "/" name "-" version ".tar.xz")) + (patches (search-patches "gst-plugins-good-flxdec-heap-overflow.patch")) (sha256 (base32 "1hkcap9l2603266gyi6jgvx7frbvfmb7xhfhjizbczy1wykjwr57")))) diff --git a/gnu/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch b/gnu/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch new file mode 100644 index 0000000..d4d483b --- /dev/null +++ b/gnu/packages/patches/gst-plugins-good-flxdec-heap-overflow.patch @@ -0,0 +1,1433 @@ +These 4 patches fix some security issues in gst-plugins-good's FLIC +decoder, including CVE-2016-{9634,9635,9636}. + +https://security-tracker.debian.org/tracker/DSA-3723-1 +https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9634 +https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9635 +https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9636 + +All 4 patches are copied from the upstream source repository: + +https://cgit.freedesktop.org/gstreamer/gst-plugins-good/ + +Each patch includes a link to the relevant upstream bug report. + +From 2e203a79b7d9af4029307c1a845b3c148d5f5e62 Mon Sep 17 00:00:00 2001 +From: Matthew Waters <matt...@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 +--- + 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 + +From 1ab2b26193861b124426e2f8eb62b75b59ec5488 Mon Sep 17 00:00:00 2001 +From: Matthew Waters <matt...@centricular.com> +Date: Tue, 22 Nov 2016 23:46:00 +1100 +Subject: [PATCH] flxdec: fix some warnings comparing unsigned < 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +bf43f44fcfada5ec4a3ce60cb374340486fe9fac was comparing an unsigned +expression to be < 0 which was always false. + +gstflxdec.c: In function ‘flx_decode_brun’: +gstflxdec.c:322:33: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] + if ((glong) row - count < 0) { + ^ +gstflxdec.c:332:33: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] + if ((glong) row - count < 0) { + ^ + +https://bugzilla.gnome.org/show_bug.cgi?id=774834 +--- + gst/flx/gstflxdec.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c +index d51a8e6..e675c99 100644 +--- a/gst/flx/gstflxdec.c ++++ b/gst/flx/gstflxdec.c +@@ -319,7 +319,7 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest) + if (count > 0x7f) { + /* literal run */ + count = 0x100 - count; +- if ((glong) row - count < 0) { ++ if ((glong) row - (glong) count < 0) { + GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."); + return FALSE; + } +@@ -329,7 +329,7 @@ flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest) + *dest++ = *data++; + + } else { +- if ((glong) row - count < 0) { ++ if ((glong) row - (glong) count < 0) { + GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."); + return FALSE; + } +-- +2.10.2 + +From b31c504645a814c59d91d49e4fe218acaf93f4ca Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebast...@centricular.com> +Date: Wed, 23 Nov 2016 11:20:49 +0200 +Subject: [PATCH] flxdec: Don't unref() parent in the chain function + +We don't own the reference here, it is owned by the caller and given to +us for the scope of this function. Leftover mistake from 0.10 porting. + +https://bugzilla.gnome.org/show_bug.cgi?id=774897 +--- + gst/flx/gstflxdec.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c +index e675c99..a237976 100644 +--- a/gst/flx/gstflxdec.c ++++ b/gst/flx/gstflxdec.c +@@ -677,7 +677,6 @@ wrong_type: + { + GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL), + ("not a flx file (type %x)", flxh->type)); +- gst_object_unref (flxdec); + return GST_FLOW_ERROR; + } + } +-- +2.10.2 + +From be670f0daf67304fb92c76aa09c30cae0bfd1fe4 Mon Sep 17 00:00:00 2001 +From: Matthew Waters <matt...@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 +--- + 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 <om...@temple-baptist.com> ++ * Copyright (C) <2016> Matthew Waters <matt...@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 + -- 2.10.2