123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /*
- * The Python Imaging Library.
- * $Id$
- *
- * decoder for Autodesk Animator FLI/FLC animations
- *
- * history:
- * 97-01-03 fl Created
- * 97-01-17 fl Added SS2 support (FLC)
- *
- * Copyright (c) Fredrik Lundh 1997.
- * Copyright (c) Secret Labs AB 1997.
- *
- * See the README file for information on usage and redistribution.
- */
- #include "Imaging.h"
- #define I16(ptr) ((ptr)[0] + ((ptr)[1] << 8))
- #define I32(ptr) ((ptr)[0] + ((ptr)[1] << 8) + ((ptr)[2] << 16) + ((ptr)[3] << 24))
- #define ERR_IF_DATA_OOB(offset) \
- if ((data + (offset)) > ptr + bytes) { \
- state->errcode = IMAGING_CODEC_OVERRUN; \
- return -1; \
- }
- int
- ImagingFliDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {
- UINT8 *ptr;
- int framesize;
- int c, chunks, advance;
- int l, lines;
- int i, j, x = 0, y, ymax;
- /* If not even the chunk size is present, we'd better leave */
- if (bytes < 4) {
- return 0;
- }
- /* We don't decode anything unless we have a full chunk in the
- input buffer */
- ptr = buf;
- framesize = I32(ptr);
- // there can be one pad byte in the framesize
- if (bytes + (bytes % 2) < framesize) {
- return 0;
- }
- /* Make sure this is a frame chunk. The Python driver takes
- case of other chunk types. */
- if (bytes < 8) {
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- if (I16(ptr + 4) != 0xF1FA) {
- state->errcode = IMAGING_CODEC_UNKNOWN;
- return -1;
- }
- chunks = I16(ptr + 6);
- ptr += 16;
- bytes -= 16;
- /* Process subchunks */
- for (c = 0; c < chunks; c++) {
- UINT8 *data;
- if (bytes < 10) {
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- data = ptr + 6;
- switch (I16(ptr + 4)) {
- case 4:
- case 11:
- /* FLI COLOR chunk */
- break; /* ignored; handled by Python code */
- case 7:
- /* FLI SS2 chunk (word delta) */
- /* OOB ok, we've got 4 bytes min on entry */
- lines = I16(data);
- data += 2;
- for (l = y = 0; l < lines && y < state->ysize; l++, y++) {
- UINT8 *local_buf = (UINT8 *)im->image[y];
- int p, packets;
- ERR_IF_DATA_OOB(2)
- packets = I16(data);
- data += 2;
- while (packets & 0x8000) {
- /* flag word */
- if (packets & 0x4000) {
- y += 65536 - packets; /* skip lines */
- if (y >= state->ysize) {
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- local_buf = (UINT8 *)im->image[y];
- } else {
- /* store last byte (used if line width is odd) */
- local_buf[state->xsize - 1] = (UINT8)packets;
- }
- ERR_IF_DATA_OOB(2)
- packets = I16(data);
- data += 2;
- }
- for (p = x = 0; p < packets; p++) {
- ERR_IF_DATA_OOB(2)
- x += data[0]; /* pixel skip */
- if (data[1] >= 128) {
- ERR_IF_DATA_OOB(4)
- i = 256 - data[1]; /* run */
- if (x + i + i > state->xsize) {
- break;
- }
- for (j = 0; j < i; j++) {
- local_buf[x++] = data[2];
- local_buf[x++] = data[3];
- }
- data += 2 + 2;
- } else {
- i = 2 * (int)data[1]; /* chunk */
- if (x + i > state->xsize) {
- break;
- }
- ERR_IF_DATA_OOB(2 + i)
- memcpy(local_buf + x, data + 2, i);
- data += 2 + i;
- x += i;
- }
- }
- if (p < packets) {
- break; /* didn't process all packets */
- }
- }
- if (l < lines) {
- /* didn't process all lines */
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- break;
- case 12:
- /* FLI LC chunk (byte delta) */
- /* OOB Check ok, we have 4 bytes min here */
- y = I16(data);
- ymax = y + I16(data + 2);
- data += 4;
- for (; y < ymax && y < state->ysize; y++) {
- UINT8 *out = (UINT8 *)im->image[y];
- ERR_IF_DATA_OOB(1)
- int p, packets = *data++;
- for (p = x = 0; p < packets; p++, x += i) {
- ERR_IF_DATA_OOB(2)
- x += data[0]; /* skip pixels */
- if (data[1] & 0x80) {
- i = 256 - data[1]; /* run */
- if (x + i > state->xsize) {
- break;
- }
- ERR_IF_DATA_OOB(3)
- memset(out + x, data[2], i);
- data += 3;
- } else {
- i = data[1]; /* chunk */
- if (x + i > state->xsize) {
- break;
- }
- ERR_IF_DATA_OOB(2 + i)
- memcpy(out + x, data + 2, i);
- data += i + 2;
- }
- }
- if (p < packets) {
- break; /* didn't process all packets */
- }
- }
- if (y < ymax) {
- /* didn't process all lines */
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- break;
- case 13:
- /* FLI BLACK chunk */
- for (y = 0; y < state->ysize; y++) {
- memset(im->image[y], 0, state->xsize);
- }
- break;
- case 15:
- /* FLI BRUN chunk */
- /* OOB, ok, we've got 4 bytes min on entry */
- for (y = 0; y < state->ysize; y++) {
- UINT8 *out = (UINT8 *)im->image[y];
- data += 1; /* ignore packetcount byte */
- for (x = 0; x < state->xsize; x += i) {
- ERR_IF_DATA_OOB(2)
- if (data[0] & 0x80) {
- i = 256 - data[0];
- if (x + i > state->xsize) {
- break; /* safety first */
- }
- ERR_IF_DATA_OOB(i + 1)
- memcpy(out + x, data + 1, i);
- data += i + 1;
- } else {
- i = data[0];
- if (x + i > state->xsize) {
- break; /* safety first */
- }
- memset(out + x, data[1], i);
- data += 2;
- }
- }
- if (x != state->xsize) {
- /* didn't unpack whole line */
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- }
- break;
- case 16:
- /* COPY chunk */
- if (INT32_MAX / state->xsize < state->ysize) {
- /* Integer overflow, bail */
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- /* Note, have to check Data + size, not just ptr + size) */
- if (data + (state->xsize * state->ysize) > ptr + bytes) {
- /* not enough data for frame */
- /* UNDONE Unclear that we're actually going to leave the buffer at the right place. */
- return ptr - buf; /* bytes consumed */
- }
- for (y = 0; y < state->ysize; y++) {
- UINT8 *local_buf = (UINT8 *)im->image[y];
- memcpy(local_buf, data, state->xsize);
- data += state->xsize;
- }
- break;
- case 18:
- /* PSTAMP chunk */
- break; /* ignored */
- default:
- /* unknown chunk */
- /* printf("unknown FLI/FLC chunk: %d\n", I16(ptr+4)); */
- state->errcode = IMAGING_CODEC_UNKNOWN;
- return -1;
- }
- advance = I32(ptr);
- if (advance == 0 ) {
- // If there's no advance, we're in an infinite loop
- state->errcode = IMAGING_CODEC_BROKEN;
- return -1;
- }
- if (advance < 0 || advance > bytes) {
- state->errcode = IMAGING_CODEC_OVERRUN;
- return -1;
- }
- ptr += advance;
- bytes -= advance;
- }
- return -1; /* end of frame */
- }
|