Pillow
290 строк · 8.0 Кб
1/*
2* The Python Imaging Library.
3* $Id$
4*
5* decoder for Sgi RLE data.
6*
7* history:
8* 2017-07-28 mb fixed for images larger than 64KB
9* 2017-07-20 mb created
10*
11* Copyright (c) Mickael Bonfill 2017.
12*
13* See the README file for information on usage and redistribution.
14*/
15
16#include "Imaging.h"17#include "Sgi.h"18
19#define SGI_HEADER_SIZE 51220#define RLE_COPY_FLAG 0x8021#define RLE_MAX_RUN 0x7f22
23static void24read4B(UINT32 *dest, UINT8 *buf) {25*dest = (UINT32)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);26}
27
28/*
29SgiRleDecoding is done in a single channel row oriented set of RLE chunks.
30
31* The file is arranged as
32- SGI Header
33- Rle Offset Table
34- Rle Length Table
35- Scanline Data
36
37* Each RLE atom is c->bpc bytes wide (1 or 2)
38
39* Each RLE Chunk is [specifier atom] [ 1 or n data atoms ]
40
41* Copy Atoms are a byte with the high bit set, and the low 7 are
42the number of bytes to copy from the source to the
43destination. e.g.
44
45CBBBBBBBB or 0CHLHLHLHLHLHL (B=byte, H/L = Hi low bytes)
46
47* Run atoms do not have the high bit set, and the low 7 bits are
48the number of copies of the next atom to copy to the
49destination. e.g.:
50
51RB -> BBBBB or RHL -> HLHLHLHLHL
52
53The upshot of this is, there is no way to determine the required
54length of the input buffer from reloffset and rlelength without
55going through the data at that scan line.
56
57Furthermore, there's no requirement that individual scan lines
58pointed to from the rleoffset table are in any sort of order or
59used only once, or even disjoint. There's also no requirement that
60all of the data in the scan line area of the image file be used
61
62*/
63static int64expandrow(UINT8 *dest, UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer) {65/*66* n here is the number of rlechunks
67* z is the number of channels, for calculating the interleave
68* offset to go to RGBA style pixels
69* xsize is the row width
70* end_of_buffer is the address of the end of the input buffer
71*/
72
73UINT8 pixel, count;74int x = 0;75
76for (; n > 0; n--) {77if (src > end_of_buffer) {78return -1;79}80pixel = *src++;81if (n == 1 && pixel != 0) {82return n;83}84count = pixel & RLE_MAX_RUN;85if (!count) {86return count;87}88if (x + count > xsize) {89return -1;90}91x += count;92if (pixel & RLE_COPY_FLAG) {93if (src + count > end_of_buffer) {94return -1;95}96while (count--) {97*dest = *src++;98dest += z;99}100
101} else {102if (src > end_of_buffer) {103return -1;104}105pixel = *src++;106while (count--) {107*dest = pixel;108dest += z;109}110}111}112return 0;113}
114
115static int116expandrow2(117UINT8 *dest, const UINT8 *src, int n, int z, int xsize, UINT8 *end_of_buffer118) {119UINT8 pixel, count;120int x = 0;121
122for (; n > 0; n--) {123if (src + 1 > end_of_buffer) {124return -1;125}126pixel = src[1];127src += 2;128if (n == 1 && pixel != 0) {129return n;130}131count = pixel & RLE_MAX_RUN;132if (!count) {133return count;134}135if (x + count > xsize) {136return -1;137}138x += count;139if (pixel & RLE_COPY_FLAG) {140if (src + 2 * count > end_of_buffer) {141return -1;142}143while (count--) {144memcpy(dest, src, 2);145src += 2;146dest += z * 2;147}148} else {149if (src + 2 > end_of_buffer) {150return -1;151}152while (count--) {153memcpy(dest, src, 2);154dest += z * 2;155}156src += 2;157}158}159return 0;160}
161
162int
163ImagingSgiRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) {164UINT8 *ptr;165SGISTATE *c;166int err = 0;167int status;168
169/* size check */170if (im->xsize > INT_MAX / im->bands || im->ysize > INT_MAX / im->bands) {171state->errcode = IMAGING_CODEC_MEMORY;172return -1;173}174
175/* Get all data from File descriptor */176c = (SGISTATE *)state->context;177_imaging_seek_pyFd(state->fd, 0L, SEEK_END);178c->bufsize = _imaging_tell_pyFd(state->fd);179c->bufsize -= SGI_HEADER_SIZE;180
181c->tablen = im->bands * im->ysize;182/* below, we populate the starttab and lentab into the bufsize,183each with 4 bytes per element of tablen
184Check here before we allocate any memory
185*/
186if (c->bufsize < 8 * c->tablen) {187state->errcode = IMAGING_CODEC_OVERRUN;188return -1;189}190
191ptr = malloc(sizeof(UINT8) * c->bufsize);192if (!ptr) {193state->errcode = IMAGING_CODEC_MEMORY;194return -1;195}196_imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);197if (_imaging_read_pyFd(state->fd, (char *)ptr, c->bufsize) != c->bufsize) {198state->errcode = IMAGING_CODEC_UNKNOWN;199return -1;200}201
202/* decoder initialization */203state->count = 0;204state->y = 0;205if (state->ystep < 0) {206state->y = im->ysize - 1;207} else {208state->ystep = 1;209}210
211/* Allocate memory for RLE tables and rows */212free(state->buffer);213state->buffer = NULL;214/* malloc overflow check above */215state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);216c->starttab = calloc(c->tablen, sizeof(UINT32));217c->lengthtab = calloc(c->tablen, sizeof(UINT32));218if (!state->buffer || !c->starttab || !c->lengthtab) {219err = IMAGING_CODEC_MEMORY;220goto sgi_finish_decode;221}222/* populate offsets table */223for (c->tabindex = 0, c->bufindex = 0; c->tabindex < c->tablen;224c->tabindex++, c->bufindex += 4) {225read4B(&c->starttab[c->tabindex], &ptr[c->bufindex]);226}227/* populate lengths table */228for (c->tabindex = 0, c->bufindex = c->tablen * sizeof(UINT32);229c->tabindex < c->tablen;230c->tabindex++, c->bufindex += 4) {231read4B(&c->lengthtab[c->tabindex], &ptr[c->bufindex]);232}233
234/* read compressed rows */235for (c->rowno = 0; c->rowno < im->ysize; c->rowno++, state->y += state->ystep) {236for (c->channo = 0; c->channo < im->bands; c->channo++) {237c->rleoffset = c->starttab[c->rowno + c->channo * im->ysize];238c->rlelength = c->lengthtab[c->rowno + c->channo * im->ysize];239
240// Check for underflow of rleoffset-SGI_HEADER_SIZE241if (c->rleoffset < SGI_HEADER_SIZE) {242state->errcode = IMAGING_CODEC_OVERRUN;243goto sgi_finish_decode;244}245
246c->rleoffset -= SGI_HEADER_SIZE;247
248/* row decompression */249if (c->bpc == 1) {250status = expandrow(251&state->buffer[c->channo],252&ptr[c->rleoffset],253c->rlelength,254im->bands,255im->xsize,256&ptr[c->bufsize - 1]257);258} else {259status = expandrow2(260&state->buffer[c->channo * 2],261&ptr[c->rleoffset],262c->rlelength,263im->bands,264im->xsize,265&ptr[c->bufsize - 1]266);267}268if (status == -1) {269state->errcode = IMAGING_CODEC_OVERRUN;270goto sgi_finish_decode;271} else if (status == 1) {272goto sgi_finish_decode;273}274}275
276/* store decompressed data in image */277state->shuffle((UINT8 *)im->image[state->y], state->buffer, im->xsize);278}279
280sgi_finish_decode:;281
282free(c->starttab);283free(c->lengthtab);284free(ptr);285if (err != 0) {286state->errcode = err;287return -1;288}289return 0;290}
291