From 7de6ab51083dded582649a03d2a52ac2733bac6f Mon Sep 17 00:00:00 2001 From: Brian Crowell Date: Sun, 14 Oct 2012 11:38:06 -0500 Subject: [PATCH] py3k: Use "y#" code in PyArg_ParseTuple where we expect byte data This commit also renames some functions from "fromstring" and the like to "frombytes". I'll probably need to come back later and update any references to "string," here or in the docs. I also noticed that encode allocates some data for certain codecs, but never frees them. That would be a good bug to fix. I fixed the one where it outright stole a pointer from Python. --- _imaging.c | 12 +++++++----- _imagingcms.c | 9 +++++++++ decode.c | 3 ++- display.c | 25 +++++++++++++++++++++---- encode.c | 24 +++++++++++++++++++----- py3.h | 5 ++++- 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/_imaging.c b/_imaging.c index 610710bd1..6276bc678 100644 --- a/_imaging.c +++ b/_imaging.c @@ -1366,7 +1366,7 @@ _putpalette(ImagingObject* self, PyObject* args) char* rawmode; UINT8* palette; int palettesize; - if (!PyArg_ParseTuple(args, "ss#", &rawmode, &palette, &palettesize)) + if (!PyArg_ParseTuple(args, "s"PY_ARG_BYTES_LENGTH, &rawmode, &palette, &palettesize)) return NULL; if (strcmp(self->image->mode, "L") != 0 && strcmp(self->image->mode, "P")) { @@ -1861,8 +1861,9 @@ _getprojection(ImagingObject* self, PyObject* args) ImagingGetProjection(self->image, (unsigned char *)xprofile, (unsigned char *)yprofile); - result = Py_BuildValue("s#s#", xprofile, self->image->xsize, - yprofile, self->image->ysize); + result = Py_BuildValue(PY_ARG_BYTES_LENGTH PY_ARG_BYTES_LENGTH, + xprofile, self->image->xsize, + yprofile, self->image->ysize); free(xprofile); free(yprofile); @@ -2089,7 +2090,7 @@ _font_new(PyObject* self_, PyObject* args) ImagingObject* imagep; unsigned char* glyphdata; int glyphdata_length; - if (!PyArg_ParseTuple(args, "O!s#", + if (!PyArg_ParseTuple(args, "O!"PY_ARG_BYTES_LENGTH, &Imaging_Type, &imagep, &glyphdata, &glyphdata_length)) return NULL; @@ -2787,7 +2788,8 @@ _crc32(PyObject* self, PyObject* args) hi = lo = 0; - if (!PyArg_ParseTuple(args, "s#|(ii)", &buffer, &bytes, &hi, &lo)) + if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"|(ii)", + &buffer, &bytes, &hi, &lo)) return NULL; crc = ((UINT32) (hi & 0xFFFF) << 16) + (lo & 0xFFFF); diff --git a/_imagingcms.c b/_imagingcms.c index 693de5c3b..910dc6eeb 100644 --- a/_imagingcms.c +++ b/_imagingcms.c @@ -129,8 +129,13 @@ cms_profile_fromstring(PyObject* self, PyObject* args) char* pProfile; int nProfile; +#if PY_VERSION_HEX >= 0x03000000 + if (!PyArg_ParseTuple(args, "y#:profile_frombytes", &pProfile, &nProfile)) + return NULL; +#else if (!PyArg_ParseTuple(args, "s#:profile_fromstring", &pProfile, &nProfile)) return NULL; +#endif cmsErrorAction(LCMS_ERROR_IGNORE); @@ -496,7 +501,11 @@ cms_get_display_profile_win32(PyObject* self, PyObject* args) static PyMethodDef pyCMSdll_methods[] = { {"profile_open", cms_profile_open, 1}, +#if PY_VERSION_HEX >= 0x03000000 + {"profile_frombytes", cms_profile_fromstring, 1}, +#else {"profile_fromstring", cms_profile_fromstring, 1}, +#endif /* profile and transform functions */ {"buildTransform", buildTransform, 1}, diff --git a/decode.c b/decode.c index 6f5fe278f..0b2be8dfd 100644 --- a/decode.c +++ b/decode.c @@ -37,6 +37,7 @@ #endif #include "Imaging.h" +#include "py3.h" #include "Gif.h" #include "Lzw.h" @@ -111,7 +112,7 @@ _decode(ImagingDecoderObject* decoder, PyObject* args) UINT8* buffer; int bufsize, status; - if (!PyArg_ParseTuple(args, "s#", &buffer, &bufsize)) + if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH, &buffer, &bufsize)) return NULL; status = decoder->decode(decoder->im, &decoder->state, buffer, bufsize); diff --git a/display.c b/display.c index b334fbc95..9571b1cbe 100644 --- a/display.c +++ b/display.c @@ -31,6 +31,7 @@ #endif #include "Imaging.h" +#include "py3.h" /* -------------------------------------------------------------------- */ /* Windows DIB support */ @@ -183,8 +184,14 @@ _fromstring(ImagingDisplayObject* display, PyObject* args) { char* ptr; int bytes; + +#if PY_VERSION_HEX >= 0x03000000 + if (!PyArg_ParseTuple(args, "y#:frombytes", &ptr, &bytes)) + return NULL; +#else if (!PyArg_ParseTuple(args, "s#:fromstring", &ptr, &bytes)) - return NULL; + return NULL; +#endif if (display->dib->ysize * display->dib->linesize != bytes) { PyErr_SetString(PyExc_ValueError, "wrong size"); @@ -200,10 +207,15 @@ _fromstring(ImagingDisplayObject* display, PyObject* args) static PyObject* _tostring(ImagingDisplayObject* display, PyObject* args) { +#if PY_VERSION_HEX >= 0x03000000 + if (!PyArg_ParseTuple(args, ":tobytes")) + return NULL; +#else if (!PyArg_ParseTuple(args, ":tostring")) - return NULL; + return NULL; +#endif - return PyString_FromStringAndSize( + return PyBytes_FromStringAndSize( display->dib->bits, display->dib->ysize * display->dib->linesize ); } @@ -215,8 +227,13 @@ static struct PyMethodDef methods[] = { {"query_palette", (PyCFunction)_query_palette, 1}, {"getdc", (PyCFunction)_getdc, 1}, {"releasedc", (PyCFunction)_releasedc, 1}, +#if PY_VERSION_HEX >= 0x03000000 + {"frombytes", (PyCFunction)_fromstring, 1}, + {"tobytes", (PyCFunction)_tostring, 1}, +#else {"fromstring", (PyCFunction)_fromstring, 1}, {"tostring", (PyCFunction)_tostring, 1}, +#endif {NULL, NULL} /* sentinel */ }; @@ -771,7 +788,7 @@ PyImaging_DrawWmf(PyObject* self, PyObject* args) int datasize; int width, height; int x0, y0, x1, y1; - if (!PyArg_ParseTuple(args, "s#(ii)(iiii):_load", &data, &datasize, + if (!PyArg_ParseTuple(args, PY_ARG_BYTES_LENGTH"(ii)(iiii):_load", &data, &datasize, &width, &height, &x0, &x1, &y0, &y1)) return NULL; diff --git a/encode.c b/encode.c index 939fc6b93..670bd7dc9 100644 --- a/encode.c +++ b/encode.c @@ -30,6 +30,7 @@ #endif #include "Imaging.h" +#include "py3.h" #include "Gif.h" #ifdef HAVE_UNISTD_H @@ -451,9 +452,21 @@ PyImaging_ZipEncoderNew(PyObject* self, PyObject* args) int optimize = 0; char* dictionary = NULL; int dictionary_size = 0; - if (!PyArg_ParseTuple(args, "ss|is#", &mode, &rawmode, &optimize, - &dictionary, &dictionary_size)) - return NULL; + if (!PyArg_ParseTuple(args, "ss|i"PY_ARG_BYTES_LENGTH, &mode, &rawmode, + &optimize, &dictionary, &dictionary_size)) + return NULL; + + /* Copy to avoid referencing Python's memory, but there's no mechanism to + free this memory later, so this function (and several others here) + leaks. */ + if (dictionary && dictionary_size > 0) { + char* p = malloc(dictionary_size); + if (!p) + return PyErr_NoMemory(); + memcpy(p, dictionary, dictionary_size); + dictionary = p; + } else + dictionary = NULL; encoder = PyImaging_EncoderNew(sizeof(ZIPSTATE)); if (encoder == NULL) @@ -513,8 +526,9 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) int xdpi = 0, ydpi = 0; int subsampling = -1; /* -1=default, 0=none, 1=medium, 2=high */ char* extra = NULL; int extra_size; - if (!PyArg_ParseTuple(args, "ss|iiiiiiiis#", &mode, &rawmode, &quality, - &progressive, &smooth, &optimize, &streamtype, + if (!PyArg_ParseTuple(args, "ss|iiiiiiii"PY_ARG_BYTES_LENGTH, + &mode, &rawmode, &quality, + &progressive, &smooth, &optimize, &streamtype, &xdpi, &ydpi, &subsampling, &extra, &extra_size)) return NULL; diff --git a/py3.h b/py3.h index a0054bb46..e0658b0bb 100644 --- a/py3.h +++ b/py3.h @@ -11,13 +11,16 @@ */ #if PY_VERSION_HEX >= 0x03000000 +#define PY_ARG_BYTES_LENGTH "y#" + /* Map PyInt -> PyLong */ #define PyInt_AsLong PyLong_AsLong #define PyInt_Check PyLong_Check #define PyInt_FromLong PyLong_FromLong #define PyInt_AS_LONG PyLong_AS_LONG -#else +#else /* PY_VERSION_HEX < 0x03000000 */ +#define PY_ARG_BYTES_LENGTH "s#" #if !defined(KEEP_PY_UNICODE) /* Map PyUnicode -> PyString */