diff options
Diffstat (limited to 'Modules/zlibmodule.c')
-rw-r--r-- | Modules/zlibmodule.c | 464 |
1 files changed, 285 insertions, 179 deletions
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 519af940c7e..bb453aed637 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -5,41 +5,19 @@ #include "Python.h" +#include "structmember.h" #include "zlib.h" #ifdef WITH_THREAD -#include "pythread.h" - -/* #defs ripped off from _tkinter.c, even though the situation here is much - simpler, because we don't have to worry about waiting for Tcl - events! And, since zlib itself is threadsafe, we don't need to worry - about re-entering zlib functions. - - N.B. - - Since ENTER_ZLIB and LEAVE_ZLIB only need to be called on functions - that modify the components of preexisting de/compress objects, it - could prove to be a performance gain on multiprocessor machines if - there was an de/compress object-specific lock. However, for the - moment the ENTER_ZLIB and LEAVE_ZLIB calls are global for ALL - de/compress objects. - */ - -static PyThread_type_lock zlib_lock = NULL; /* initialized on module load */ - -#define ENTER_ZLIB \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock(zlib_lock, 1); \ - Py_END_ALLOW_THREADS - -#define LEAVE_ZLIB \ - PyThread_release_lock(zlib_lock); - + #include "pythread.h" + #define ENTER_ZLIB(obj) \ + Py_BEGIN_ALLOW_THREADS; \ + PyThread_acquire_lock((obj)->lock, 1); \ + Py_END_ALLOW_THREADS; + #define LEAVE_ZLIB(obj) PyThread_release_lock((obj)->lock); #else - -#define ENTER_ZLIB -#define LEAVE_ZLIB - + #define ENTER_ZLIB(obj) + #define LEAVE_ZLIB(obj) #endif /* The following parameters are copied from zutil.h, version 0.95 */ @@ -53,7 +31,6 @@ static PyThread_type_lock zlib_lock = NULL; /* initialized on module load */ /* The output buffer will be increased in chunks of DEFAULTALLOC bytes. */ #define DEFAULTALLOC (16*1024) -#define PyInit_zlib initzlib static PyTypeObject Comptype; static PyTypeObject Decomptype; @@ -67,6 +44,9 @@ typedef struct PyObject *unused_data; PyObject *unconsumed_tail; int is_initialised; + #ifdef WITH_THREAD + PyThread_type_lock lock; + #endif } compobject; static void @@ -116,16 +96,19 @@ newcompobject(PyTypeObject *type) if (self == NULL) return NULL; self->is_initialised = 0; - self->unused_data = PyString_FromString(""); + self->unused_data = PyBytes_FromStringAndSize("", 0); if (self->unused_data == NULL) { Py_DECREF(self); return NULL; } - self->unconsumed_tail = PyString_FromString(""); + self->unconsumed_tail = PyBytes_FromStringAndSize("", 0); if (self->unconsumed_tail == NULL) { Py_DECREF(self); return NULL; } +#ifdef WITH_THREAD + self->lock = PyThread_allocate_lock(); +#endif return self; } @@ -138,21 +121,31 @@ static PyObject * PyZlib_compress(PyObject *self, PyObject *args) { PyObject *ReturnVal = NULL; - Byte *input, *output; - int length, level=Z_DEFAULT_COMPRESSION, err; + Py_buffer pinput; + Byte *input, *output = NULL; + unsigned int length; + int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; /* require Python string object, optional 'level' arg */ - if (!PyArg_ParseTuple(args, "s#|i:compress", &input, &length, &level)) + if (!PyArg_ParseTuple(args, "y*|i:compress", &pinput, &level)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error; + } + input = pinput.buf; + length = pinput.len; + zst.avail_out = length + length/1000 + 12 + 1; output = (Byte*)malloc(zst.avail_out); if (output == NULL) { PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); - return NULL; + goto error; } /* Past the point of no return. From here on out, we need to make sure @@ -194,12 +187,13 @@ PyZlib_compress(PyObject *self, PyObject *args) err=deflateEnd(&zst); if (err == Z_OK) - ReturnVal = PyString_FromStringAndSize((char *)output, - zst.total_out); + ReturnVal = PyBytes_FromStringAndSize((char *)output, + zst.total_out); else zlib_error(zst, err, "while finishing compression"); error: + PyBuffer_Release(&pinput); free(output); return ReturnVal; @@ -214,29 +208,39 @@ PyDoc_STRVAR(decompress__doc__, static PyObject * PyZlib_decompress(PyObject *self, PyObject *args) { - PyObject *result_str; + PyObject *result_str = NULL; + Py_buffer pinput; Byte *input; - int length, err; + unsigned int length; + int err; int wsize=DEF_WBITS; Py_ssize_t r_strlen=DEFAULTALLOC; z_stream zst; - if (!PyArg_ParseTuple(args, "s#|in:decompress", - &input, &length, &wsize, &r_strlen)) + if (!PyArg_ParseTuple(args, "y*|in:decompress", + &pinput, &wsize, &r_strlen)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error; + } + input = pinput.buf; + length = pinput.len; + if (r_strlen <= 0) r_strlen = 1; zst.avail_in = length; zst.avail_out = r_strlen; - if (!(result_str = PyString_FromStringAndSize(NULL, r_strlen))) - return NULL; + if (!(result_str = PyBytes_FromStringAndSize(NULL, r_strlen))) + goto error; zst.zalloc = (alloc_func)NULL; zst.zfree = (free_func)Z_NULL; - zst.next_out = (Byte *)PyString_AS_STRING(result_str); + zst.next_out = (Byte *)PyBytes_AS_STRING(result_str); zst.next_in = (Byte *)input; err = inflateInit2(&zst, wsize); @@ -275,12 +279,12 @@ PyZlib_decompress(PyObject *self, PyObject *args) /* fall through */ case(Z_OK): /* need more memory */ - if (_PyString_Resize(&result_str, r_strlen << 1) < 0) { + if (_PyBytes_Resize(&result_str, r_strlen << 1) < 0) { inflateEnd(&zst); goto error; } - zst.next_out = (unsigned char *)PyString_AS_STRING(result_str) \ - + r_strlen; + zst.next_out = + (unsigned char *)PyBytes_AS_STRING(result_str) + r_strlen; zst.avail_out = r_strlen; r_strlen = r_strlen << 1; break; @@ -297,10 +301,14 @@ PyZlib_decompress(PyObject *self, PyObject *args) goto error; } - _PyString_Resize(&result_str, zst.total_out); + if (_PyBytes_Resize(&result_str, zst.total_out) < 0) + goto error; + + PyBuffer_Release(&pinput); return result_str; error: + PyBuffer_Release(&pinput); Py_XDECREF(result_str); return NULL; } @@ -381,23 +389,30 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args) } static void -Comp_dealloc(compobject *self) +Dealloc(compobject *self) { - if (self->is_initialised) - deflateEnd(&self->zst); +#ifdef WITH_THREAD + PyThread_free_lock(self->lock); +#endif Py_XDECREF(self->unused_data); Py_XDECREF(self->unconsumed_tail); PyObject_Del(self); } static void +Comp_dealloc(compobject *self) +{ + if (self->is_initialised) + deflateEnd(&self->zst); + Dealloc(self); +} + +static void Decomp_dealloc(compobject *self) { if (self->is_initialised) inflateEnd(&self->zst); - Py_XDECREF(self->unused_data); - Py_XDECREF(self->unconsumed_tail); - PyObject_Del(self); + Dealloc(self); } PyDoc_STRVAR(comp_compress__doc__, @@ -411,25 +426,34 @@ PyDoc_STRVAR(comp_compress__doc__, static PyObject * PyZlib_objcompress(compobject *self, PyObject *args) { - int err, inplen; + int err; + unsigned int inplen; Py_ssize_t length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; + Py_buffer pinput; Byte *input; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "s#:compress", &input, &inplen)) + if (!PyArg_ParseTuple(args, "y*:compress", &pinput)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } + input = pinput.buf; + inplen = pinput.len; - if (!(RetVal = PyString_FromStringAndSize(NULL, length))) - return NULL; + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; - ENTER_ZLIB + ENTER_ZLIB(self); start_total_out = self->zst.total_out; self->zst.avail_in = inplen; self->zst.next_in = input; self->zst.avail_out = length; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal); Py_BEGIN_ALLOW_THREADS err = deflate(&(self->zst), Z_NO_FLUSH); @@ -438,10 +462,13 @@ PyZlib_objcompress(compobject *self, PyObject *args) /* while Z_OK and the output buffer is full, there might be more output, so extend the output buffer and try again */ while (err == Z_OK && self->zst.avail_out == 0) { - if (_PyString_Resize(&RetVal, length << 1) < 0) + if (_PyBytes_Resize(&RetVal, length << 1) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; goto error; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ - + length; + } + self->zst.next_out = + (unsigned char *)PyBytes_AS_STRING(RetVal) + length; self->zst.avail_out = length; length = length << 1; @@ -460,10 +487,15 @@ PyZlib_objcompress(compobject *self, PyObject *args) RetVal = NULL; goto error; } - _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; + } error: - LEAVE_ZLIB + LEAVE_ZLIB(self); + error_outer: + PyBuffer_Release(&pinput); return RetVal; } @@ -476,7 +508,7 @@ save_unconsumed_input(compobject *self, int err) /* The end of the compressed data has been reached. Store the leftover input data in self->unused_data. */ if (self->zst.avail_in > 0) { - Py_ssize_t old_size = PyString_GET_SIZE(self->unused_data); + Py_ssize_t old_size = PyBytes_GET_SIZE(self->unused_data); Py_ssize_t new_size; PyObject *new_data; if (self->zst.avail_in > PY_SSIZE_T_MAX - old_size) { @@ -484,23 +516,23 @@ save_unconsumed_input(compobject *self, int err) return -1; } new_size = old_size + self->zst.avail_in; - new_data = PyString_FromStringAndSize(NULL, new_size); + new_data = PyBytes_FromStringAndSize(NULL, new_size); if (new_data == NULL) return -1; - Py_MEMCPY(PyString_AS_STRING(new_data), - PyString_AS_STRING(self->unused_data), old_size); - Py_MEMCPY(PyString_AS_STRING(new_data) + old_size, + Py_MEMCPY(PyBytes_AS_STRING(new_data), + PyBytes_AS_STRING(self->unused_data), old_size); + Py_MEMCPY(PyBytes_AS_STRING(new_data) + old_size, self->zst.next_in, self->zst.avail_in); Py_DECREF(self->unused_data); self->unused_data = new_data; self->zst.avail_in = 0; } } - if (self->zst.avail_in > 0 || PyString_GET_SIZE(self->unconsumed_tail)) { + if (self->zst.avail_in > 0 || PyBytes_GET_SIZE(self->unconsumed_tail)) { /* This code handles two distinct cases: 1. Output limit was reached. Save leftover input in unconsumed_tail. 2. All input data was consumed. Clear unconsumed_tail. */ - PyObject *new_data = PyString_FromStringAndSize( + PyObject *new_data = PyBytes_FromStringAndSize( (char *)self->zst.next_in, self->zst.avail_in); if (new_data == NULL) return -1; @@ -524,34 +556,43 @@ PyDoc_STRVAR(decomp_decompress__doc__, static PyObject * PyZlib_objdecompress(compobject *self, PyObject *args) { - int err, inplen, max_length = 0; + int err, max_length = 0; + unsigned int inplen; Py_ssize_t old_length, length = DEFAULTALLOC; - PyObject *RetVal; + PyObject *RetVal = NULL; + Py_buffer pinput; Byte *input; unsigned long start_total_out; - if (!PyArg_ParseTuple(args, "s#|i:decompress", &input, - &inplen, &max_length)) + if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput, + &max_length)) return NULL; + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "Size does not fit in an unsigned int"); + goto error_outer; + } + input = pinput.buf; + inplen = pinput.len; if (max_length < 0) { PyErr_SetString(PyExc_ValueError, "max_length must be greater than zero"); - return NULL; + goto error_outer; } /* limit amount of data allocated to max_length */ if (max_length && length > max_length) length = max_length; - if (!(RetVal = PyString_FromStringAndSize(NULL, length))) - return NULL; + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) + goto error_outer; - ENTER_ZLIB + ENTER_ZLIB(self); start_total_out = self->zst.total_out; self->zst.avail_in = inplen; self->zst.next_in = input; self->zst.avail_out = length; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal); Py_BEGIN_ALLOW_THREADS err = inflate(&(self->zst), Z_SYNC_FLUSH); @@ -573,10 +614,13 @@ PyZlib_objdecompress(compobject *self, PyObject *args) if (max_length && length > max_length) length = max_length; - if (_PyString_Resize(&RetVal, length) < 0) + if (_PyBytes_Resize(&RetVal, length) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; goto error; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ - + old_length; + } + self->zst.next_out = + (unsigned char *)PyBytes_AS_STRING(RetVal) + old_length; self->zst.avail_out = length - old_length; Py_BEGIN_ALLOW_THREADS @@ -604,11 +648,15 @@ PyZlib_objdecompress(compobject *self, PyObject *args) goto error; } - _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; + } error: - LEAVE_ZLIB - + LEAVE_ZLIB(self); + error_outer: + PyBuffer_Release(&pinput); return RetVal; } @@ -634,18 +682,18 @@ PyZlib_flush(compobject *self, PyObject *args) /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in doing any work at all; just return an empty string. */ if (flushmode == Z_NO_FLUSH) { - return PyString_FromStringAndSize(NULL, 0); + return PyBytes_FromStringAndSize(NULL, 0); } - if (!(RetVal = PyString_FromStringAndSize(NULL, length))) + if (!(RetVal = PyBytes_FromStringAndSize(NULL, length))) return NULL; - ENTER_ZLIB + ENTER_ZLIB(self); start_total_out = self->zst.total_out; self->zst.avail_in = 0; self->zst.avail_out = length; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal); Py_BEGIN_ALLOW_THREADS err = deflate(&(self->zst), flushmode); @@ -654,10 +702,13 @@ PyZlib_flush(compobject *self, PyObject *args) /* while Z_OK and the output buffer is full, there might be more output, so extend the output buffer and try again */ while (err == Z_OK && self->zst.avail_out == 0) { - if (_PyString_Resize(&RetVal, length << 1) < 0) + if (_PyBytes_Resize(&RetVal, length << 1) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; goto error; - self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ - + length; + } + self->zst.next_out = + (unsigned char *)PyBytes_AS_STRING(RetVal) + length; self->zst.avail_out = length; length = length << 1; @@ -691,10 +742,13 @@ PyZlib_flush(compobject *self, PyObject *args) goto error; } - _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) { + Py_DECREF(RetVal); + RetVal = NULL; + } error: - LEAVE_ZLIB + LEAVE_ZLIB(self); return RetVal; } @@ -715,7 +769,7 @@ PyZlib_copy(compobject *self) /* Copy the zstream state * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe */ - ENTER_ZLIB + ENTER_ZLIB(self); err = deflateCopy(&retval->zst, &self->zst); switch(err) { case(Z_OK): @@ -731,7 +785,6 @@ PyZlib_copy(compobject *self) zlib_error(self->zst, err, "while copying compression object"); goto error; } - Py_INCREF(self->unused_data); Py_INCREF(self->unconsumed_tail); Py_XDECREF(retval->unused_data); @@ -742,11 +795,11 @@ PyZlib_copy(compobject *self) /* Mark it as being initialized */ retval->is_initialised = 1; - LEAVE_ZLIB + LEAVE_ZLIB(self); return (PyObject *)retval; error: - LEAVE_ZLIB + LEAVE_ZLIB(self); Py_XDECREF(retval); return NULL; } @@ -766,7 +819,7 @@ PyZlib_uncopy(compobject *self) /* Copy the zstream state * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe */ - ENTER_ZLIB + ENTER_ZLIB(self); err = inflateCopy(&retval->zst, &self->zst); switch(err) { case(Z_OK): @@ -793,11 +846,11 @@ PyZlib_uncopy(compobject *self) /* Mark it as being initialized */ retval->is_initialised = 1; - LEAVE_ZLIB + LEAVE_ZLIB(self); return (PyObject *)retval; error: - LEAVE_ZLIB + LEAVE_ZLIB(self); Py_XDECREF(retval); return NULL; } @@ -823,17 +876,17 @@ PyZlib_unflush(compobject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "length must be greater than zero"); return NULL; } - if (!(retval = PyString_FromStringAndSize(NULL, length))) + if (!(retval = PyBytes_FromStringAndSize(NULL, length))) return NULL; - ENTER_ZLIB + ENTER_ZLIB(self); start_total_out = self->zst.total_out; - self->zst.avail_in = PyString_GET_SIZE(self->unconsumed_tail); - self->zst.next_in = (Byte *)PyString_AS_STRING(self->unconsumed_tail); + self->zst.avail_in = PyBytes_GET_SIZE(self->unconsumed_tail); + self->zst.next_in = (Byte *)PyBytes_AS_STRING(self->unconsumed_tail); self->zst.avail_out = length; - self->zst.next_out = (Byte *)PyString_AS_STRING(retval); + self->zst.next_out = (Byte *)PyBytes_AS_STRING(retval); Py_BEGIN_ALLOW_THREADS err = inflate(&(self->zst), Z_FINISH); @@ -842,9 +895,12 @@ PyZlib_unflush(compobject *self, PyObject *args) /* while Z_OK and the output buffer is full, there might be more output, so extend the output buffer and try again */ while ((err == Z_OK || err == Z_BUF_ERROR) && self->zst.avail_out == 0) { - if (_PyString_Resize(&retval, length << 1) < 0) + if (_PyBytes_Resize(&retval, length << 1) < 0) { + Py_DECREF(retval); + retval = NULL; goto error; - self->zst.next_out = (Byte *)PyString_AS_STRING(retval) + length; + } + self->zst.next_out = (Byte *)PyBytes_AS_STRING(retval) + length; self->zst.avail_out = length; length = length << 1; @@ -873,11 +929,14 @@ PyZlib_unflush(compobject *self, PyObject *args) } } - _PyString_Resize(&retval, self->zst.total_out - start_total_out); + if (_PyBytes_Resize(&retval, self->zst.total_out - start_total_out) < 0) { + Py_DECREF(retval); + retval = NULL; + } error: - LEAVE_ZLIB + LEAVE_ZLIB(self); return retval; } @@ -908,80 +967,86 @@ static PyMethodDef Decomp_methods[] = {NULL, NULL} }; -static PyObject * -Comp_getattr(compobject *self, char *name) -{ - /* No ENTER/LEAVE_ZLIB is necessary because this fn doesn't touch - internal data. */ - - return Py_FindMethod(comp_methods, (PyObject *)self, name); -} - -static PyObject * -Decomp_getattr(compobject *self, char *name) -{ - PyObject * retval; - - ENTER_ZLIB - - if (strcmp(name, "unused_data") == 0) { - Py_INCREF(self->unused_data); - retval = self->unused_data; - } else if (strcmp(name, "unconsumed_tail") == 0) { - Py_INCREF(self->unconsumed_tail); - retval = self->unconsumed_tail; - } else - retval = Py_FindMethod(Decomp_methods, (PyObject *)self, name); - - LEAVE_ZLIB - - return retval; -} +#define COMP_OFF(x) offsetof(compobject, x) +static PyMemberDef Decomp_members[] = { + {"unused_data", T_OBJECT, COMP_OFF(unused_data), READONLY}, + {"unconsumed_tail", T_OBJECT, COMP_OFF(unconsumed_tail), READONLY}, + {NULL}, +}; PyDoc_STRVAR(adler32__doc__, "adler32(string[, start]) -- Compute an Adler-32 checksum of string.\n" "\n" "An optional starting value can be specified. The returned checksum is\n" -"a signed integer."); +"an integer."); static PyObject * PyZlib_adler32(PyObject *self, PyObject *args) { unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */ - Byte *buf; - int len, signed_val; + Py_buffer pbuf; - if (!PyArg_ParseTuple(args, "s#|I:adler32", &buf, &len, &adler32val)) + if (!PyArg_ParseTuple(args, "y*|I:adler32", &pbuf, &adler32val)) return NULL; - /* In Python 2.x we return a signed integer regardless of native platform - * long size (the 32bit unsigned long is treated as 32-bit signed and sign - * extended into a 64-bit long inside the integer object). 3.0 does the - * right thing and returns unsigned. http://bugs.python.org/issue1202 */ - signed_val = adler32(adler32val, buf, len); - return PyInt_FromLong(signed_val); + /* Releasing the GIL for very small buffers is inefficient + and may lower performance */ + if (pbuf.len > 1024*5) { + unsigned char *buf = pbuf.buf; + Py_ssize_t len = pbuf.len; + + Py_BEGIN_ALLOW_THREADS + /* Avoid truncation of length for very large buffers. adler32() takes + length as an unsigned int, which may be narrower than Py_ssize_t. */ + while (len > (size_t) UINT_MAX) { + adler32val = adler32(adler32val, buf, UINT_MAX); + buf += (size_t) UINT_MAX; + len -= (size_t) UINT_MAX; + } + adler32val = adler32(adler32val, buf, len); + Py_END_ALLOW_THREADS + } else { + adler32val = adler32(adler32val, pbuf.buf, pbuf.len); + } + PyBuffer_Release(&pbuf); + return PyLong_FromUnsignedLong(adler32val & 0xffffffffU); } PyDoc_STRVAR(crc32__doc__, "crc32(string[, start]) -- Compute a CRC-32 checksum of string.\n" "\n" "An optional starting value can be specified. The returned checksum is\n" -"a signed integer."); +"an integer."); static PyObject * PyZlib_crc32(PyObject *self, PyObject *args) { unsigned int crc32val = 0; /* crc32(0L, Z_NULL, 0) */ - Byte *buf; - int len, signed_val; + Py_buffer pbuf; + int signed_val; - if (!PyArg_ParseTuple(args, "s#|I:crc32", &buf, &len, &crc32val)) + if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val)) return NULL; - /* In Python 2.x we return a signed integer regardless of native platform - * long size (the 32bit unsigned long is treated as 32-bit signed and sign - * extended into a 64-bit long inside the integer object). 3.0 does the - * right thing and returns unsigned. http://bugs.python.org/issue1202 */ - signed_val = crc32(crc32val, buf, len); - return PyInt_FromLong(signed_val); + /* Releasing the GIL for very small buffers is inefficient + and may lower performance */ + if (pbuf.len > 1024*5) { + unsigned char *buf = pbuf.buf; + Py_ssize_t len = pbuf.len; + + Py_BEGIN_ALLOW_THREADS + /* Avoid truncation of length for very large buffers. crc32() takes + length as an unsigned int, which may be narrower than Py_ssize_t. */ + while (len > (size_t) UINT_MAX) { + crc32val = crc32(crc32val, buf, UINT_MAX); + buf += (size_t) UINT_MAX; + len -= (size_t) UINT_MAX; + } + signed_val = crc32(crc32val, buf, len); + Py_END_ALLOW_THREADS + } else { + signed_val = crc32(crc32val, pbuf.buf, pbuf.len); + } + PyBuffer_Release(&pbuf); + return PyLong_FromUnsignedLong(signed_val & 0xffffffffU); } @@ -1009,13 +1074,28 @@ static PyTypeObject Comptype = { 0, (destructor)Comp_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - (getattrfunc)Comp_getattr, /*tp_getattr*/ + 0, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_compare*/ + 0, /*tp_reserved*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + comp_methods, /*tp_methods*/ }; static PyTypeObject Decomptype = { @@ -1025,13 +1105,29 @@ static PyTypeObject Decomptype = { 0, (destructor)Decomp_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - (getattrfunc)Decomp_getattr, /*tp_getattr*/ + 0, /*tp_getattr*/ 0, /*tp_setattr*/ - 0, /*tp_compare*/ + 0, /*tp_reserved*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + Decomp_methods, /*tp_methods*/ + Decomp_members, /*tp_members*/ }; PyDoc_STRVAR(zlib_module_documentation, @@ -1049,17 +1145,29 @@ PyDoc_STRVAR(zlib_module_documentation, "Compressor objects support compress() and flush() methods; decompressor\n" "objects support decompress() and flush()."); +static struct PyModuleDef zlibmodule = { + PyModuleDef_HEAD_INIT, + "zlib", + zlib_module_documentation, + -1, + zlib_methods, + NULL, + NULL, + NULL, + NULL +}; + PyMODINIT_FUNC PyInit_zlib(void) { PyObject *m, *ver; - Py_TYPE(&Comptype) = &PyType_Type; - Py_TYPE(&Decomptype) = &PyType_Type; - m = Py_InitModule4("zlib", zlib_methods, - zlib_module_documentation, - (PyObject*)NULL,PYTHON_API_VERSION); + if (PyType_Ready(&Comptype) < 0) + return NULL; + if (PyType_Ready(&Decomptype) < 0) + return NULL; + m = PyModule_Create(&zlibmodule); if (m == NULL) - return; + return NULL; ZlibError = PyErr_NewException("zlib.error", NULL, NULL); if (ZlibError != NULL) { @@ -1081,13 +1189,11 @@ PyInit_zlib(void) PyModule_AddIntConstant(m, "Z_SYNC_FLUSH", Z_SYNC_FLUSH); PyModule_AddIntConstant(m, "Z_FULL_FLUSH", Z_FULL_FLUSH); - ver = PyString_FromString(ZLIB_VERSION); + ver = PyUnicode_FromString(ZLIB_VERSION); if (ver != NULL) PyModule_AddObject(m, "ZLIB_VERSION", ver); PyModule_AddStringConstant(m, "__version__", "1.0"); -#ifdef WITH_THREAD - zlib_lock = PyThread_allocate_lock(); -#endif /* WITH_THREAD */ + return m; } |