Merge pull request #1781 from wiredfool/malloc_check

Integer overflow checks on malloc
This commit is contained in:
wiredfool 2016-06-21 12:09:19 +01:00 committed by GitHub
commit bdd0a6a4e4
21 changed files with 985 additions and 793 deletions

View File

@ -362,9 +362,20 @@ getbands(const char* mode)
#define TYPE_DOUBLE (0x400|sizeof(double)) #define TYPE_DOUBLE (0x400|sizeof(double))
static void* static void*
getlist(PyObject* arg, int* length, const char* wrong_length, int type) getlist(PyObject* arg, Py_ssize_t* length, const char* wrong_length, int type)
{ {
int i, n, itemp; /* - allocates and returns a c array of the items in the
python sequence arg.
- the size of the returned array is in length
- all of the arg items must be numeric items of the type
specified in type
- sequence length is checked against the length parameter IF
an error parameter is passed in wrong_length
- caller is responsible for freeing the memory
*/
Py_ssize_t i, n;
int itemp;
double dtemp; double dtemp;
void* list; void* list;
PyObject* seq; PyObject* seq;
@ -381,7 +392,9 @@ getlist(PyObject* arg, int* length, const char* wrong_length, int type)
return NULL; return NULL;
} }
list = malloc(n * (type & 0xff)); /* malloc check ok, type & ff is just a sizeof(something)
calloc checks for overflow */
list = calloc(n, type & 0xff);
if (!list) if (!list)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -845,7 +858,7 @@ static PyObject*
_filter(ImagingObject* self, PyObject* args) _filter(ImagingObject* self, PyObject* args)
{ {
PyObject* imOut; PyObject* imOut;
int kernelsize; Py_ssize_t kernelsize;
FLOAT32* kerneldata; FLOAT32* kerneldata;
int xsize, ysize; int xsize, ysize;
@ -859,7 +872,7 @@ _filter(ImagingObject* self, PyObject* args)
kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32); kerneldata = getlist(kernel, &kernelsize, NULL, TYPE_FLOAT32);
if (!kerneldata) if (!kerneldata)
return NULL; return NULL;
if (kernelsize != xsize * ysize) { if (kernelsize != (Py_ssize_t) xsize * (Py_ssize_t) ysize) {
free(kerneldata); free(kerneldata);
return ImagingError_ValueError("bad kernel size"); return ImagingError_ValueError("bad kernel size");
} }
@ -1148,8 +1161,8 @@ _point(ImagingObject* self, PyObject* args)
{ {
static const char* wrong_number = "wrong number of lut entries"; static const char* wrong_number = "wrong number of lut entries";
int n, i; Py_ssize_t n;
int bands; int i, bands;
Imaging im; Imaging im;
PyObject* list; PyObject* list;
@ -1614,7 +1627,7 @@ _transform2(ImagingObject* self, PyObject* args)
static const char* wrong_number = "wrong number of matrix entries"; static const char* wrong_number = "wrong number of matrix entries";
Imaging imOut; Imaging imOut;
int n; Py_ssize_t n;
double *a; double *a;
ImagingObject* imagep; ImagingObject* imagep;
@ -1849,6 +1862,7 @@ _getprojection(ImagingObject* self, PyObject* args)
unsigned char* yprofile; unsigned char* yprofile;
PyObject* result; PyObject* result;
/* malloc check ok */
xprofile = malloc(self->image->xsize); xprofile = malloc(self->image->xsize);
yprofile = malloc(self->image->ysize); yprofile = malloc(self->image->ysize);
@ -2295,7 +2309,7 @@ _draw_dealloc(ImagingDrawObject* self)
PyObject_Del(self); PyObject_Del(self);
} }
extern int PyPath_Flatten(PyObject* data, double **xy); extern Py_ssize_t PyPath_Flatten(PyObject* data, double **xy);
static PyObject* static PyObject*
_draw_ink(ImagingDrawObject* self, PyObject* args) _draw_ink(ImagingDrawObject* self, PyObject* args)
@ -2316,7 +2330,7 @@ static PyObject*
_draw_arc(ImagingDrawObject* self, PyObject* args) _draw_arc(ImagingDrawObject* self, PyObject* args)
{ {
double* xy; double* xy;
int n; Py_ssize_t n;
PyObject* data; PyObject* data;
int ink; int ink;
@ -2352,7 +2366,7 @@ static PyObject*
_draw_bitmap(ImagingDrawObject* self, PyObject* args) _draw_bitmap(ImagingDrawObject* self, PyObject* args)
{ {
double *xy; double *xy;
int n; Py_ssize_t n;
PyObject *data; PyObject *data;
ImagingObject* bitmap; ImagingObject* bitmap;
@ -2388,7 +2402,7 @@ static PyObject*
_draw_chord(ImagingDrawObject* self, PyObject* args) _draw_chord(ImagingDrawObject* self, PyObject* args)
{ {
double* xy; double* xy;
int n; Py_ssize_t n;
PyObject* data; PyObject* data;
int ink, fill; int ink, fill;
@ -2424,7 +2438,7 @@ static PyObject*
_draw_ellipse(ImagingDrawObject* self, PyObject* args) _draw_ellipse(ImagingDrawObject* self, PyObject* args)
{ {
double* xy; double* xy;
int n; Py_ssize_t n;
PyObject* data; PyObject* data;
int ink; int ink;
@ -2475,7 +2489,7 @@ static PyObject*
_draw_lines(ImagingDrawObject* self, PyObject* args) _draw_lines(ImagingDrawObject* self, PyObject* args)
{ {
double *xy; double *xy;
int i, n; Py_ssize_t i, n;
PyObject *data; PyObject *data;
int ink; int ink;
@ -2543,7 +2557,7 @@ static PyObject*
_draw_points(ImagingDrawObject* self, PyObject* args) _draw_points(ImagingDrawObject* self, PyObject* args)
{ {
double *xy; double *xy;
int i, n; Py_ssize_t i, n;
PyObject *data; PyObject *data;
int ink; int ink;
@ -2605,7 +2619,7 @@ static PyObject*
_draw_pieslice(ImagingDrawObject* self, PyObject* args) _draw_pieslice(ImagingDrawObject* self, PyObject* args)
{ {
double* xy; double* xy;
int n; Py_ssize_t n;
PyObject* data; PyObject* data;
int ink, fill; int ink, fill;
@ -2641,7 +2655,7 @@ _draw_polygon(ImagingDrawObject* self, PyObject* args)
{ {
double *xy; double *xy;
int *ixy; int *ixy;
int n, i; Py_ssize_t n, i;
PyObject* data; PyObject* data;
int ink; int ink;
@ -2660,7 +2674,7 @@ _draw_polygon(ImagingDrawObject* self, PyObject* args)
} }
/* Copy list of vertices to array */ /* Copy list of vertices to array */
ixy = (int*) malloc(n * 2 * sizeof(int)); ixy = (int*) calloc(n, 2 * sizeof(int));
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
ixy[i+i] = (int) xy[i+i]; ixy[i+i] = (int) xy[i+i];
@ -2685,7 +2699,7 @@ static PyObject*
_draw_rectangle(ImagingDrawObject* self, PyObject* args) _draw_rectangle(ImagingDrawObject* self, PyObject* args)
{ {
double* xy; double* xy;
int n; Py_ssize_t n;
PyObject* data; PyObject* data;
int ink; int ink;

View File

@ -188,8 +188,13 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args)
/* Allocate memory buffer (if bits field is set) */ /* Allocate memory buffer (if bits field is set) */
if (state->bits > 0) { if (state->bits > 0) {
if (!state->bytes) if (!state->bytes) {
if (state->xsize > ((INT_MAX / state->bits)-7)){
return PyErr_NoMemory();
}
state->bytes = (state->bits * state->xsize+7)/8; state->bytes = (state->bits * state->xsize+7)/8;
}
/* malloc check ok, oveflow checked above */
state->buffer = (UINT8*) malloc(state->bytes); state->buffer = (UINT8*) malloc(state->bytes);
if (!state->buffer) if (!state->buffer)
return PyErr_NoMemory(); return PyErr_NoMemory();

View File

@ -159,6 +159,7 @@ _encode_to_file(ImagingEncoderObject* encoder, PyObject* args)
return NULL; return NULL;
/* Allocate an encoder buffer */ /* Allocate an encoder buffer */
/* malloc check ok, either constant int, or checked by PyArg_ParseTuple */
buf = (UINT8*) malloc(bufsize); buf = (UINT8*) malloc(bufsize);
if (!buf) if (!buf)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -233,7 +234,11 @@ _setimage(ImagingEncoderObject* encoder, PyObject* args)
/* Allocate memory buffer (if bits field is set) */ /* Allocate memory buffer (if bits field is set) */
if (state->bits > 0) { if (state->bits > 0) {
if (state->xsize > ((INT_MAX / state->bits)-7)) {
return PyErr_NoMemory();
}
state->bytes = (state->bits * state->xsize+7)/8; state->bytes = (state->bits * state->xsize+7)/8;
/* malloc check ok, overflow checked above */
state->buffer = (UINT8*) malloc(state->bytes); state->buffer = (UINT8*) malloc(state->bytes);
if (!state->buffer) if (!state->buffer)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -478,10 +483,9 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
&dictionary, &dictionary_size)) &dictionary, &dictionary_size))
return NULL; return NULL;
/* Copy to avoid referencing Python's memory, but there's no mechanism to /* Copy to avoid referencing Python's memory */
free this memory later, so this function (and several others here)
leaks. */
if (dictionary && dictionary_size > 0) { if (dictionary && dictionary_size > 0) {
/* malloc check ok, size comes from PyArg_ParseTuple */
char* p = malloc(dictionary_size); char* p = malloc(dictionary_size);
if (!p) if (!p)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -498,6 +502,7 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args)
return NULL; return NULL;
encoder->encode = ImagingZipEncode; encoder->encode = ImagingZipEncode;
encoder->cleanup = ImagingZipEncodeCleanup;
if (rawmode[0] == 'P') if (rawmode[0] == 'P')
/* disable filtering */ /* disable filtering */
@ -559,6 +564,7 @@ static unsigned int* get_qtables_arrays(PyObject* qtables, int* qtablesLen) {
Py_DECREF(tables); Py_DECREF(tables);
return NULL; return NULL;
} }
/* malloc check ok, num_tables <4, DCTSIZE2 == 64 from jpeglib.h */
qarrays = (unsigned int*) malloc(num_tables * DCTSIZE2 * sizeof(unsigned int)); qarrays = (unsigned int*) malloc(num_tables * DCTSIZE2 * sizeof(unsigned int));
if (!qarrays) { if (!qarrays) {
Py_DECREF(tables); Py_DECREF(tables);
@ -631,9 +637,11 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
if (get_packer(encoder, mode, rawmode) < 0) if (get_packer(encoder, mode, rawmode) < 0)
return NULL; return NULL;
// Freed in JpegEncode, Case 5
qarrays = get_qtables_arrays(qtables, &qtablesLen); qarrays = get_qtables_arrays(qtables, &qtablesLen);
if (extra && extra_size > 0) { if (extra && extra_size > 0) {
/* malloc check ok, length is from python parsearg */
char* p = malloc(extra_size); // Freed in JpegEncode, Case 5 char* p = malloc(extra_size); // Freed in JpegEncode, Case 5
if (!p) if (!p)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -643,6 +651,7 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
extra = NULL; extra = NULL;
if (rawExif && rawExifLen > 0) { if (rawExif && rawExifLen > 0) {
/* malloc check ok, length is from python parsearg */
char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5 char* pp = malloc(rawExifLen); // Freed in JpegEncode, Case 5
if (!pp) if (!pp)
return PyErr_NoMemory(); return PyErr_NoMemory();
@ -757,15 +766,16 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
(ttag_t) PyInt_AsLong(key), (ttag_t) PyInt_AsLong(key),
PyBytes_AsString(value)); PyBytes_AsString(value));
} else if (PyTuple_Check(value)) { } else if (PyTuple_Check(value)) {
int len,i; Py_ssize_t len,i;
float *floatav; float *floatav;
int *intav; int *intav;
TRACE(("Setting from Tuple: %d \n", (int)PyInt_AsLong(key))); TRACE(("Setting from Tuple: %d \n", (int)PyInt_AsLong(key)));
len = (int)PyTuple_Size(value); len = PyTuple_Size(value);
if (len) { if (len) {
if (PyInt_Check(PyTuple_GetItem(value,0))) { if (PyInt_Check(PyTuple_GetItem(value,0))) {
TRACE((" %d elements, setting as ints \n", len)); TRACE((" %d elements, setting as ints \n", (int)len));
intav = malloc(sizeof(int)*len); /* malloc check ok, calloc checks for overflow */
intav = calloc(len, sizeof(int));
if (intav) { if (intav) {
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
intav[i] = (int)PyInt_AsLong(PyTuple_GetItem(value,i)); intav[i] = (int)PyInt_AsLong(PyTuple_GetItem(value,i));
@ -776,8 +786,9 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
free(intav); free(intav);
} }
} else if (PyFloat_Check(PyTuple_GetItem(value,0))) { } else if (PyFloat_Check(PyTuple_GetItem(value,0))) {
TRACE((" %d elements, setting as floats \n", len)); TRACE((" %d elements, setting as floats \n", (int)len));
floatav = malloc(sizeof(float)*len); /* malloc check ok, calloc checks for overflow */
floatav = calloc(len, sizeof(float));
if (floatav) { if (floatav) {
for (i=0;i<len;i++) { for (i=0;i<len;i++) {
floatav[i] = (float)PyFloat_AsDouble(PyTuple_GetItem(value,i)); floatav[i] = (float)PyFloat_AsDouble(PyTuple_GetItem(value,i));

View File

@ -39,14 +39,14 @@ ImagingGetModeDIB(int size_out[2])
mode = "P"; mode = "P";
if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) { if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) {
mode = "RGB"; mode = "RGB";
if (GetDeviceCaps(dc, BITSPIXEL) == 1) if (GetDeviceCaps(dc, BITSPIXEL) == 1)
mode = "1"; mode = "1";
} }
if (size_out) { if (size_out) {
size_out[0] = GetDeviceCaps(dc, HORZRES); size_out[0] = GetDeviceCaps(dc, HORZRES);
size_out[1] = GetDeviceCaps(dc, VERTRES); size_out[1] = GetDeviceCaps(dc, VERTRES);
} }
DeleteDC(dc); DeleteDC(dc);
@ -66,18 +66,20 @@ ImagingNewDIB(const char *mode, int xsize, int ysize)
/* Check mode */ /* Check mode */
if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 && if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 &&
strcmp(mode, "RGB") != 0) strcmp(mode, "RGB") != 0)
return (ImagingDIB) ImagingError_ModeError(); return (ImagingDIB) ImagingError_ModeError();
/* Create DIB context and info header */ /* Create DIB context and info header */
/* malloc check ok, small constant allocation */
dib = (ImagingDIB) malloc(sizeof(*dib)); dib = (ImagingDIB) malloc(sizeof(*dib));
if (!dib) if (!dib)
return (ImagingDIB) ImagingError_MemoryError(); return (ImagingDIB) ImagingError_MemoryError();
/* malloc check ok, small constant allocation */
dib->info = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) + dib->info = (BITMAPINFO*) malloc(sizeof(BITMAPINFOHEADER) +
256 * sizeof(RGBQUAD)); 256 * sizeof(RGBQUAD));
if (!dib->info) { if (!dib->info) {
free(dib); free(dib);
return (ImagingDIB) ImagingError_MemoryError(); return (ImagingDIB) ImagingError_MemoryError();
} }
memset(dib->info, 0, sizeof(BITMAPINFOHEADER)); memset(dib->info, 0, sizeof(BITMAPINFOHEADER));
@ -91,17 +93,17 @@ ImagingNewDIB(const char *mode, int xsize, int ysize)
/* Create DIB */ /* Create DIB */
dib->dc = CreateCompatibleDC(NULL); dib->dc = CreateCompatibleDC(NULL);
if (!dib->dc) { if (!dib->dc) {
free(dib->info); free(dib->info);
free(dib); free(dib);
return (ImagingDIB) ImagingError_MemoryError(); return (ImagingDIB) ImagingError_MemoryError();
} }
dib->bitmap = CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS, dib->bitmap = CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS,
&dib->bits, NULL, 0); &dib->bits, NULL, 0);
if (!dib->bitmap) { if (!dib->bitmap) {
free(dib->info); free(dib->info);
free(dib); free(dib);
return (ImagingDIB) ImagingError_MemoryError(); return (ImagingDIB) ImagingError_MemoryError();
} }
strcpy(dib->mode, mode); strcpy(dib->mode, mode);
@ -112,10 +114,10 @@ ImagingNewDIB(const char *mode, int xsize, int ysize)
dib->linesize = (xsize * dib->pixelsize + 3) & -4; dib->linesize = (xsize * dib->pixelsize + 3) & -4;
if (dib->pixelsize == 1) if (dib->pixelsize == 1)
dib->pack = dib->unpack = (ImagingShuffler) memcpy; dib->pack = dib->unpack = (ImagingShuffler) memcpy;
else { else {
dib->pack = ImagingPackBGR; dib->pack = ImagingPackBGR;
dib->unpack = ImagingPackBGR; dib->unpack = ImagingPackBGR;
} }
/* Bind the DIB to the device context */ /* Bind the DIB to the device context */
@ -125,88 +127,88 @@ ImagingNewDIB(const char *mode, int xsize, int ysize)
/* Bind a palette to it as well (only required for 8-bit DIBs) */ /* Bind a palette to it as well (only required for 8-bit DIBs) */
if (dib->pixelsize == 1) { if (dib->pixelsize == 1) {
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
palette[i].rgbRed = palette[i].rgbRed =
palette[i].rgbGreen = palette[i].rgbGreen =
palette[i].rgbBlue = i; palette[i].rgbBlue = i;
palette[i].rgbReserved = 0; palette[i].rgbReserved = 0;
} }
SetDIBColorTable(dib->dc, 0, 256, palette); SetDIBColorTable(dib->dc, 0, 256, palette);
} }
/* Create an associated palette (for 8-bit displays only) */ /* Create an associated palette (for 8-bit displays only) */
if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) { if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) {
char palbuf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)]; char palbuf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
LPLOGPALETTE pal = (LPLOGPALETTE) palbuf; LPLOGPALETTE pal = (LPLOGPALETTE) palbuf;
int i, r, g, b; int i, r, g, b;
/* Load system palette */ /* Load system palette */
pal->palVersion = 0x300; pal->palVersion = 0x300;
pal->palNumEntries = 256; pal->palNumEntries = 256;
GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry); GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);
if (strcmp(mode, "L") == 0) { if (strcmp(mode, "L") == 0) {
/* Greyscale DIB. Fill all 236 slots with a greyscale ramp /* Greyscale DIB. Fill all 236 slots with a greyscale ramp
* (this is usually overkill on Windows since VGA only offers * (this is usually overkill on Windows since VGA only offers
* 6 bits greyscale resolution). Ignore the slots already * 6 bits greyscale resolution). Ignore the slots already
* allocated by Windows */ * allocated by Windows */
i = 10; i = 10;
for (r = 0; r < 236; r++) { for (r = 0; r < 236; r++) {
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peRed =
pal->palPalEntry[i].peGreen = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = i; pal->palPalEntry[i].peBlue = i;
i++; i++;
} }
dib->palette = CreatePalette(pal); dib->palette = CreatePalette(pal);
} else if (strcmp(mode, "RGB") == 0) { } else if (strcmp(mode, "RGB") == 0) {
#ifdef CUBE216 #ifdef CUBE216
/* Colour DIB. Create a 6x6x6 colour cube (216 entries) and /* Colour DIB. Create a 6x6x6 colour cube (216 entries) and
* add 20 extra greylevels for best result with greyscale * add 20 extra greylevels for best result with greyscale
* images. */ * images. */
i = 10; i = 10;
for (r = 0; r < 256; r += 51) for (r = 0; r < 256; r += 51)
for (g = 0; g < 256; g += 51) for (g = 0; g < 256; g += 51)
for (b = 0; b < 256; b += 51) { for (b = 0; b < 256; b += 51) {
pal->palPalEntry[i].peRed = r; pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g; pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b; pal->palPalEntry[i].peBlue = b;
i++; i++;
} }
for (r = 1; r < 22-1; r++) { for (r = 1; r < 22-1; r++) {
/* Black and white are already provided by the cube. */ /* Black and white are already provided by the cube. */
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peRed =
pal->palPalEntry[i].peGreen = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = r * 255 / (22-1); pal->palPalEntry[i].peBlue = r * 255 / (22-1);
i++; i++;
} }
#else #else
/* Colour DIB. Alternate palette. */ /* Colour DIB. Alternate palette. */
i = 10; i = 10;
for (r = 0; r < 256; r += 37) for (r = 0; r < 256; r += 37)
for (g = 0; g < 256; g += 32) for (g = 0; g < 256; g += 32)
for (b = 0; b < 256; b += 64) { for (b = 0; b < 256; b += 64) {
pal->palPalEntry[i].peRed = r; pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g; pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b; pal->palPalEntry[i].peBlue = b;
i++; i++;
} }
#endif #endif
dib->palette = CreatePalette(pal); dib->palette = CreatePalette(pal);
} }
} }
@ -222,8 +224,8 @@ ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4])
int y; int y;
for (y = 0; y < im->ysize; y++) for (y = 0; y < im->ysize; y++)
dib->pack(dib->bits + dib->linesize*(dib->ysize-(xy[1]+y)-1) + dib->pack(dib->bits + dib->linesize*(dib->ysize-(xy[1]+y)-1) +
xy[0]*dib->pixelsize, im->image[y], im->xsize); xy[0]*dib->pixelsize, im->image[y], im->xsize);
} }
@ -233,7 +235,7 @@ ImagingExposeDIB(ImagingDIB dib, void *dc)
/* Copy bitmap to display */ /* Copy bitmap to display */
if (dib->palette != 0) if (dib->palette != 0)
SelectPalette((HDC) dc, dib->palette, FALSE); SelectPalette((HDC) dc, dib->palette, FALSE);
BitBlt((HDC) dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY); BitBlt((HDC) dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY);
} }
@ -266,15 +268,15 @@ ImagingQueryPaletteDIB(ImagingDIB dib, void *dc)
if (dib->palette != 0) { if (dib->palette != 0) {
/* Realize associated palette */ /* Realize associated palette */
HPALETTE now = SelectPalette((HDC) dc, dib->palette, FALSE); HPALETTE now = SelectPalette((HDC) dc, dib->palette, FALSE);
n = RealizePalette((HDC) dc); n = RealizePalette((HDC) dc);
/* Restore palette */ /* Restore palette */
SelectPalette((HDC) dc, now, FALSE); SelectPalette((HDC) dc, now, FALSE);
} else } else
n = 0; n = 0;
return n; /* number of colours that was changed */ return n; /* number of colours that was changed */
} }
@ -285,13 +287,13 @@ ImagingDeleteDIB(ImagingDIB dib)
/* Clean up */ /* Clean up */
if (dib->palette) if (dib->palette)
DeleteObject(dib->palette); DeleteObject(dib->palette);
if (dib->bitmap) { if (dib->bitmap) {
SelectObject(dib->dc, dib->old_bitmap); SelectObject(dib->dc, dib->old_bitmap);
DeleteObject(dib->bitmap); DeleteObject(dib->bitmap);
} }
if (dib->dc) if (dib->dc)
DeleteDC(dib->dc); DeleteDC(dib->dc);
free(dib->info); free(dib->info);
} }

View File

@ -434,7 +434,8 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill,
} }
/* Initialize the edge table and find polygon boundaries */ /* Initialize the edge table and find polygon boundaries */
edge_table = malloc(sizeof(Edge*) * n); /* malloc check ok, using calloc */
edge_table = calloc(n, sizeof(Edge*));
if (!edge_table) { if (!edge_table) {
return -1; return -1;
} }
@ -462,7 +463,8 @@ polygon_generic(Imaging im, int n, Edge *e, int ink, int eofill,
} }
/* Process the edge table with a scan line searching for intersections */ /* Process the edge table with a scan line searching for intersections */
xx = malloc(sizeof(float) * edge_count * 2); /* malloc check ok, using calloc */
xx = calloc(edge_count * 2, sizeof(float));
if (!xx) { if (!xx) {
free(edge_table); free(edge_table);
return -1; return -1;
@ -700,7 +702,8 @@ ImagingDrawPolygon(Imaging im, int count, int* xy, const void* ink_,
if (fill) { if (fill) {
/* Build edge list */ /* Build edge list */
Edge* e = malloc(count * sizeof(Edge)); /* malloc check ok, using calloc */
Edge* e = calloc(count, sizeof(Edge));
if (!e) { if (!e) {
(void) ImagingError_MemoryError(); (void) ImagingError_MemoryError();
return -1; return -1;
@ -769,10 +772,16 @@ ellipse(Imaging im, int x0, int y0, int x1, int y1,
while (end < start) while (end < start)
end += 360; end += 360;
if (end - start > 360) {
/* no need to go in loops */
end = start + 361;
}
if (mode != ARC && fill) { if (mode != ARC && fill) {
/* Build edge list */ /* Build edge list */
Edge* e = malloc((end - start + 3) * sizeof(Edge)); /* malloc check UNDONE, FLOAT? */
Edge* e = calloc((end - start + 3), sizeof(Edge));
if (!e) { if (!e) {
ImagingError_MemoryError(); ImagingError_MemoryError();
return -1; return -1;
@ -929,10 +938,16 @@ allocate(ImagingOutline outline, int extra)
if (outline->count + extra > outline->size) { if (outline->count + extra > outline->size) {
/* expand outline buffer */ /* expand outline buffer */
outline->size += extra + 25; outline->size += extra + 25;
if (!outline->edges) if (!outline->edges) {
e = malloc(outline->size * sizeof(Edge)); /* malloc check ok, uses calloc for overflow */
else e = calloc(outline->size, sizeof(Edge));
} else {
if (outline->size > INT_MAX / sizeof(Edge)) {
return NULL;
}
/* malloc check ok, overflow checked above */
e = realloc(outline->edges, outline->size * sizeof(Edge)); e = realloc(outline->edges, outline->size * sizeof(Edge));
}
if (!e) if (!e)
return NULL; return NULL;
outline->edges = e; outline->edges = e;

View File

@ -684,7 +684,8 @@ ImagingScaleAffine(Imaging imOut, Imaging imIn,
if (y1 > imOut->ysize) if (y1 > imOut->ysize)
y1 = imOut->ysize; y1 = imOut->ysize;
xintab = (int*) malloc(imOut->xsize * sizeof(int)); /* malloc check ok, uses calloc for overflow */
xintab = (int*) calloc(imOut->xsize, sizeof(int));
if (!xintab) { if (!xintab) {
ImagingDelete(imOut); ImagingDelete(imOut);
return (Imaging) ImagingError_MemoryError(); return (Imaging) ImagingError_MemoryError();

View File

@ -61,6 +61,7 @@ emit(GIFENCODERSTATE *context, int byte)
block = context->free; block = context->free;
context->free = NULL; context->free = NULL;
} else { } else {
/* malloc check ok, small constant allocation */
block = malloc(sizeof(GIFENCODERBLOCK)); block = malloc(sizeof(GIFENCODERBLOCK));
if (!block) if (!block)
return 0; return 0;

View File

@ -168,9 +168,9 @@ extern Imaging ImagingNewMap(const char* filename, int readonly,
const char* mode, int xsize, int ysize); const char* mode, int xsize, int ysize);
extern Imaging ImagingNewPrologue(const char *mode, extern Imaging ImagingNewPrologue(const char *mode,
unsigned xsize, unsigned ysize); int xsize, int ysize);
extern Imaging ImagingNewPrologueSubtype(const char *mode, extern Imaging ImagingNewPrologueSubtype(const char *mode,
unsigned xsize, unsigned ysize, int xsize, int ysize,
int structure_size); int structure_size);
extern Imaging ImagingNewEpilogue(Imaging im); extern Imaging ImagingNewEpilogue(Imaging im);
@ -453,6 +453,7 @@ extern int ImagingZipDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingZipEncode(Imaging im, ImagingCodecState state, extern int ImagingZipEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingZipEncodeCleanup(ImagingCodecState state);
#endif #endif
typedef void (*ImagingShuffler)(UINT8* out, const UINT8* in, int pixels); typedef void (*ImagingShuffler)(UINT8* out, const UINT8* in, int pixels);

View File

@ -168,6 +168,7 @@ ImagingIncrementalCodecCreate(ImagingIncrementalCodecEntry codec_entry,
int seekable, int seekable,
int fd) int fd)
{ {
/* malloc check ok, small constant allocation */
ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct)); ImagingIncrementalCodec codec = (ImagingIncrementalCodec)malloc(sizeof(struct ImagingIncrementalCodecStruct));
codec->entry = codec_entry; codec->entry = codec_entry;
@ -370,7 +371,17 @@ ImagingIncrementalCodecPushBuffer(ImagingIncrementalCodec codec,
/* In this specific case, we append to a buffer we allocate ourselves */ /* In this specific case, we append to a buffer we allocate ourselves */
size_t old_size = codec->stream.end - codec->stream.buffer; size_t old_size = codec->stream.end - codec->stream.buffer;
size_t new_size = codec->stream.end - codec->stream.buffer + bytes; size_t new_size = codec->stream.end - codec->stream.buffer + bytes;
UINT8 *new = (UINT8 *)realloc (codec->stream.buffer, new_size); UINT8 *new;
if (old_size > SIZE_MAX - bytes) {
codec->state->errcode = IMAGING_CODEC_MEMORY;
#ifndef _WIN32
pthread_mutex_unlock(&codec->data_mutex);
#endif
return -1;
}
/* malloc check ok, overflow checked */
new = (UINT8 *)realloc (codec->stream.buffer, new_size);
if (!new) { if (!new) {
codec->state->errcode = IMAGING_CODEC_MEMORY; codec->state->errcode = IMAGING_CODEC_MEMORY;

View File

@ -702,6 +702,7 @@ j2k_decode_entry(Imaging im, ImagingCodecState state,
tile_info.y1 = (tile_info.y1 + correction) >> context->reduce; tile_info.y1 = (tile_info.y1 + correction) >> context->reduce;
if (buffer_size < tile_info.data_size) { if (buffer_size < tile_info.data_size) {
/* malloc check ok, tile_info.data_size from openjpeg */
UINT8 *new = realloc (state->buffer, tile_info.data_size); UINT8 *new = realloc (state->buffer, tile_info.data_size);
if (!new) { if (!new) {
state->errcode = IMAGING_CODEC_MEMORY; state->errcode = IMAGING_CODEC_MEMORY;

View File

@ -31,20 +31,20 @@ ImagingPaletteNew(const char* mode)
ImagingPalette palette; ImagingPalette palette;
if (strcmp(mode, "RGB") && strcmp(mode, "RGBA")) if (strcmp(mode, "RGB") && strcmp(mode, "RGBA"))
return (ImagingPalette) ImagingError_ModeError(); return (ImagingPalette) ImagingError_ModeError();
palette = calloc(1, sizeof(struct ImagingPaletteInstance)); palette = calloc(1, sizeof(struct ImagingPaletteInstance));
if (!palette) if (!palette)
return (ImagingPalette) ImagingError_MemoryError(); return (ImagingPalette) ImagingError_MemoryError();
strncpy(palette->mode, mode, IMAGING_MODE_LENGTH); strncpy(palette->mode, mode, IMAGING_MODE_LENGTH);
/* Initialize to ramp */ /* Initialize to ramp */
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
palette->palette[i*4+0] = palette->palette[i*4+0] =
palette->palette[i*4+1] = palette->palette[i*4+1] =
palette->palette[i*4+2] = (UINT8) i; palette->palette[i*4+2] = (UINT8) i;
palette->palette[i*4+3] = 255; /* opaque */ palette->palette[i*4+3] = 255; /* opaque */
} }
return palette; return palette;
@ -60,35 +60,35 @@ ImagingPaletteNewBrowser(void)
palette = ImagingPaletteNew("RGB"); palette = ImagingPaletteNew("RGB");
if (!palette) if (!palette)
return NULL; return NULL;
/* Blank out unused entries */ /* Blank out unused entries */
/* FIXME: Add 10-level windows palette here? */ /* FIXME: Add 10-level windows palette here? */
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
palette->palette[i*4+0] = palette->palette[i*4+0] =
palette->palette[i*4+1] = palette->palette[i*4+1] =
palette->palette[i*4+2] = 0; palette->palette[i*4+2] = 0;
} }
/* Simple 6x6x6 colour cube */ /* Simple 6x6x6 colour cube */
for (b = 0; b < 256; b += 51) for (b = 0; b < 256; b += 51)
for (g = 0; g < 256; g += 51) for (g = 0; g < 256; g += 51)
for (r = 0; r < 256; r += 51) { for (r = 0; r < 256; r += 51) {
palette->palette[i*4+0] = r; palette->palette[i*4+0] = r;
palette->palette[i*4+1] = g; palette->palette[i*4+1] = g;
palette->palette[i*4+2] = b; palette->palette[i*4+2] = b;
i++; i++;
} }
/* Blank out unused entries */ /* Blank out unused entries */
/* FIXME: add 30-level greyscale wedge here? */ /* FIXME: add 30-level greyscale wedge here? */
for (; i < 256; i++) { for (; i < 256; i++) {
palette->palette[i*4+0] = palette->palette[i*4+0] =
palette->palette[i*4+1] = palette->palette[i*4+1] =
palette->palette[i*4+2] = 0; palette->palette[i*4+2] = 0;
} }
return palette; return palette;
@ -102,11 +102,11 @@ ImagingPaletteDuplicate(ImagingPalette palette)
ImagingPalette new_palette; ImagingPalette new_palette;
if (!palette) if (!palette)
return NULL; return NULL;
/* malloc check ok, small constant allocation */
new_palette = malloc(sizeof(struct ImagingPaletteInstance)); new_palette = malloc(sizeof(struct ImagingPaletteInstance));
if (!new_palette) if (!new_palette)
return (ImagingPalette) ImagingError_MemoryError(); return (ImagingPalette) ImagingError_MemoryError();
memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance)); memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance));
@ -122,15 +122,15 @@ ImagingPaletteDelete(ImagingPalette palette)
/* Destroy palette object */ /* Destroy palette object */
if (palette) { if (palette) {
if (palette->cache) if (palette->cache)
free(palette->cache); free(palette->cache);
free(palette); free(palette);
} }
} }
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Colour mapping */ /* Colour mapping */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* This code is used to map RGB triplets to palette indices, using /* This code is used to map RGB triplets to palette indices, using
@ -143,26 +143,26 @@ ImagingPaletteDelete(ImagingPalette palette)
* *
* The IJG JPEG library is copyright (C) 1991-1995, Thomas G. Lane. */ * The IJG JPEG library is copyright (C) 1991-1995, Thomas G. Lane. */
#define DIST(a, b, s) (a - b) * (a - b) * s #define DIST(a, b, s) (a - b) * (a - b) * s
/* Colour weights (no scaling, for now) */ /* Colour weights (no scaling, for now) */
#define RSCALE 1 #define RSCALE 1
#define GSCALE 1 #define GSCALE 1
#define BSCALE 1 #define BSCALE 1
/* Calculated scaled distances */ /* Calculated scaled distances */
#define RDIST(a, b) DIST(a, b, RSCALE*RSCALE) #define RDIST(a, b) DIST(a, b, RSCALE*RSCALE)
#define GDIST(a, b) DIST(a, b, GSCALE*GSCALE) #define GDIST(a, b) DIST(a, b, GSCALE*GSCALE)
#define BDIST(a, b) DIST(a, b, BSCALE*BSCALE) #define BDIST(a, b) DIST(a, b, BSCALE*BSCALE)
/* Incremental steps */ /* Incremental steps */
#define RSTEP (4 * RSCALE) #define RSTEP (4 * RSCALE)
#define GSTEP (4 * GSCALE) #define GSTEP (4 * GSCALE)
#define BSTEP (4 * BSCALE) #define BSTEP (4 * BSCALE)
#define BOX 8 #define BOX 8
#define BOXVOLUME BOX*BOX*BOX #define BOXVOLUME BOX*BOX*BOX
void void
ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b)
@ -191,25 +191,25 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b)
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
int r, g, b; int r, g, b;
unsigned int tmin, tmax; unsigned int tmin, tmax;
/* Find min and max distances to any point in the box */ /* Find min and max distances to any point in the box */
r = palette->palette[i*4+0]; r = palette->palette[i*4+0];
tmin = (r < r0) ? RDIST(r, r1) : (r > r1) ? RDIST(r, r0) : 0; tmin = (r < r0) ? RDIST(r, r1) : (r > r1) ? RDIST(r, r0) : 0;
tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0); tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0);
g = palette->palette[i*4+1]; g = palette->palette[i*4+1];
tmin += (g < g0) ? GDIST(g, g1) : (g > g1) ? GDIST(g, g0) : 0; tmin += (g < g0) ? GDIST(g, g1) : (g > g1) ? GDIST(g, g0) : 0;
tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0); tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0);
b = palette->palette[i*4+2]; b = palette->palette[i*4+2];
tmin += (b < b0) ? BDIST(b, b1) : (b > b1) ? BDIST(b, b0) : 0; tmin += (b < b0) ? BDIST(b, b1) : (b > b1) ? BDIST(b, b0) : 0;
tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0); tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0);
dmin[i] = tmin; dmin[i] = tmin;
if (tmax < dmax) if (tmax < dmax)
dmax = tmax; /* keep the smallest max distance only */ dmax = tmax; /* keep the smallest max distance only */
} }
@ -220,47 +220,47 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b)
* distance is less than or equal the smallest max distance */ * distance is less than or equal the smallest max distance */
for (i = 0; i < BOXVOLUME; i++) for (i = 0; i < BOXVOLUME; i++)
d[i] = (unsigned int) ~0; d[i] = (unsigned int) ~0;
for (i = 0; i < 256; i++) for (i = 0; i < 256; i++)
if (dmin[i] <= dmax) { if (dmin[i] <= dmax) {
int rd, gd, bd; int rd, gd, bd;
int ri, gi, bi; int ri, gi, bi;
int rx, gx, bx; int rx, gx, bx;
ri = (r0 - palette->palette[i*4+0]) * RSCALE; ri = (r0 - palette->palette[i*4+0]) * RSCALE;
gi = (g0 - palette->palette[i*4+1]) * GSCALE; gi = (g0 - palette->palette[i*4+1]) * GSCALE;
bi = (b0 - palette->palette[i*4+2]) * BSCALE; bi = (b0 - palette->palette[i*4+2]) * BSCALE;
rd = ri*ri + gi*gi + bi*bi; rd = ri*ri + gi*gi + bi*bi;
ri = ri * (2 * RSTEP) + RSTEP * RSTEP; ri = ri * (2 * RSTEP) + RSTEP * RSTEP;
gi = gi * (2 * GSTEP) + GSTEP * GSTEP; gi = gi * (2 * GSTEP) + GSTEP * GSTEP;
bi = bi * (2 * BSTEP) + BSTEP * BSTEP; bi = bi * (2 * BSTEP) + BSTEP * BSTEP;
rx = ri; rx = ri;
for (r = j = 0; r < BOX; r++) { for (r = j = 0; r < BOX; r++) {
gd = rd; gx = gi; gd = rd; gx = gi;
for (g = 0; g < BOX; g++) { for (g = 0; g < BOX; g++) {
bd = gd; bx = bi; bd = gd; bx = bi;
for (b = 0; b < BOX; b++) { for (b = 0; b < BOX; b++) {
if ((unsigned int) bd < d[j]) { if ((unsigned int) bd < d[j]) {
d[j] = bd; d[j] = bd;
c[j] = (UINT8) i; c[j] = (UINT8) i;
} }
bd += bx; bd += bx;
bx += 2 * BSTEP * BSTEP; bx += 2 * BSTEP * BSTEP;
j++; j++;
} }
gd += gx; gd += gx;
gx += 2 * GSTEP * GSTEP; gx += 2 * GSTEP * GSTEP;
} }
rd += rx; rd += rx;
rx += 2 * RSTEP * RSTEP; rx += 2 * RSTEP * RSTEP;
} }
} }
/* Step 3 -- Update cache */ /* Step 3 -- Update cache */
@ -269,9 +269,9 @@ ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b)
j = 0; j = 0;
for (r = r0; r < r1; r+=4) for (r = r0; r < r1; r+=4)
for (g = g0; g < g1; g+=4) for (g = g0; g < g1; g+=4)
for (b = b0; b < b1; b+=4) for (b = b0; b < b1; b+=4)
ImagingPaletteCache(palette, r, g, b) = c[j++]; ImagingPaletteCache(palette, r, g, b) = c[j++];
} }
@ -285,18 +285,19 @@ ImagingPaletteCachePrepare(ImagingPalette palette)
if (palette->cache == NULL) { if (palette->cache == NULL) {
/* The cache is 512k. It might be a good idea to break it /* The cache is 512k. It might be a good idea to break it
up into a pointer array (e.g. an 8-bit image?) */ up into a pointer array (e.g. an 8-bit image?) */
palette->cache = (INT16*) malloc(entries * sizeof(INT16)); /* malloc check ok, small constant allocation */
if (!palette->cache) { palette->cache = (INT16*) malloc(entries * sizeof(INT16));
(void) ImagingError_MemoryError(); if (!palette->cache) {
return -1; (void) ImagingError_MemoryError();
} return -1;
}
/* Mark all entries as empty */ /* Mark all entries as empty */
for (i = 0; i < entries; i++) for (i = 0; i < entries; i++)
palette->cache[i] = 0x100; palette->cache[i] = 0x100;
} }
@ -310,7 +311,7 @@ ImagingPaletteCacheDelete(ImagingPalette palette)
/* Release the colour cache, if any */ /* Release the colour cache, if any */
if (palette && palette->cache) { if (palette && palette->cache) {
free(palette->cache); free(palette->cache);
palette->cache = NULL; palette->cache = NULL;
} }
} }

View File

@ -31,6 +31,11 @@
#include "QuantHash.h" #include "QuantHash.h"
#include "QuantHeap.h" #include "QuantHeap.h"
/* MSVC9.0 */
#ifndef UINT32_MAX
#define UINT32_MAX 0xffffffff
#endif
#define NO_OUTPUT #define NO_OUTPUT
typedef struct { typedef struct {
@ -150,6 +155,7 @@ create_pixel_hash(Pixel *pixelData,uint32_t nPixels)
uint32_t timer,timer2,timer3; uint32_t timer,timer2,timer3;
#endif #endif
/* malloc check ok, small constant allocation */
d=malloc(sizeof(PixelHashData)); d=malloc(sizeof(PixelHashData));
if (!d) return NULL; if (!d) return NULL;
hash=hashtable_new(pixel_hash,pixel_cmp); hash=hashtable_new(pixel_hash,pixel_cmp);
@ -234,6 +240,7 @@ hash_to_list(const HashTable *h, const Pixel pixel, const uint32_t count, void *
PIXEL_SCALE(&pixel,&q,d->scale); PIXEL_SCALE(&pixel,&q,d->scale);
/* malloc check ok, small constant allocation */
p=malloc(sizeof(PixelList)); p=malloc(sizeof(PixelList));
if (!p) return; if (!p) return;
@ -557,6 +564,7 @@ split(BoxNode *node)
exit(1); exit(1);
} }
#endif #endif
/* malloc check ok, small constant allocation */
left=malloc(sizeof(BoxNode)); left=malloc(sizeof(BoxNode));
right=malloc(sizeof(BoxNode)); right=malloc(sizeof(BoxNode));
if (!left||!right) { if (!left||!right) {
@ -613,6 +621,7 @@ median_cut(PixelList *hl[3],
BoxNode *thisNode; BoxNode *thisNode;
h=ImagingQuantHeapNew(box_heap_cmp); h=ImagingQuantHeapNew(box_heap_cmp);
/* malloc check ok, small constant allocation */
root=malloc(sizeof(BoxNode)); root=malloc(sizeof(BoxNode));
if (!root) { ImagingQuantHeapFree(h); return NULL; } if (!root) { ImagingQuantHeapFree(h); return NULL; }
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
@ -954,15 +963,16 @@ compute_palette_from_median_cut(
uint32_t *count; uint32_t *count;
*palette=NULL; *palette=NULL;
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) { /* malloc check ok, using calloc */
if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) {
return 0; return 0;
} }
memset(count,0,sizeof(uint32_t)*nPaletteEntries);
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
avg[i]=NULL; avg[i]=NULL;
} }
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
if (!(avg[i]=malloc(sizeof(uint32_t)*nPaletteEntries))) { /* malloc check ok, using calloc */
if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) {
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
if (avg[i]) free (avg[i]); if (avg[i]) free (avg[i]);
} }
@ -970,9 +980,6 @@ compute_palette_from_median_cut(
return 0; return 0;
} }
} }
for(i=0;i<3;i++) {
memset(avg[i],0,sizeof(uint32_t)*nPaletteEntries);
}
for (i=0;i<nPixels;i++) { for (i=0;i<nPixels;i++) {
#ifdef TEST_SPLIT_INTEGRITY #ifdef TEST_SPLIT_INTEGRITY
if (!(i%100)) { printf ("%05d\r",i); fflush(stdout); } if (!(i%100)) { printf ("%05d\r",i); fflush(stdout); }
@ -1004,7 +1011,8 @@ compute_palette_from_median_cut(
avg[2][paletteEntry]+=pixelData[i].c.b; avg[2][paletteEntry]+=pixelData[i].c.b;
count[paletteEntry]++; count[paletteEntry]++;
} }
p=malloc(sizeof(Pixel)*nPaletteEntries); /* malloc check ok, using calloc */
p=calloc(nPaletteEntries, sizeof(Pixel));
if (!p) { if (!p) {
for(i=0;i<3;i++) free (avg[i]); for(i=0;i<3;i++) free (avg[i]);
free(count); free(count);
@ -1090,21 +1098,33 @@ k_means(Pixel *pixelData,
int changes; int changes;
int built=0; int built=0;
if (!(count=malloc(sizeof(uint32_t)*nPaletteEntries))) { if (nPaletteEntries > UINT32_MAX / (sizeof(uint32_t))) {
return 0;
}
/* malloc check ok, using calloc */
if (!(count=calloc(nPaletteEntries, sizeof(uint32_t)))) {
return 0; return 0;
} }
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
avg[i]=NULL; avg[i]=NULL;
} }
for(i=0;i<3;i++) { for(i=0;i<3;i++) {
if (!(avg[i]=malloc(sizeof(uint32_t)*nPaletteEntries))) { /* malloc check ok, using calloc */
if (!(avg[i]=calloc(nPaletteEntries, sizeof(uint32_t)))) {
goto error_1; goto error_1;
} }
} }
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries);
/* this is enough of a check, since the multiplication n*size is done above */
if (nPaletteEntries > UINT32_MAX / nPaletteEntries) {
goto error_1;
}
/* malloc check ok, using calloc, checking n*n above */
avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t));
if (!avgDist) { goto error_1; } if (!avgDist) { goto error_1; }
avgDistSortKey=malloc(sizeof(uint32_t *)*nPaletteEntries*nPaletteEntries); /* malloc check ok, using calloc, checking n*n above */
avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *));
if (!avgDistSortKey) { goto error_2; } if (!avgDistSortKey) { goto error_2; }
#ifndef NO_OUTPUT #ifndef NO_OUTPUT
@ -1251,13 +1271,19 @@ quantize(Pixel *pixelData,
free_box_tree(root); free_box_tree(root);
root=NULL; root=NULL;
qp=malloc(sizeof(uint32_t)*nPixels); /* malloc check ok, using calloc for overflow */
qp=calloc(nPixels, sizeof(uint32_t));
if (!qp) { goto error_4; } if (!qp) { goto error_4; }
avgDist=malloc(sizeof(uint32_t)*nPaletteEntries*nPaletteEntries); if (nPaletteEntries > UINT32_MAX / nPaletteEntries ) {
goto error_5;
}
/* malloc check ok, using calloc for overflow, check of n*n above */
avgDist=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t));
if (!avgDist) { goto error_5; } if (!avgDist) { goto error_5; }
avgDistSortKey=malloc(sizeof(uint32_t *)*nPaletteEntries*nPaletteEntries); /* malloc check ok, using calloc for overflow, check of n*n above */
avgDistSortKey=calloc(nPaletteEntries*nPaletteEntries, sizeof(uint32_t *));
if (!avgDistSortKey) { goto error_6; } if (!avgDistSortKey) { goto error_6; }
if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) { if (!build_distance_tables(avgDist,avgDistSortKey,p,nPaletteEntries)) {
@ -1400,7 +1426,8 @@ quantize2(Pixel *pixelData,
uint32_t *avgDist; uint32_t *avgDist;
uint32_t **avgDistSortKey; uint32_t **avgDistSortKey;
p=malloc(sizeof(Pixel)*nQuantPixels); /* malloc check ok, using calloc */
p=calloc(nQuantPixels, sizeof(Pixel));
if (!p) return 0; if (!p) return 0;
mean[0]=mean[1]=mean[2]=0; mean[0]=mean[1]=mean[2]=0;
h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp); h=hashtable_new(unshifted_pixel_hash,unshifted_pixel_cmp);
@ -1422,13 +1449,20 @@ quantize2(Pixel *pixelData,
} }
hashtable_free(h); hashtable_free(h);
qp=malloc(sizeof(uint32_t)*nPixels); /* malloc check ok, using calloc */
qp=calloc(nPixels, sizeof(uint32_t));
if (!qp) { goto error_1; } if (!qp) { goto error_1; }
avgDist=malloc(sizeof(uint32_t)*nQuantPixels*nQuantPixels); if (nQuantPixels > UINT32_MAX / nQuantPixels ) {
goto error_2;
}
/* malloc check ok, using calloc for overflow, check of n*n above */
avgDist=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t));
if (!avgDist) { goto error_2; } if (!avgDist) { goto error_2; }
avgDistSortKey=malloc(sizeof(uint32_t *)*nQuantPixels*nQuantPixels); /* malloc check ok, using calloc for overflow, check of n*n above */
avgDistSortKey=calloc(nQuantPixels*nQuantPixels, sizeof(uint32_t *));
if (!avgDistSortKey) { goto error_3; } if (!avgDistSortKey) { goto error_3; }
if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) { if (!build_distance_tables(avgDist,avgDistSortKey,p,nQuantPixels)) {
@ -1474,7 +1508,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
ImagingSectionCookie cookie; ImagingSectionCookie cookie;
if (!im) if (!im)
return ImagingError_ModeError(); return ImagingError_ModeError();
if (colors < 1 || colors > 256) if (colors < 1 || colors > 256)
/* FIXME: for colors > 256, consider returning an RGB image /* FIXME: for colors > 256, consider returning an RGB image
instead (see @PIL205) */ instead (see @PIL205) */
@ -1488,7 +1522,11 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans)
if (!strcmp(im->mode, "RGBA") && mode != 2 && mode != 3) if (!strcmp(im->mode, "RGBA") && mode != 2 && mode != 3)
return ImagingError_ModeError(); return ImagingError_ModeError();
p = malloc(sizeof(Pixel) * im->xsize * im->ysize); if (im->xsize > INT_MAX / im->ysize) {
return ImagingError_MemoryError();
}
/* malloc check ok, using calloc for final overflow, x*y above */
p = calloc(im->xsize * im->ysize, sizeof(Pixel));
if (!p) if (!p)
return ImagingError_MemoryError(); return ImagingError_MemoryError();

View File

@ -20,6 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <limits.h>
#include "QuantHeap.h" #include "QuantHeap.h"
@ -47,7 +48,12 @@ static int _heap_grow(Heap *h,int newsize) {
void *newheap; void *newheap;
if (!newsize) newsize=h->heapsize<<1; if (!newsize) newsize=h->heapsize<<1;
if (newsize<h->heapsize) return 0; if (newsize<h->heapsize) return 0;
newheap=malloc(sizeof(void *)*newsize); if (newsize > INT_MAX / sizeof(void *)){
return 0;
}
/* malloc check ok, using calloc for overflow, also checking
above due to memcpy below*/
newheap=calloc(newsize, sizeof(void *));
if (!newheap) return 0; if (!newheap) return 0;
memcpy(newheap,h->heap,sizeof(void *)*h->heapsize); memcpy(newheap,h->heap,sizeof(void *)*h->heapsize);
free(h->heap); free(h->heap);
@ -132,11 +138,16 @@ int ImagingQuantHeapTop(Heap *h,void **r) {
Heap *ImagingQuantHeapNew(HeapCmpFunc cf) { Heap *ImagingQuantHeapNew(HeapCmpFunc cf) {
Heap *h; Heap *h;
/* malloc check ok, small constant allocation */
h=malloc(sizeof(Heap)); h=malloc(sizeof(Heap));
if (!h) return NULL; if (!h) return NULL;
h->heapsize=INITIAL_SIZE; h->heapsize=INITIAL_SIZE;
h->heap=malloc(sizeof(void *)*h->heapsize); /* malloc check ok, using calloc for overflow */
if (!h->heap) { free(h); return NULL; } h->heap=calloc(h->heapsize, sizeof(void *));
if (!h->heap) {
free(h);
return NULL;
}
h->heapcount=0; h->heapcount=0;
h->cf=cf; h->cf=cf;
return h; return h;

View File

@ -26,6 +26,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#include "QuantOctree.h" #include "QuantOctree.h"
@ -53,6 +54,7 @@ static ColorCube
new_color_cube(int r, int g, int b, int a) { new_color_cube(int r, int g, int b, int a) {
ColorCube cube; ColorCube cube;
/* malloc check ok, small constant allocation */
cube = malloc(sizeof(struct _ColorCube)); cube = malloc(sizeof(struct _ColorCube));
if (!cube) return NULL; if (!cube) return NULL;
@ -61,6 +63,12 @@ new_color_cube(int r, int g, int b, int a) {
cube->bBits = MAX(b, 0); cube->bBits = MAX(b, 0);
cube->aBits = MAX(a, 0); cube->aBits = MAX(a, 0);
/* overflow check for size multiplication below */
if (cube->rBits + cube->gBits + cube->bBits + cube->aBits > 31) {
free(cube);
return NULL;
}
/* the width of the cube for each dimension */ /* the width of the cube for each dimension */
cube->rWidth = 1<<cube->rBits; cube->rWidth = 1<<cube->rBits;
cube->gWidth = 1<<cube->gBits; cube->gWidth = 1<<cube->gBits;
@ -76,6 +84,7 @@ new_color_cube(int r, int g, int b, int a) {
/* the number of color buckets */ /* the number of color buckets */
cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth; cube->size = cube->rWidth * cube->gWidth * cube->bWidth * cube->aWidth;
/* malloc check ok, overflow checked above */
cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket)); cube->buckets = calloc(cube->size, sizeof(struct _ColorBucket));
if (!cube->buckets) { if (!cube->buckets) {
@ -154,7 +163,11 @@ compare_bucket_count(const ColorBucket a, const ColorBucket b) {
static ColorBucket static ColorBucket
create_sorted_color_palette(const ColorCube cube) { create_sorted_color_palette(const ColorCube cube) {
ColorBucket buckets; ColorBucket buckets;
buckets = malloc(sizeof(struct _ColorBucket)*cube->size); if (cube->size > LONG_MAX / sizeof(struct _ColorBucket)) {
return NULL;
}
/* malloc check ok, calloc + overflow check above for memcpy */
buckets = calloc(cube->size, sizeof(struct _ColorBucket));
if (!buckets) return NULL; if (!buckets) return NULL;
memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket)*cube->size); memcpy(buckets, cube->buckets, sizeof(struct _ColorBucket)*cube->size);
@ -280,7 +293,15 @@ void add_lookup_buckets(ColorCube cube, ColorBucket palette, long nColors, long
ColorBucket ColorBucket
combined_palette(ColorBucket bucketsA, long nBucketsA, ColorBucket bucketsB, long nBucketsB) { combined_palette(ColorBucket bucketsA, long nBucketsA, ColorBucket bucketsB, long nBucketsB) {
ColorBucket result; ColorBucket result;
result = malloc(sizeof(struct _ColorBucket)*(nBucketsA+nBucketsB)); if (nBucketsA > LONG_MAX - nBucketsB ||
(nBucketsA+nBucketsB) > LONG_MAX / sizeof(struct _ColorBucket)) {
return NULL;
}
/* malloc check ok, overflow check above */
result = calloc(nBucketsA + nBucketsB, sizeof(struct _ColorBucket));
if (!result) {
return NULL;
}
memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA); memcpy(result, bucketsA, sizeof(struct _ColorBucket) * nBucketsA);
memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB); memcpy(&result[nBucketsA], bucketsB, sizeof(struct _ColorBucket) * nBucketsB);
return result; return result;
@ -291,7 +312,8 @@ create_palette_array(const ColorBucket palette, unsigned int paletteLength) {
Pixel *paletteArray; Pixel *paletteArray;
unsigned int i; unsigned int i;
paletteArray = malloc(sizeof(Pixel)*paletteLength); /* malloc check ok, calloc for overflow */
paletteArray = calloc(paletteLength, sizeof(Pixel));
if (!paletteArray) return NULL; if (!paletteArray) return NULL;
for (i=0; i<paletteLength; i++) { for (i=0; i<paletteLength; i++) {
@ -405,6 +427,7 @@ int quantize_octree(Pixel *pixelData,
paletteBucketsFine = NULL; paletteBucketsFine = NULL;
free(paletteBucketsCoarse); free(paletteBucketsCoarse);
paletteBucketsCoarse = NULL; paletteBucketsCoarse = NULL;
if (!paletteBuckets) goto error;
/* add all coarse colors to our coarse lookup cube. */ /* add all coarse colors to our coarse lookup cube. */
coarseLookupCube = new_color_cube(cubeBits[4], cubeBits[5], coarseLookupCube = new_color_cube(cubeBits[4], cubeBits[5],
@ -422,7 +445,8 @@ int quantize_octree(Pixel *pixelData,
add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors); add_lookup_buckets(lookupCube, paletteBuckets, nFineColors, nCoarseColors);
/* create result pixels and map palette indices */ /* create result pixels and map palette indices */
qp = malloc(sizeof(Pixel)*nPixels); /* malloc check ok, calloc for overflow */
qp = calloc(nPixels, sizeof(Pixel));
if (!qp) goto error; if (!qp) goto error;
map_image_pixels(pixelData, nPixels, lookupCube, qp); map_image_pixels(pixelData, nPixels, lookupCube, qp);

View File

@ -55,21 +55,28 @@ ImagingRankFilter(Imaging im, int size, int rank)
int i, margin, size2; int i, margin, size2;
if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL) if (!im || im->bands != 1 || im->type == IMAGING_TYPE_SPECIAL)
return (Imaging) ImagingError_ModeError(); return (Imaging) ImagingError_ModeError();
if (!(size & 1)) if (!(size & 1))
return (Imaging) ImagingError_ValueError("bad filter size"); return (Imaging) ImagingError_ValueError("bad filter size");
/* malloc check ok, for overflow in the define below */
if (size > INT_MAX / size ||
size > INT_MAX / (size * sizeof(FLOAT32))) {
return (Imaging) ImagingError_ValueError("filter size too large");
}
size2 = size * size; size2 = size * size;
margin = (size-1) / 2; margin = (size-1) / 2;
if (rank < 0 || rank >= size2) if (rank < 0 || rank >= size2)
return (Imaging) ImagingError_ValueError("bad rank value"); return (Imaging) ImagingError_ValueError("bad rank value");
imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin); imOut = ImagingNew(im->mode, im->xsize - 2*margin, im->ysize - 2*margin);
if (!imOut) if (!imOut)
return NULL; return NULL;
/* malloc check ok, checked above */
#define RANK_BODY(type) do {\ #define RANK_BODY(type) do {\
type* buf = malloc(size2 * sizeof(type));\ type* buf = malloc(size2 * sizeof(type));\
if (!buf)\ if (!buf)\

View File

@ -98,15 +98,13 @@ ImagingPrecompute(int inSize, int outSize, struct filter *filterp,
if (outSize > INT_MAX / (kmax * sizeof(double))) if (outSize > INT_MAX / (kmax * sizeof(double)))
return 0; return 0;
// sizeof(double) should be greater than 0 as well
if (outSize > INT_MAX / (2 * sizeof(double)))
return 0;
/* coefficient buffer */ /* coefficient buffer */
/* malloc check ok, overflow checked above */
kk = malloc(outSize * kmax * sizeof(double)); kk = malloc(outSize * kmax * sizeof(double));
if ( ! kk) if ( ! kk)
return 0; return 0;
/* malloc check ok, kmax*sizeof(double) > 2*sizeof(int) */
xbounds = malloc(outSize * 2 * sizeof(int)); xbounds = malloc(outSize * 2 * sizeof(int));
if ( ! xbounds) { if ( ! xbounds) {
free(kk); free(kk);

View File

@ -46,7 +46,7 @@ int ImagingNewCount = 0;
*/ */
Imaging Imaging
ImagingNewPrologueSubtype(const char *mode, unsigned xsize, unsigned ysize, ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize,
int size) int size)
{ {
Imaging im; Imaging im;
@ -56,6 +56,11 @@ ImagingNewPrologueSubtype(const char *mode, unsigned xsize, unsigned ysize,
if (!im) if (!im)
return (Imaging) ImagingError_MemoryError(); return (Imaging) ImagingError_MemoryError();
/* linesize overflow check, roughly the current largest space req'd */
if (xsize > (INT_MAX / 4) - 1) {
return (Imaging) ImagingError_MemoryError();
}
/* Setup image descriptor */ /* Setup image descriptor */
im->xsize = xsize; im->xsize = xsize;
im->ysize = ysize; im->ysize = ysize;
@ -226,7 +231,7 @@ ImagingNewPrologueSubtype(const char *mode, unsigned xsize, unsigned ysize,
} }
Imaging Imaging
ImagingNewPrologue(const char *mode, unsigned xsize, unsigned ysize) ImagingNewPrologue(const char *mode, int xsize, int ysize)
{ {
return ImagingNewPrologueSubtype( return ImagingNewPrologueSubtype(
mode, xsize, ysize, sizeof(struct ImagingMemoryInstance) mode, xsize, ysize, sizeof(struct ImagingMemoryInstance)
@ -306,7 +311,8 @@ ImagingNewArray(const char *mode, int xsize, int ysize)
/* Allocate image as an array of lines */ /* Allocate image as an array of lines */
for (y = 0; y < im->ysize; y++) { for (y = 0; y < im->ysize; y++) {
p = (char *) malloc(im->linesize); /* malloc check linesize checked in prologue */
p = (char *) calloc(1, im->linesize);
if (!p) { if (!p) {
ImagingDestroyArray(im); ImagingDestroyArray(im);
break; break;
@ -339,24 +345,32 @@ ImagingNewBlock(const char *mode, int xsize, int ysize)
{ {
Imaging im; Imaging im;
Py_ssize_t y, i; Py_ssize_t y, i;
Py_ssize_t bytes;
im = ImagingNewPrologue(mode, xsize, ysize); im = ImagingNewPrologue(mode, xsize, ysize);
if (!im) if (!im)
return NULL; return NULL;
/* Use a single block */ /* We shouldn't overflow, since the threshold defined
bytes = (Py_ssize_t) im->ysize * im->linesize; below says that we're only going to allocate max 4M
if (bytes <= 0) here before going to the array allocator. Check anyway.
*/
if (im->linesize &&
im->ysize > INT_MAX / im->linesize) {
/* punt if we're going to overflow */
return NULL;
}
if (im->ysize * im->linesize <= 0) {
/* some platforms return NULL for malloc(0); this fix /* some platforms return NULL for malloc(0); this fix
prevents MemoryError on zero-sized images on such prevents MemoryError on zero-sized images on such
platforms */ platforms */
bytes = 1; im->block = (char *) malloc(1);
im->block = (char *) malloc(bytes); } else {
/* malloc check ok, overflow check above */
im->block = (char *) calloc(im->ysize, im->linesize);
}
if (im->block) { if (im->block) {
memset(im->block, 0, bytes);
for (y = i = 0; y < im->ysize; y++) { for (y = i = 0; y < im->ysize; y++) {
im->image[y] = im->block + i; im->image[y] = im->block + i;
i += im->linesize; i += im->linesize;
@ -392,7 +406,7 @@ ImagingNew(const char* mode, int xsize, int ysize)
} else } else
bytes = strlen(mode); /* close enough */ bytes = strlen(mode); /* close enough */
if ((int64_t) xsize * (int64_t) ysize * bytes <= THRESHOLD) { if ((int64_t) xsize * (int64_t) ysize <= THRESHOLD / bytes) {
im = ImagingNewBlock(mode, xsize, ysize); im = ImagingNewBlock(mode, xsize, ysize);
if (im) if (im)
return im; return im;

View File

@ -58,10 +58,14 @@ tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
tdata_t new; tdata_t new;
tsize_t newsize=state->size; tsize_t newsize=state->size;
while (newsize < (size + state->size)) { while (newsize < (size + state->size)) {
if (newsize > (tsize_t)SIZE_MAX - 64*1024){
return 0;
}
newsize += 64*1024; newsize += 64*1024;
// newsize*=2; // UNDONE, by 64k chunks? // newsize*=2; // UNDONE, by 64k chunks?
} }
TRACE(("Reallocing in write to %d bytes\n", (int)newsize)); TRACE(("Reallocing in write to %d bytes\n", (int)newsize));
/* malloc check ok, overflow checked above */
new = realloc(state->data, newsize); new = realloc(state->data, newsize);
if (!new) { if (!new) {
// fail out // fail out
@ -305,6 +309,7 @@ int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) {
} else { } else {
// malloc a buffer to write the tif, we're going to need to realloc or something if we need bigger. // malloc a buffer to write the tif, we're going to need to realloc or something if we need bigger.
TRACE(("Opening a buffer for writing \n")); TRACE(("Opening a buffer for writing \n"));
/* malloc check ok, small constant allocation */
clientstate->data = malloc(bufsize); clientstate->data = malloc(bufsize);
clientstate->size = bufsize; clientstate->size = bufsize;
clientstate->flrealloc=1; clientstate->flrealloc=1;

View File

@ -18,7 +18,7 @@
#include "Imaging.h" #include "Imaging.h"
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
#include "Zip.h" #include "Zip.h"
@ -37,7 +37,7 @@ static int get_row_len(ImagingCodecState state, int pass)
} }
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Decoder */ /* Decoder */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
int int
@ -52,50 +52,56 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (!state->state) { if (!state->state) {
/* Initialization */ /* Initialization */
if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE) if (context->mode == ZIP_PNG || context->mode == ZIP_PNG_PALETTE)
context->prefix = 1; /* PNG */ context->prefix = 1; /* PNG */
/* Expand standard buffer to make room for the (optional) filter /* overflow check for malloc */
prefix, and allocate a buffer to hold the previous line */ if (state->bytes > INT_MAX - 1) {
free(state->buffer); state->errcode = IMAGING_CODEC_MEMORY;
state->buffer = (UINT8*) malloc(state->bytes+1); return -1;
context->previous = (UINT8*) malloc(state->bytes+1); }
if (!state->buffer || !context->previous) { /* Expand standard buffer to make room for the (optional) filter
state->errcode = IMAGING_CODEC_MEMORY; prefix, and allocate a buffer to hold the previous line */
return -1; free(state->buffer);
} /* malloc check ok, overflow checked above */
state->buffer = (UINT8*) malloc(state->bytes+1);
context->previous = (UINT8*) malloc(state->bytes+1);
if (!state->buffer || !context->previous) {
state->errcode = IMAGING_CODEC_MEMORY;
return -1;
}
context->last_output = 0; context->last_output = 0;
/* Initialize to black */ /* Initialize to black */
memset(context->previous, 0, state->bytes+1); memset(context->previous, 0, state->bytes+1);
/* Setup decompression context */ /* Setup decompression context */
context->z_stream.zalloc = (alloc_func) NULL; context->z_stream.zalloc = (alloc_func) NULL;
context->z_stream.zfree = (free_func) NULL; context->z_stream.zfree = (free_func) NULL;
context->z_stream.opaque = (voidpf) NULL; context->z_stream.opaque = (voidpf) NULL;
err = inflateInit(&context->z_stream); err = inflateInit(&context->z_stream);
if (err < 0) { if (err < 0) {
state->errcode = IMAGING_CODEC_CONFIG; state->errcode = IMAGING_CODEC_CONFIG;
return -1; return -1;
} }
if (context->interlaced) { if (context->interlaced) {
context->pass = 0; context->pass = 0;
state->y = STARTING_ROW[context->pass]; state->y = STARTING_ROW[context->pass];
} }
/* Ready to decode */ /* Ready to decode */
state->state = 1; state->state = 1;
} }
if (context->interlaced) { if (context->interlaced) {
row_len = get_row_len(state, context->pass); row_len = get_row_len(state, context->pass);
} else { } else {
row_len = state->bytes; row_len = state->bytes;
} }
/* Setup the source buffer */ /* Setup the source buffer */
@ -105,162 +111,162 @@ ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
/* Decompress what we've got this far */ /* Decompress what we've got this far */
while (context->z_stream.avail_in > 0) { while (context->z_stream.avail_in > 0) {
context->z_stream.next_out = state->buffer + context->last_output; context->z_stream.next_out = state->buffer + context->last_output;
context->z_stream.avail_out = context->z_stream.avail_out =
row_len + context->prefix - context->last_output; row_len + context->prefix - context->last_output;
err = inflate(&context->z_stream, Z_NO_FLUSH); err = inflate(&context->z_stream, Z_NO_FLUSH);
if (err < 0) { if (err < 0) {
/* Something went wrong inside the compression library */ /* Something went wrong inside the compression library */
if (err == Z_DATA_ERROR) if (err == Z_DATA_ERROR)
state->errcode = IMAGING_CODEC_BROKEN; state->errcode = IMAGING_CODEC_BROKEN;
else if (err == Z_MEM_ERROR) else if (err == Z_MEM_ERROR)
state->errcode = IMAGING_CODEC_MEMORY; state->errcode = IMAGING_CODEC_MEMORY;
else else
state->errcode = IMAGING_CODEC_CONFIG; state->errcode = IMAGING_CODEC_CONFIG;
free(context->previous); free(context->previous);
inflateEnd(&context->z_stream); inflateEnd(&context->z_stream);
return -1; return -1;
} }
n = row_len + context->prefix - context->z_stream.avail_out; n = row_len + context->prefix - context->z_stream.avail_out;
if (n < row_len + context->prefix) { if (n < row_len + context->prefix) {
context->last_output = n; context->last_output = n;
break; /* need more input data */ break; /* need more input data */
} }
/* Apply predictor */ /* Apply predictor */
switch (context->mode) { switch (context->mode) {
case ZIP_PNG: case ZIP_PNG:
switch (state->buffer[0]) { switch (state->buffer[0]) {
case 0: case 0:
break; break;
case 1: case 1:
/* prior */ /* prior */
bpp = (state->bits + 7) / 8; bpp = (state->bits + 7) / 8;
for (i = bpp+1; i <= row_len; i++) for (i = bpp+1; i <= row_len; i++)
state->buffer[i] += state->buffer[i-bpp]; state->buffer[i] += state->buffer[i-bpp];
break; break;
case 2: case 2:
/* up */ /* up */
for (i = 1; i <= row_len; i++) for (i = 1; i <= row_len; i++)
state->buffer[i] += context->previous[i]; state->buffer[i] += context->previous[i];
break; break;
case 3: case 3:
/* average */ /* average */
bpp = (state->bits + 7) / 8; bpp = (state->bits + 7) / 8;
for (i = 1; i <= bpp; i++) for (i = 1; i <= bpp; i++)
state->buffer[i] += context->previous[i]/2; state->buffer[i] += context->previous[i]/2;
for (; i <= row_len; i++) for (; i <= row_len; i++)
state->buffer[i] += state->buffer[i] +=
(state->buffer[i-bpp] + context->previous[i])/2; (state->buffer[i-bpp] + context->previous[i])/2;
break; break;
case 4: case 4:
/* paeth filtering */ /* paeth filtering */
bpp = (state->bits + 7) / 8; bpp = (state->bits + 7) / 8;
for (i = 1; i <= bpp; i++) for (i = 1; i <= bpp; i++)
state->buffer[i] += context->previous[i]; state->buffer[i] += context->previous[i];
for (; i <= row_len; i++) { for (; i <= row_len; i++) {
int a, b, c; int a, b, c;
int pa, pb, pc; int pa, pb, pc;
/* fetch pixels */ /* fetch pixels */
a = state->buffer[i-bpp]; a = state->buffer[i-bpp];
b = context->previous[i]; b = context->previous[i];
c = context->previous[i-bpp]; c = context->previous[i-bpp];
/* distances to surrounding pixels */ /* distances to surrounding pixels */
pa = abs(b - c); pa = abs(b - c);
pb = abs(a - c); pb = abs(a - c);
pc = abs(a + b - 2*c); pc = abs(a + b - 2*c);
/* pick predictor with the shortest distance */ /* pick predictor with the shortest distance */
state->buffer[i] += state->buffer[i] +=
(pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
} }
break; break;
default: default:
state->errcode = IMAGING_CODEC_UNKNOWN; state->errcode = IMAGING_CODEC_UNKNOWN;
free(context->previous); free(context->previous);
inflateEnd(&context->z_stream); inflateEnd(&context->z_stream);
return -1; return -1;
} }
break; break;
case ZIP_TIFF_PREDICTOR: case ZIP_TIFF_PREDICTOR:
bpp = (state->bits + 7) / 8; bpp = (state->bits + 7) / 8;
for (i = bpp+1; i <= row_len; i++) for (i = bpp+1; i <= row_len; i++)
state->buffer[i] += state->buffer[i-bpp]; state->buffer[i] += state->buffer[i-bpp];
break; break;
} }
/* Stuff data into the image */ /* Stuff data into the image */
if (context->interlaced) { if (context->interlaced) {
int col = STARTING_COL[context->pass]; int col = STARTING_COL[context->pass];
if (state->bits >= 8) { if (state->bits >= 8) {
/* Stuff pixels in their correct location, one by one */ /* Stuff pixels in their correct location, one by one */
for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) { for (i = 0; i < row_len; i += ((state->bits + 7) / 8)) {
state->shuffle((UINT8*) im->image[state->y] + state->shuffle((UINT8*) im->image[state->y] +
col * im->pixelsize, col * im->pixelsize,
state->buffer + context->prefix + i, 1); state->buffer + context->prefix + i, 1);
col += COL_INCREMENT[context->pass]; col += COL_INCREMENT[context->pass];
} }
} else { } else {
/* Handle case with more than a pixel in each byte */ /* Handle case with more than a pixel in each byte */
int row_bits = ((state->xsize + OFFSET[context->pass]) int row_bits = ((state->xsize + OFFSET[context->pass])
/ COL_INCREMENT[context->pass]) * state->bits; / COL_INCREMENT[context->pass]) * state->bits;
for (i = 0; i < row_bits; i += state->bits) { for (i = 0; i < row_bits; i += state->bits) {
UINT8 byte = *(state->buffer + context->prefix + (i / 8)); UINT8 byte = *(state->buffer + context->prefix + (i / 8));
byte <<= (i % 8); byte <<= (i % 8);
state->shuffle((UINT8*) im->image[state->y] + state->shuffle((UINT8*) im->image[state->y] +
col * im->pixelsize, &byte, 1); col * im->pixelsize, &byte, 1);
col += COL_INCREMENT[context->pass]; col += COL_INCREMENT[context->pass];
} }
} }
/* Find next valid scanline */ /* Find next valid scanline */
state->y += ROW_INCREMENT[context->pass]; state->y += ROW_INCREMENT[context->pass];
while (state->y >= state->ysize || row_len <= 0) { while (state->y >= state->ysize || row_len <= 0) {
context->pass++; context->pass++;
if (context->pass == 7) { if (context->pass == 7) {
/* Force exit below */ /* Force exit below */
state->y = state->ysize; state->y = state->ysize;
break; break;
} }
state->y = STARTING_ROW[context->pass]; state->y = STARTING_ROW[context->pass];
row_len = get_row_len(state, context->pass); row_len = get_row_len(state, context->pass);
/* Since we're moving to the "first" line, the previous line /* Since we're moving to the "first" line, the previous line
* should be black to make filters work corectly */ * should be black to make filters work corectly */
memset(state->buffer, 0, state->bytes+1); memset(state->buffer, 0, state->bytes+1);
} }
} else { } else {
state->shuffle((UINT8*) im->image[state->y + state->yoff] + state->shuffle((UINT8*) im->image[state->y + state->yoff] +
state->xoff * im->pixelsize, state->xoff * im->pixelsize,
state->buffer + context->prefix, state->buffer + context->prefix,
state->xsize); state->xsize);
state->y++; state->y++;
} }
/* all inflate output has been consumed */ /* all inflate output has been consumed */
context->last_output = 0; context->last_output = 0;
if (state->y >= state->ysize || err == Z_STREAM_END) { if (state->y >= state->ysize || err == Z_STREAM_END) {
/* The image and the data should end simultaneously */ /* The image and the data should end simultaneously */
/* if (state->y < state->ysize || err != Z_STREAM_END) /* if (state->y < state->ysize || err != Z_STREAM_END)
state->errcode = IMAGING_CODEC_BROKEN; */ state->errcode = IMAGING_CODEC_BROKEN; */
free(context->previous); free(context->previous);
inflateEnd(&context->z_stream); inflateEnd(&context->z_stream);
return -1; /* end of file (errcode=0) */ return -1; /* end of file (errcode=0) */
} }
/* Swap buffer pointers */ /* Swap buffer pointers */
ptr = state->buffer; ptr = state->buffer;
state->buffer = context->previous; state->buffer = context->previous;
context->previous = ptr; context->previous = ptr;
} }

View File

@ -5,8 +5,8 @@
* coder for ZIP (deflated) image data * coder for ZIP (deflated) image data
* *
* History: * History:
* 96-12-29 fl created * 96-12-29 fl created
* 96-12-30 fl adaptive filter selection, encoder tuning * 96-12-30 fl adaptive filter selection, encoder tuning
* *
* Copyright (c) Fredrik Lundh 1996. * Copyright (c) Fredrik Lundh 1996.
* Copyright (c) Secret Labs AB 1997. * Copyright (c) Secret Labs AB 1997.
@ -17,7 +17,7 @@
#include "Imaging.h" #include "Imaging.h"
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
#include "Zip.h" #include "Zip.h"
@ -33,82 +33,89 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
if (!state->state) { if (!state->state) {
/* Initialization */ /* Initialization */
/* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */ /* Valid modes are ZIP_PNG, ZIP_PNG_PALETTE, and ZIP_TIFF */
/* Expand standard buffer to make room for the filter selector, /* overflow check for malloc */
and allocate filter buffers */ if (state->bytes > INT_MAX - 1) {
free(state->buffer); state->errcode = IMAGING_CODEC_MEMORY;
state->buffer = (UINT8*) malloc(state->bytes+1); return -1;
context->previous = (UINT8*) malloc(state->bytes+1); }
context->prior = (UINT8*) malloc(state->bytes+1);
context->up = (UINT8*) malloc(state->bytes+1);
context->average = (UINT8*) malloc(state->bytes+1);
context->paeth = (UINT8*) malloc(state->bytes+1);
if (!state->buffer || !context->previous || !context->prior ||
!context->up || !context->average || !context->paeth) {
free(context->paeth);
free(context->average);
free(context->up);
free(context->prior);
free(context->previous);
state->errcode = IMAGING_CODEC_MEMORY;
return -1;
}
/* Initalise filter buffers */ /* Expand standard buffer to make room for the filter selector,
state->buffer[0] = 0; and allocate filter buffers */
context->prior[0] = 1; free(state->buffer);
context->up[0] = 2; /* malloc check ok, overflow checked above */
context->average[0] = 3; state->buffer = (UINT8*) malloc(state->bytes+1);
context->paeth[0] = 4; context->previous = (UINT8*) malloc(state->bytes+1);
context->prior = (UINT8*) malloc(state->bytes+1);
context->up = (UINT8*) malloc(state->bytes+1);
context->average = (UINT8*) malloc(state->bytes+1);
context->paeth = (UINT8*) malloc(state->bytes+1);
if (!state->buffer || !context->previous || !context->prior ||
!context->up || !context->average || !context->paeth) {
free(context->paeth);
free(context->average);
free(context->up);
free(context->prior);
free(context->previous);
state->errcode = IMAGING_CODEC_MEMORY;
return -1;
}
/* Initialise previous buffer to black */ /* Initalise filter buffers */
memset(context->previous, 0, state->bytes+1); state->buffer[0] = 0;
context->prior[0] = 1;
context->up[0] = 2;
context->average[0] = 3;
context->paeth[0] = 4;
/* Setup compression context */ /* Initialise previous buffer to black */
context->z_stream.zalloc = (alloc_func)0; memset(context->previous, 0, state->bytes+1);
context->z_stream.zfree = (free_func)0;
context->z_stream.opaque = (voidpf)0;
context->z_stream.next_in = 0;
context->z_stream.avail_in = 0;
compress_level = (context->optimize) ? Z_BEST_COMPRESSION /* Setup compression context */
: context->compress_level; context->z_stream.zalloc = (alloc_func)0;
context->z_stream.zfree = (free_func)0;
context->z_stream.opaque = (voidpf)0;
context->z_stream.next_in = 0;
context->z_stream.avail_in = 0;
if (context->compress_type == -1) { compress_level = (context->optimize) ? Z_BEST_COMPRESSION
compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED : context->compress_level;
: Z_DEFAULT_STRATEGY;
} else {
compress_type = context->compress_type;
}
err = deflateInit2(&context->z_stream, if (context->compress_type == -1) {
/* compression level */ compress_type = (context->mode == ZIP_PNG) ? Z_FILTERED
compress_level, : Z_DEFAULT_STRATEGY;
/* compression method */ } else {
Z_DEFLATED, compress_type = context->compress_type;
/* compression memory resources */ }
15, 9,
/* compression strategy (image data are filtered)*/
compress_type);
if (err < 0) {
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
if (context->dictionary && context->dictionary_size > 0) { err = deflateInit2(&context->z_stream,
err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary, /* compression level */
context->dictionary_size); compress_level,
if (err < 0) { /* compression method */
state->errcode = IMAGING_CODEC_CONFIG; Z_DEFLATED,
return -1; /* compression memory resources */
} 15, 9,
} /* compression strategy (image data are filtered)*/
compress_type);
if (err < 0) {
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
/* Ready to decode */ if (context->dictionary && context->dictionary_size > 0) {
state->state = 1; err = deflateSetDictionary(&context->z_stream, (unsigned char *)context->dictionary,
context->dictionary_size);
if (err < 0) {
state->errcode = IMAGING_CODEC_CONFIG;
return -1;
}
}
/* Ready to decode */
state->state = 1;
} }
@ -116,222 +123,222 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
context->z_stream.next_out = buf; context->z_stream.next_out = buf;
context->z_stream.avail_out = bytes; context->z_stream.avail_out = bytes;
if (context->z_stream.next_in && context->z_stream.avail_in > 0) { if (context->z_stream.next_in && context->z_stream.avail_in > 0) {
/* We have some data from previous round, deflate it first */ /* We have some data from previous round, deflate it first */
err = deflate(&context->z_stream, Z_NO_FLUSH); err = deflate(&context->z_stream, Z_NO_FLUSH);
if (err < 0) { if (err < 0) {
/* Something went wrong inside the compression library */ /* Something went wrong inside the compression library */
if (err == Z_DATA_ERROR) if (err == Z_DATA_ERROR)
state->errcode = IMAGING_CODEC_BROKEN; state->errcode = IMAGING_CODEC_BROKEN;
else if (err == Z_MEM_ERROR) else if (err == Z_MEM_ERROR)
state->errcode = IMAGING_CODEC_MEMORY; state->errcode = IMAGING_CODEC_MEMORY;
else else
state->errcode = IMAGING_CODEC_CONFIG; state->errcode = IMAGING_CODEC_CONFIG;
free(context->paeth); free(context->paeth);
free(context->average); free(context->average);
free(context->up); free(context->up);
free(context->prior); free(context->prior);
free(context->previous); free(context->previous);
deflateEnd(&context->z_stream); deflateEnd(&context->z_stream);
return -1; return -1;
} }
} }
ImagingSectionEnter(&cookie); ImagingSectionEnter(&cookie);
for (;;) { for (;;) {
switch (state->state) { switch (state->state) {
case 1: case 1:
/* Compress image data */ /* Compress image data */
while (context->z_stream.avail_out > 0) { while (context->z_stream.avail_out > 0) {
if (state->y >= state->ysize) { if (state->y >= state->ysize) {
/* End of image; now flush compressor buffers */ /* End of image; now flush compressor buffers */
state->state = 2; state->state = 2;
break; break;
} }
/* Stuff image data into the compressor */ /* Stuff image data into the compressor */
state->shuffle(state->buffer+1, state->shuffle(state->buffer+1,
(UINT8*) im->image[state->y + state->yoff] + (UINT8*) im->image[state->y + state->yoff] +
state->xoff * im->pixelsize, state->xoff * im->pixelsize,
state->xsize); state->xsize);
state->y++; state->y++;
context->output = state->buffer; context->output = state->buffer;
if (context->mode == ZIP_PNG) { if (context->mode == ZIP_PNG) {
/* Filter the image data. For each line, select /* Filter the image data. For each line, select
the filter that gives the least total distance the filter that gives the least total distance
from zero for the filtered data (taken from from zero for the filtered data (taken from
LIBPNG) */ LIBPNG) */
bpp = (state->bits + 7) / 8; bpp = (state->bits + 7) / 8;
/* 0. No filter */ /* 0. No filter */
for (i = 1, sum = 0; i <= state->bytes; i++) { for (i = 1, sum = 0; i <= state->bytes; i++) {
UINT8 v = state->buffer[i]; UINT8 v = state->buffer[i];
sum += (v < 128) ? v : 256 - v; sum += (v < 128) ? v : 256 - v;
} }
/* 2. Up. We'll test this first to save time when /* 2. Up. We'll test this first to save time when
an image line is identical to the one above. */ an image line is identical to the one above. */
if (sum > 0) { if (sum > 0) {
for (i = 1, s = 0; i <= state->bytes; i++) { for (i = 1, s = 0; i <= state->bytes; i++) {
UINT8 v = state->buffer[i] - context->previous[i]; UINT8 v = state->buffer[i] - context->previous[i];
context->up[i] = v; context->up[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
if (s < sum) { if (s < sum) {
context->output = context->up; context->output = context->up;
sum = s; /* 0 if line was duplicated */ sum = s; /* 0 if line was duplicated */
} }
} }
/* 1. Prior */ /* 1. Prior */
if (sum > 0) { if (sum > 0) {
for (i = 1, s = 0; i <= bpp; i++) { for (i = 1, s = 0; i <= bpp; i++) {
UINT8 v = state->buffer[i]; UINT8 v = state->buffer[i];
context->prior[i] = v; context->prior[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
for (; i <= state->bytes; i++) { for (; i <= state->bytes; i++) {
UINT8 v = state->buffer[i] - state->buffer[i-bpp]; UINT8 v = state->buffer[i] - state->buffer[i-bpp];
context->prior[i] = v; context->prior[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
if (s < sum) { if (s < sum) {
context->output = context->prior; context->output = context->prior;
sum = s; /* 0 if line is solid */ sum = s; /* 0 if line is solid */
} }
} }
/* 3. Average (not very common in real-life images, /* 3. Average (not very common in real-life images,
so its only used with the optimize option) */ so its only used with the optimize option) */
if (context->optimize && sum > 0) { if (context->optimize && sum > 0) {
for (i = 1, s = 0; i <= bpp; i++) { for (i = 1, s = 0; i <= bpp; i++) {
UINT8 v = state->buffer[i] - context->previous[i]/2; UINT8 v = state->buffer[i] - context->previous[i]/2;
context->average[i] = v; context->average[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
for (; i <= state->bytes; i++) { for (; i <= state->bytes; i++) {
UINT8 v = state->buffer[i] - UINT8 v = state->buffer[i] -
(state->buffer[i-bpp] + context->previous[i])/2; (state->buffer[i-bpp] + context->previous[i])/2;
context->average[i] = v; context->average[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
if (s < sum) { if (s < sum) {
context->output = context->average; context->output = context->average;
sum = s; sum = s;
} }
} }
/* 4. Paeth */ /* 4. Paeth */
if (sum > 0) { if (sum > 0) {
for (i = 1, s = 0; i <= bpp; i++) { for (i = 1, s = 0; i <= bpp; i++) {
UINT8 v = state->buffer[i] - context->previous[i]; UINT8 v = state->buffer[i] - context->previous[i];
context->paeth[i] = v; context->paeth[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
for (; i <= state->bytes; i++) { for (; i <= state->bytes; i++) {
UINT8 v; UINT8 v;
int a, b, c; int a, b, c;
int pa, pb, pc; int pa, pb, pc;
/* fetch pixels */ /* fetch pixels */
a = state->buffer[i-bpp]; a = state->buffer[i-bpp];
b = context->previous[i]; b = context->previous[i];
c = context->previous[i-bpp]; c = context->previous[i-bpp];
/* distances to surrounding pixels */ /* distances to surrounding pixels */
pa = abs(b - c); pa = abs(b - c);
pb = abs(a - c); pb = abs(a - c);
pc = abs(a + b - 2*c); pc = abs(a + b - 2*c);
/* pick predictor with the shortest distance */ /* pick predictor with the shortest distance */
v = state->buffer[i] - v = state->buffer[i] -
((pa <= pb && pa <= pc) ? a : ((pa <= pb && pa <= pc) ? a :
(pb <= pc) ? b : c); (pb <= pc) ? b : c);
context->paeth[i] = v; context->paeth[i] = v;
s += (v < 128) ? v : 256 - v; s += (v < 128) ? v : 256 - v;
} }
if (s < sum) { if (s < sum) {
context->output = context->paeth; context->output = context->paeth;
sum = s; sum = s;
} }
} }
} }
/* Compress this line */ /* Compress this line */
context->z_stream.next_in = context->output; context->z_stream.next_in = context->output;
context->z_stream.avail_in = state->bytes+1; context->z_stream.avail_in = state->bytes+1;
err = deflate(&context->z_stream, Z_NO_FLUSH); err = deflate(&context->z_stream, Z_NO_FLUSH);
if (err < 0) { if (err < 0) {
/* Something went wrong inside the compression library */ /* Something went wrong inside the compression library */
if (err == Z_DATA_ERROR) if (err == Z_DATA_ERROR)
state->errcode = IMAGING_CODEC_BROKEN; state->errcode = IMAGING_CODEC_BROKEN;
else if (err == Z_MEM_ERROR) else if (err == Z_MEM_ERROR)
state->errcode = IMAGING_CODEC_MEMORY; state->errcode = IMAGING_CODEC_MEMORY;
else else
state->errcode = IMAGING_CODEC_CONFIG; state->errcode = IMAGING_CODEC_CONFIG;
free(context->paeth); free(context->paeth);
free(context->average); free(context->average);
free(context->up); free(context->up);
free(context->prior); free(context->prior);
free(context->previous); free(context->previous);
deflateEnd(&context->z_stream); deflateEnd(&context->z_stream);
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
return -1; return -1;
} }
/* Swap buffer pointers */ /* Swap buffer pointers */
ptr = state->buffer; ptr = state->buffer;
state->buffer = context->previous; state->buffer = context->previous;
context->previous = ptr; context->previous = ptr;
} }
if (context->z_stream.avail_out == 0) if (context->z_stream.avail_out == 0)
break; /* Buffer full */ break; /* Buffer full */
case 2: case 2:
/* End of image data; flush compressor buffers */ /* End of image data; flush compressor buffers */
while (context->z_stream.avail_out > 0) { while (context->z_stream.avail_out > 0) {
err = deflate(&context->z_stream, Z_FINISH); err = deflate(&context->z_stream, Z_FINISH);
if (err == Z_STREAM_END) { if (err == Z_STREAM_END) {
free(context->paeth); free(context->paeth);
free(context->average); free(context->average);
free(context->up); free(context->up);
free(context->prior); free(context->prior);
free(context->previous); free(context->previous);
deflateEnd(&context->z_stream); deflateEnd(&context->z_stream);
state->errcode = IMAGING_CODEC_END; state->errcode = IMAGING_CODEC_END;
break; break;
} }
if (context->z_stream.avail_out == 0) if (context->z_stream.avail_out == 0)
break; /* Buffer full */ break; /* Buffer full */
} }
} }
ImagingSectionLeave(&cookie); ImagingSectionLeave(&cookie);
return bytes - context->z_stream.avail_out; return bytes - context->z_stream.avail_out;
} }
@ -341,6 +348,24 @@ ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
return -1; return -1;
} }
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
int
ImagingZipEncodeCleanup(ImagingCodecState state) {
ZIPSTATE* context = (ZIPSTATE*) state->context;
if (context->dictionary) {
free (context->dictionary);
context->dictionary = NULL;
}
return -1;
}
const char* const char*
ImagingZipVersion(void) ImagingZipVersion(void)
{ {

201
path.c
View File

@ -37,7 +37,7 @@ extern int PyImaging_CheckBuffer(PyObject* buffer);
extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view); extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Class */ /* Class */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
typedef struct { typedef struct {
@ -86,7 +86,7 @@ path_new(Py_ssize_t count, double* xy, int duplicate)
path = PyObject_New(PyPathObject, &PyPathType); path = PyObject_New(PyPathObject, &PyPathType);
if (path == NULL) if (path == NULL)
return NULL; return NULL;
path->count = count; path->count = count;
path->xy = xy; path->xy = xy;
@ -102,26 +102,26 @@ path_dealloc(PyPathObject* path)
} }
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Helpers */ /* Helpers */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
#define PyPath_Check(op) (Py_TYPE(op) == &PyPathType) #define PyPath_Check(op) (Py_TYPE(op) == &PyPathType)
int Py_ssize_t
PyPath_Flatten(PyObject* data, double **pxy) PyPath_Flatten(PyObject* data, double **pxy)
{ {
int i, j, n; Py_ssize_t i, j, n;
double *xy; double *xy;
if (PyPath_Check(data)) { if (PyPath_Check(data)) {
/* This was another path object. */ /* This was another path object. */
PyPathObject *path = (PyPathObject*) data; PyPathObject *path = (PyPathObject*) data;
xy = alloc_array(path->count); xy = alloc_array(path->count);
if (!xy) if (!xy)
return -1; return -1;
memcpy(xy, path->xy, 2 * path->count * sizeof(double)); memcpy(xy, path->xy, 2 * path->count * sizeof(double));
*pxy = xy; *pxy = xy;
return path->count; return path->count;
} }
if (PyImaging_CheckBuffer(data)) { if (PyImaging_CheckBuffer(data)) {
@ -143,8 +143,8 @@ PyPath_Flatten(PyObject* data, double **pxy)
} }
if (!PySequence_Check(data)) { if (!PySequence_Check(data)) {
PyErr_SetString(PyExc_TypeError, "argument must be sequence"); PyErr_SetString(PyExc_TypeError, "argument must be sequence");
return -1; return -1;
} }
j = 0; j = 0;
@ -156,7 +156,7 @@ PyPath_Flatten(PyObject* data, double **pxy)
/* Allocate for worst case */ /* Allocate for worst case */
xy = alloc_array(n); xy = alloc_array(n);
if (!xy) if (!xy)
return -1; return -1;
/* Copy table to path array */ /* Copy table to path array */
if (PyList_Check(data)) { if (PyList_Check(data)) {
@ -164,9 +164,9 @@ PyPath_Flatten(PyObject* data, double **pxy)
double x, y; double x, y;
PyObject *op = PyList_GET_ITEM(data, i); PyObject *op = PyList_GET_ITEM(data, i);
if (PyFloat_Check(op)) if (PyFloat_Check(op))
xy[j++] = PyFloat_AS_DOUBLE(op); xy[j++] = PyFloat_AS_DOUBLE(op);
else if (PyInt_Check(op)) else if (PyInt_Check(op))
xy[j++] = (float) PyInt_AS_LONG(op); xy[j++] = (float) PyInt_AS_LONG(op);
else if (PyNumber_Check(op)) else if (PyNumber_Check(op))
xy[j++] = PyFloat_AsDouble(op); xy[j++] = PyFloat_AsDouble(op);
else if (PyArg_ParseTuple(op, "dd", &x, &y)) { else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
@ -182,9 +182,9 @@ PyPath_Flatten(PyObject* data, double **pxy)
double x, y; double x, y;
PyObject *op = PyTuple_GET_ITEM(data, i); PyObject *op = PyTuple_GET_ITEM(data, i);
if (PyFloat_Check(op)) if (PyFloat_Check(op))
xy[j++] = PyFloat_AS_DOUBLE(op); xy[j++] = PyFloat_AS_DOUBLE(op);
else if (PyInt_Check(op)) else if (PyInt_Check(op))
xy[j++] = (float) PyInt_AS_LONG(op); xy[j++] = (float) PyInt_AS_LONG(op);
else if (PyNumber_Check(op)) else if (PyNumber_Check(op))
xy[j++] = PyFloat_AsDouble(op); xy[j++] = PyFloat_AsDouble(op);
else if (PyArg_ParseTuple(op, "dd", &x, &y)) { else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
@ -211,9 +211,9 @@ PyPath_Flatten(PyObject* data, double **pxy)
} }
} }
if (PyFloat_Check(op)) if (PyFloat_Check(op))
xy[j++] = PyFloat_AS_DOUBLE(op); xy[j++] = PyFloat_AS_DOUBLE(op);
else if (PyInt_Check(op)) else if (PyInt_Check(op))
xy[j++] = (float) PyInt_AS_LONG(op); xy[j++] = (float) PyInt_AS_LONG(op);
else if (PyNumber_Check(op)) else if (PyNumber_Check(op))
xy[j++] = PyFloat_AsDouble(op); xy[j++] = PyFloat_AsDouble(op);
else if (PyArg_ParseTuple(op, "dd", &x, &y)) { else if (PyArg_ParseTuple(op, "dd", &x, &y)) {
@ -229,9 +229,9 @@ PyPath_Flatten(PyObject* data, double **pxy)
} }
if (j & 1) { if (j & 1) {
PyErr_SetString(PyExc_ValueError, "wrong number of coordinates"); PyErr_SetString(PyExc_ValueError, "wrong number of coordinates");
free(xy); free(xy);
return -1; return -1;
} }
*pxy = xy; *pxy = xy;
@ -240,7 +240,7 @@ PyPath_Flatten(PyObject* data, double **pxy)
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Factories */ /* Factories */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
PyObject* PyObject*
@ -274,7 +274,7 @@ PyPath_Create(PyObject* self, PyObject* args)
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Methods */ /* Methods */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
static PyObject* static PyObject*
@ -283,29 +283,30 @@ path_compact(PyPathObject* self, PyObject* args)
/* Simple-minded method to shorten path. A point is removed if /* Simple-minded method to shorten path. A point is removed if
the city block distance to the previous point is less than the the city block distance to the previous point is less than the
given distance */ given distance */
int i, j; Py_ssize_t i, j;
double *xy; double *xy;
double cityblock = 2.0; double cityblock = 2.0;
if (!PyArg_ParseTuple(args, "|d:compact", &cityblock)) if (!PyArg_ParseTuple(args, "|d:compact", &cityblock))
return NULL; return NULL;
xy = self->xy; xy = self->xy;
/* remove bogus vertices */ /* remove bogus vertices */
for (i = j = 1; i < self->count; i++) { for (i = j = 1; i < self->count; i++) {
if (fabs(xy[j+j-2]-xy[i+i]) + fabs(xy[j+j-1]-xy[i+i+1]) >= cityblock) { if (fabs(xy[j+j-2]-xy[i+i]) + fabs(xy[j+j-1]-xy[i+i+1]) >= cityblock) {
xy[j+j] = xy[i+i]; xy[j+j] = xy[i+i];
xy[j+j+1] = xy[i+i+1]; xy[j+j+1] = xy[i+i+1];
j++; j++;
} }
} }
i = self->count - j; i = self->count - j;
self->count = j; self->count = j;
/* shrink coordinate array */ /* shrink coordinate array */
/* malloc check ok, self->count is smaller than it was before */
self->xy = realloc(self->xy, 2 * self->count * sizeof(double)); self->xy = realloc(self->xy, 2 * self->count * sizeof(double));
return Py_BuildValue("i", i); /* number of removed vertices */ return Py_BuildValue("i", i); /* number of removed vertices */
@ -331,12 +332,12 @@ static PyObject*
path_getbbox(PyPathObject* self, PyObject* args) path_getbbox(PyPathObject* self, PyObject* args)
{ {
/* Find bounding box */ /* Find bounding box */
int i; Py_ssize_t i;
double *xy; double *xy;
double x0, y0, x1, y1; double x0, y0, x1, y1;
if (!PyArg_ParseTuple(args, ":getbbox")) if (!PyArg_ParseTuple(args, ":getbbox"))
return NULL; return NULL;
xy = self->xy; xy = self->xy;
@ -344,27 +345,27 @@ path_getbbox(PyPathObject* self, PyObject* args)
y0 = y1 = xy[1]; y0 = y1 = xy[1];
for (i = 1; i < self->count; i++) { for (i = 1; i < self->count; i++) {
if (xy[i+i] < x0) if (xy[i+i] < x0)
x0 = xy[i+i]; x0 = xy[i+i];
if (xy[i+i] > x1) if (xy[i+i] > x1)
x1 = xy[i+i]; x1 = xy[i+i];
if (xy[i+i+1] < y0) if (xy[i+i+1] < y0)
y0 = xy[i+i+1]; y0 = xy[i+i+1];
if (xy[i+i+1] > y1) if (xy[i+i+1] > y1)
y1 = xy[i+i+1]; y1 = xy[i+i+1];
} }
return Py_BuildValue("dddd", x0, y0, x1, y1); return Py_BuildValue("dddd", x0, y0, x1, y1);
} }
static PyObject* static PyObject*
path_getitem(PyPathObject* self, int i) path_getitem(PyPathObject* self, Py_ssize_t i)
{ {
if (i < 0) if (i < 0)
i = self->count + i; i = self->count + i;
if (i < 0 || i >= self->count) { if (i < 0 || i >= self->count) {
PyErr_SetString(PyExc_IndexError, "path index out of range"); PyErr_SetString(PyExc_IndexError, "path index out of range");
return NULL; return NULL;
} }
return Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]); return Py_BuildValue("dd", self->xy[i+i], self->xy[i+i+1]);
@ -398,27 +399,27 @@ static PyObject*
path_map(PyPathObject* self, PyObject* args) path_map(PyPathObject* self, PyObject* args)
{ {
/* Map coordinate set through function */ /* Map coordinate set through function */
int i; Py_ssize_t i;
double *xy; double *xy;
PyObject* function; PyObject* function;
if (!PyArg_ParseTuple(args, "O:map", &function)) if (!PyArg_ParseTuple(args, "O:map", &function))
return NULL; return NULL;
xy = self->xy; xy = self->xy;
/* apply function to coordinate set */ /* apply function to coordinate set */
for (i = 0; i < self->count; i++) { for (i = 0; i < self->count; i++) {
double x = xy[i+i]; double x = xy[i+i];
double y = xy[i+i+1]; double y = xy[i+i+1];
PyObject* item = PyObject_CallFunction(function, "dd", x, y); PyObject* item = PyObject_CallFunction(function, "dd", x, y);
if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) { if (!item || !PyArg_ParseTuple(item, "dd", &x, &y)) {
Py_XDECREF(item); Py_XDECREF(item);
return NULL; return NULL;
} }
xy[i+i] = x; xy[i+i] = x;
xy[i+i+1] = y; xy[i+i+1] = y;
Py_DECREF(item); Py_DECREF(item);
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -426,7 +427,7 @@ path_map(PyPathObject* self, PyObject* args)
} }
static int static int
path_setitem(PyPathObject* self, int i, PyObject* op) path_setitem(PyPathObject* self, Py_ssize_t i, PyObject* op)
{ {
double* xy; double* xy;
@ -454,11 +455,11 @@ static PyObject*
path_tolist(PyPathObject* self, PyObject* args) path_tolist(PyPathObject* self, PyObject* args)
{ {
PyObject *list; PyObject *list;
int i; Py_ssize_t i;
int flat = 0; int flat = 0;
if (!PyArg_ParseTuple(args, "|i:tolist", &flat)) if (!PyArg_ParseTuple(args, "|i:tolist", &flat))
return NULL; return NULL;
if (flat) { if (flat) {
list = PyList_New(self->count*2); list = PyList_New(self->count*2);
@ -491,39 +492,39 @@ static PyObject*
path_transform(PyPathObject* self, PyObject* args) path_transform(PyPathObject* self, PyObject* args)
{ {
/* Apply affine transform to coordinate set */ /* Apply affine transform to coordinate set */
int i; Py_ssize_t i;
double *xy; double *xy;
double a, b, c, d, e, f; double a, b, c, d, e, f;
double wrap = 0.0; double wrap = 0.0;
if (!PyArg_ParseTuple(args, "(dddddd)|d:transform", if (!PyArg_ParseTuple(args, "(dddddd)|d:transform",
&a, &b, &c, &d, &e, &f, &a, &b, &c, &d, &e, &f,
&wrap)) &wrap))
return NULL; return NULL;
xy = self->xy; xy = self->xy;
/* transform the coordinate set */ /* transform the coordinate set */
if (b == 0.0 && d == 0.0) if (b == 0.0 && d == 0.0)
/* scaling */ /* scaling */
for (i = 0; i < self->count; i++) { for (i = 0; i < self->count; i++) {
xy[i+i] = a*xy[i+i]+c; xy[i+i] = a*xy[i+i]+c;
xy[i+i+1] = e*xy[i+i+1]+f; xy[i+i+1] = e*xy[i+i+1]+f;
} }
else else
/* affine transform */ /* affine transform */
for (i = 0; i < self->count; i++) { for (i = 0; i < self->count; i++) {
double x = xy[i+i]; double x = xy[i+i];
double y = xy[i+i+1]; double y = xy[i+i+1];
xy[i+i] = a*x+b*y+c; xy[i+i] = a*x+b*y+c;
xy[i+i+1] = d*x+e*y+f; xy[i+i+1] = d*x+e*y+f;
} }
/* special treatment of geographical map data */ /* special treatment of geographical map data */
if (wrap != 0.0) if (wrap != 0.0)
for (i = 0; i < self->count; i++) for (i = 0; i < self->count; i++)
xy[i+i] = fmod(xy[i+i], wrap); xy[i+i] = fmod(xy[i+i], wrap);
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
@ -543,7 +544,7 @@ static struct PyMethodDef methods[] = {
static PyObject* static PyObject*
path_getattr_id(PyPathObject* self, void* closure) path_getattr_id(PyPathObject* self, void* closure)
{ {
return Py_BuildValue("n", (Py_ssize_t) self->xy); return Py_BuildValue("n", (Py_ssize_t) self->xy);
} }
static struct PyGetSetDef getsetters[] = { static struct PyGetSetDef getsetters[] = {
@ -593,13 +594,13 @@ path_subscript(PyPathObject* self, PyObject* item) {
} }
static PySequenceMethods path_as_sequence = { static PySequenceMethods path_as_sequence = {
(lenfunc)path_len, /*sq_length*/ (lenfunc)path_len, /*sq_length*/
(binaryfunc)0, /*sq_concat*/ (binaryfunc)0, /*sq_concat*/
(ssizeargfunc)0, /*sq_repeat*/ (ssizeargfunc)0, /*sq_repeat*/
(ssizeargfunc)path_getitem, /*sq_item*/ (ssizeargfunc)path_getitem, /*sq_item*/
(ssizessizeargfunc)path_getslice, /*sq_slice*/ (ssizessizeargfunc)path_getslice, /*sq_slice*/
(ssizeobjargproc)path_setitem, /*sq_ass_item*/ (ssizeobjargproc)path_setitem, /*sq_ass_item*/
(ssizessizeobjargproc)0, /*sq_ass_slice*/ (ssizessizeobjargproc)0, /*sq_ass_slice*/
}; };
static PyMappingMethods path_as_mapping = { static PyMappingMethods path_as_mapping = {
@ -609,19 +610,19 @@ static PyMappingMethods path_as_mapping = {
}; };
static PyTypeObject PyPathType = { static PyTypeObject PyPathType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"Path", /*tp_name*/ "Path", /*tp_name*/
sizeof(PyPathObject), /*tp_size*/ sizeof(PyPathObject), /*tp_size*/
0, /*tp_itemsize*/ 0, /*tp_itemsize*/
/* methods */ /* methods */
(destructor)path_dealloc, /*tp_dealloc*/ (destructor)path_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
0, /*tp_getattr*/ 0, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
0, /*tp_repr*/ 0, /*tp_repr*/
0, /*tp_as_number */ 0, /*tp_as_number */
&path_as_sequence, /*tp_as_sequence */ &path_as_sequence, /*tp_as_sequence */
&path_as_mapping, /*tp_as_mapping */ &path_as_mapping, /*tp_as_mapping */
0, /*tp_hash*/ 0, /*tp_hash*/
0, /*tp_call*/ 0, /*tp_call*/