apply CVE patch for security weakness 24/132124/2 accepted/tizen/unified/20170608.072420 submit/tizen/20170608.033315
authorSejun Park <sejun79.park@samsung.com>
Thu, 1 Jun 2017 06:55:13 +0000 (15:55 +0900)
committerSejun Park <sejun79.park@samsung.com>
Thu, 1 Jun 2017 07:03:55 +0000 (16:03 +0900)
https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=153a8ae752c90d07190ef45803422a4f71ea8bff

Change-Id: I1472b6d6dcac2371c9d32d4ca0d9f5e98d4b9a1e

gst/flx/flx_color.c
gst/flx/flx_fmt.h
gst/flx/gstflxdec.c [changed mode: 0644->0755]
gst/flx/gstflxdec.h

index 047bfdf..3a58135 100644 (file)
@@ -101,7 +101,6 @@ flx_set_palette_vector (FlxColorSpaceConverter * flxpal, guint start, guint num,
   } else {
     memcpy (&flxpal->palvec[start * 3], newpal, grab * 3);
   }
-
 }
 
 void
index 9ab31ba..abff200 100644 (file)
@@ -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__ */
old mode 100644 (file)
new mode 100755 (executable)
index 3df4e9b..aa1bed5
@@ -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
@@ -47,15 +49,17 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_STATIC_CAPS ("video/x-fli")
     );
 
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+#define RGB_ORDER "xRGB"
+#else
+#define RGB_ORDER "BGRx"
+#endif
+
 /* output */
 static GstStaticPadTemplate src_video_factory = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("xRGB"))
-#else
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRx"))
-#endif
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (RGB_ORDER))
     );
 
 static void gst_flxdec_dispose (GstFlxDec * flxdec);
@@ -71,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 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_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))
 
@@ -201,99 +209,124 @@ gst_flxdec_sink_event_handler (GstPad * pad, GstObject * parent,
   return ret;
 }
 
-static void
-flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
-    guchar * dest)
+static gboolean
+flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  FlxFrameChunk *hdr;
-
-  g_return_if_fail (data != NULL);
-
-  while (count--) {
-    hdr = (FlxFrameChunk *) data;
-    FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
-    data += FlxFrameChunkSize;
+  gboolean ret = TRUE;
+
+  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:
-        flx_decode_brun (flxdec, data, dest);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_brun (flxdec, &chunk, writer);
         break;
 
       case FLX_LC:
-        flx_decode_delta_fli (flxdec, data, dest);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_delta_fli (flxdec, &chunk, writer);
         break;
 
       case FLX_SS2:
-        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;
     }
+
+    if (!ret)
+      break;
   }
-}
 
+  return ret;
 
-static void
-flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
-{
-  guint packs, count, indx;
+parse_error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
+error:
+  return FALSE;
+}
 
-  g_return_if_fail (flxdec != NULL);
 
-  packs = (data[0] + (data[1] << 8));
+static gboolean
+flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer, gint scale)
+{
+  guint8 count, indx;
+  guint16 packs;
 
-  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;
+
+    actual_count = count == 0 ? 256 : count;
 
-    GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
-    flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
+    if (!gst_byte_reader_get_data (reader, count * 3, &data))
+      goto error;
 
-    data += (count * 3);
+    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 void
-flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+static gboolean
+flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  gulong count, lines, row;
-  guchar x;
+  gulong lines, row;
 
-  g_return_if_fail (flxdec != NULL);
+  g_return_val_if_fail (flxdec != NULL, FALSE);
 
   lines = flxdec->hdr.height;
   while (lines--) {
@@ -302,151 +335,374 @@ 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;
-        row -= count;
+        count = ABS (count);
 
-        while (count--)
-          *dest++ = *data++;
+        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;
+
+        if (!gst_byte_reader_get_data (reader, count, &data))
+          goto error;
+        if (!gst_byte_writer_put_data (writer, data, count))
+          goto error;
       } else {
+        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 void
-flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+static gboolean
+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_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));
-  data += 4;
+  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);
+
+  if (start_line + lines > flxdec->hdr.height) {
+    GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
+    return FALSE;
+  }
 
-  /* 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 */
-      dest += *data++;
+      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 > 0x7f) {
-        /* literal run */
-        count = 0x100 - count;
-        x = *data++;
+      if (count < 0) {
+        guint8 x;
 
-        while (count--)
-          *dest++ = x;
+        /* literal run */
+        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. "
+              "line too long.");
+          return FALSE;
+        }
 
+        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.");
+          return FALSE;
+        }
+
         /* 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 void
-flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+static gboolean
+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_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));
-  data += 2;
+  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;
+
+  if (lines > flxdec->hdr.height) {
+    GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
+    return FALSE;
+  }
 
-  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) {
-        /* 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;
+        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 */
-      dest += *data++;
+      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. "
+              "line too long.");
+          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 {
-        /* literal word run */
+        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;
+        }
+
         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;
         }
       }
     }
     lines--;
   }
+
+  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;
@@ -457,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;
 
@@ -509,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);
@@ -532,51 +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 */
-          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);
+            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);
@@ -587,32 +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;
       }
-
-      if (chunk)
-        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));
-    gst_object_unref (flxdec);
-    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
index 3f9a0aa..f5507a4 100644 (file)
@@ -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
@@ -31,7 +33,7 @@ typedef enum {
   GST_FLXDEC_READ_HEADER,
   GST_FLXDEC_PLAYING,
 } GstFlxDecState;
-       
+
 
 /* Definition of structure storing data for this element. */
 typedef struct _GstFlxDec  GstFlxDec;
@@ -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;