|
|
|
@ -131,7 +131,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
FlicDecodeContext *s = avctx->priv_data; |
|
|
|
|
|
|
|
|
|
int stream_ptr = 0; |
|
|
|
|
int stream_ptr_after_color_chunk; |
|
|
|
|
int pixel_ptr; |
|
|
|
|
int palette_ptr; |
|
|
|
|
unsigned char palette_idx1; |
|
|
|
@ -171,7 +170,11 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
pixels = s->frame.data[0]; |
|
|
|
|
pixel_limit = s->avctx->height * s->frame.linesize[0]; |
|
|
|
|
|
|
|
|
|
if (buf_size < 16 || buf_size > INT_MAX - (3 * 256 + FF_INPUT_BUFFER_PADDING_SIZE)) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
frame_size = AV_RL32(&buf[stream_ptr]); |
|
|
|
|
if (frame_size > buf_size) |
|
|
|
|
frame_size = buf_size; |
|
|
|
|
stream_ptr += 6; /* skip the magic number */ |
|
|
|
|
num_chunks = AV_RL16(&buf[stream_ptr]); |
|
|
|
|
stream_ptr += 10; /* skip padding */ |
|
|
|
@ -179,13 +182,16 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
frame_size -= 16; |
|
|
|
|
|
|
|
|
|
/* iterate through the chunks */ |
|
|
|
|
while ((frame_size > 0) && (num_chunks > 0)) { |
|
|
|
|
while ((frame_size >= 6) && (num_chunks > 0)) { |
|
|
|
|
int stream_ptr_after_chunk; |
|
|
|
|
chunk_size = AV_RL32(&buf[stream_ptr]); |
|
|
|
|
if (chunk_size > frame_size) { |
|
|
|
|
av_log(avctx, AV_LOG_WARNING, |
|
|
|
|
"Invalid chunk_size = %u > frame_size = %u\n", chunk_size, frame_size); |
|
|
|
|
chunk_size = frame_size; |
|
|
|
|
} |
|
|
|
|
stream_ptr_after_chunk = stream_ptr + chunk_size; |
|
|
|
|
|
|
|
|
|
stream_ptr += 4; |
|
|
|
|
chunk_type = AV_RL16(&buf[stream_ptr]); |
|
|
|
|
stream_ptr += 2; |
|
|
|
@ -193,8 +199,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
switch (chunk_type) { |
|
|
|
|
case FLI_256_COLOR: |
|
|
|
|
case FLI_COLOR: |
|
|
|
|
stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6; |
|
|
|
|
|
|
|
|
|
/* check special case: If this file is from the Magic Carpet
|
|
|
|
|
* game and uses 6-bit colors even though it reports 256-color |
|
|
|
|
* chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during |
|
|
|
@ -218,6 +222,9 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
if (color_changes == 0) |
|
|
|
|
color_changes = 256; |
|
|
|
|
|
|
|
|
|
if (stream_ptr + color_changes * 3 > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
for (j = 0; j < color_changes; j++) { |
|
|
|
|
unsigned int entry; |
|
|
|
|
|
|
|
|
@ -234,13 +241,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
s->palette[palette_ptr++] = entry; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* color chunks sometimes have weird 16-bit alignment issues;
|
|
|
|
|
* therefore, take the hardline approach and set the stream_ptr |
|
|
|
|
* to the value calculated w.r.t. the size specified by the color |
|
|
|
|
* chunk header */ |
|
|
|
|
stream_ptr = stream_ptr_after_color_chunk; |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case FLI_DELTA: |
|
|
|
@ -248,6 +248,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
compressed_lines = AV_RL16(&buf[stream_ptr]); |
|
|
|
|
stream_ptr += 2; |
|
|
|
|
while (compressed_lines > 0) { |
|
|
|
|
if (stream_ptr + 2 > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
line_packets = AV_RL16(&buf[stream_ptr]); |
|
|
|
|
stream_ptr += 2; |
|
|
|
|
if ((line_packets & 0xC000) == 0xC000) { |
|
|
|
@ -267,6 +269,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
CHECK_PIXEL_PTR(0); |
|
|
|
|
pixel_countdown = s->avctx->width; |
|
|
|
|
for (i = 0; i < line_packets; i++) { |
|
|
|
|
if (stream_ptr + 2 > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
/* account for the skip bytes */ |
|
|
|
|
pixel_skip = buf[stream_ptr++]; |
|
|
|
|
pixel_ptr += pixel_skip; |
|
|
|
@ -283,6 +287,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
CHECK_PIXEL_PTR(byte_run * 2); |
|
|
|
|
if (stream_ptr + byte_run * 2 > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { |
|
|
|
|
palette_idx1 = buf[stream_ptr++]; |
|
|
|
|
pixels[pixel_ptr++] = palette_idx1; |
|
|
|
@ -309,6 +315,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
CHECK_PIXEL_PTR(0); |
|
|
|
|
pixel_countdown = s->avctx->width; |
|
|
|
|
line_packets = buf[stream_ptr++]; |
|
|
|
|
if (stream_ptr + 2 * line_packets > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
if (line_packets > 0) { |
|
|
|
|
for (i = 0; i < line_packets; i++) { |
|
|
|
|
/* account for the skip bytes */ |
|
|
|
@ -318,6 +326,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
byte_run = (signed char)(buf[stream_ptr++]); |
|
|
|
|
if (byte_run > 0) { |
|
|
|
|
CHECK_PIXEL_PTR(byte_run); |
|
|
|
|
if (stream_ptr + byte_run > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
for (j = 0; j < byte_run; j++, pixel_countdown--) { |
|
|
|
|
palette_idx1 = buf[stream_ptr++]; |
|
|
|
|
pixels[pixel_ptr++] = palette_idx1; |
|
|
|
@ -355,6 +365,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
stream_ptr++; |
|
|
|
|
pixel_countdown = s->avctx->width; |
|
|
|
|
while (pixel_countdown > 0) { |
|
|
|
|
if (stream_ptr + 1 > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
byte_run = (signed char)(buf[stream_ptr++]); |
|
|
|
|
if (byte_run > 0) { |
|
|
|
|
palette_idx1 = buf[stream_ptr++]; |
|
|
|
@ -369,6 +381,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
} else { /* copy bytes if byte_run < 0 */ |
|
|
|
|
byte_run = -byte_run; |
|
|
|
|
CHECK_PIXEL_PTR(byte_run); |
|
|
|
|
if (stream_ptr + byte_run > stream_ptr_after_chunk) |
|
|
|
|
break; |
|
|
|
|
for (j = 0; j < byte_run; j++) { |
|
|
|
|
palette_idx1 = buf[stream_ptr++]; |
|
|
|
|
pixels[pixel_ptr++] = palette_idx1; |
|
|
|
@ -386,10 +400,9 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
|
|
|
|
|
case FLI_COPY: |
|
|
|
|
/* copy the chunk (uncompressed frame) */ |
|
|
|
|
if (chunk_size - 6 > s->avctx->width * s->avctx->height) { |
|
|
|
|
if (chunk_size - 6 != s->avctx->width * s->avctx->height) { |
|
|
|
|
av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \
|
|
|
|
|
"bigger than image, skipping chunk\n", chunk_size - 6); |
|
|
|
|
stream_ptr += chunk_size - 6; |
|
|
|
|
"has incorrect size, skipping chunk\n", chunk_size - 6); |
|
|
|
|
} else { |
|
|
|
|
for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height; |
|
|
|
|
y_ptr += s->frame.linesize[0]) { |
|
|
|
@ -402,7 +415,6 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
|
|
|
|
|
case FLI_MINI: |
|
|
|
|
/* some sort of a thumbnail? disregard this chunk... */ |
|
|
|
|
stream_ptr += chunk_size - 6; |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
default: |
|
|
|
@ -410,6 +422,8 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stream_ptr = stream_ptr_after_chunk; |
|
|
|
|
|
|
|
|
|
frame_size -= chunk_size; |
|
|
|
|
num_chunks--; |
|
|
|
|
} |
|
|
|
|