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))
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;
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;
data += rndalign (hdr->size) - FlxFrameChunkSize;
break;
}
+
+ if (!ret)
+ break;
}
+
+ return ret;
}
}
}
-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--) {
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++;
}
}
}
+
+ 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 */
while (packets--) {
/* skip count */
- dest += *data++;
+ guchar skip = *data++;
+ dest += skip;
/* RLE count */
count = *data++;
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++;
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;
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;
/* last opcode is the packet count */
while (opcode--) {
/* skip count */
- dest += *data++;
+ guchar skip = *data++;
+ dest += skip;
/* RLE count */
count = *data++;
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++;
}
lines--;
}
+
+ return TRUE;
}
static GstFlowReturn
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);