summaryrefslogtreecommitdiffstats
path: root/Modules/zlibmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/zlibmodule.c')
-rw-r--r--Modules/zlibmodule.c166
1 files changed, 131 insertions, 35 deletions
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
index 6a772ad..5a57fe9 100644
--- a/Modules/zlibmodule.c
+++ b/Modules/zlibmodule.c
@@ -43,7 +43,9 @@ typedef struct
z_stream zst;
PyObject *unused_data;
PyObject *unconsumed_tail;
+ char eof;
int is_initialised;
+ PyObject *zdict;
#ifdef WITH_THREAD
PyThread_type_lock lock;
#endif
@@ -79,14 +81,34 @@ zlib_error(z_stream zst, int err, char *msg)
}
PyDoc_STRVAR(compressobj__doc__,
-"compressobj([level]) -- Return a compressor object.\n"
+"compressobj(level=-1, method=DEFLATED, wbits=15, memlevel=8,\n"
+" strategy=Z_DEFAULT_STRATEGY[, zdict])\n"
+" -- Return a compressor object.\n"
"\n"
-"Optional arg level is the compression level, in 1-9.");
+"level is the compression level (an integer in the range 0-9; default is 6).\n"
+"Higher compression levels are slower, but produce smaller results.\n"
+"\n"
+"method is the compression algorithm. If given, this must be DEFLATED.\n"
+"\n"
+"wbits is the base two logarithm of the window size (range: 8..15).\n"
+"\n"
+"memlevel controls the amount of memory used for internal compression state.\n"
+"Valid values range from 1 to 9. Higher values result in higher memory usage,\n"
+"faster compression, and smaller output.\n"
+"\n"
+"strategy is used to tune the compression algorithm. Possible values are\n"
+"Z_DEFAULT_STRATEGY, Z_FILTERED, and Z_HUFFMAN_ONLY.\n"
+"\n"
+"zdict is the predefined compression dictionary - a sequence of bytes\n"
+"containing subsequences that are likely to occur in the input data.");
PyDoc_STRVAR(decompressobj__doc__,
-"decompressobj([wbits]) -- Return a decompressor object.\n"
+"decompressobj([wbits[, zdict]]) -- Return a decompressor object.\n"
+"\n"
+"Optional arg wbits is the window buffer size.\n"
"\n"
-"Optional arg wbits is the window buffer size.");
+"Optional arg zdict is the predefined compression dictionary. This must be\n"
+"the same dictionary as used by the compressor that produced the input data.");
static compobject *
newcompobject(PyTypeObject *type)
@@ -95,7 +117,9 @@ newcompobject(PyTypeObject *type)
self = PyObject_New(compobject, type);
if (self == NULL)
return NULL;
+ self->eof = 0;
self->is_initialised = 0;
+ self->zdict = NULL;
self->unused_data = PyBytes_FromStringAndSize("", 0);
if (self->unused_data == NULL) {
Py_DECREF(self);
@@ -297,7 +321,7 @@ PyZlib_decompress(PyObject *self, PyObject *args)
err = inflateEnd(&zst);
if (err != Z_OK) {
- zlib_error(zst, err, "while finishing data decompression");
+ zlib_error(zst, err, "while finishing decompression");
goto error;
}
@@ -314,19 +338,24 @@ PyZlib_decompress(PyObject *self, PyObject *args)
}
static PyObject *
-PyZlib_compressobj(PyObject *selfptr, PyObject *args)
+PyZlib_compressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs)
{
compobject *self;
int level=Z_DEFAULT_COMPRESSION, method=DEFLATED;
int wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=0, err;
-
- if (!PyArg_ParseTuple(args, "|iiiii:compressobj", &level, &method, &wbits,
- &memLevel, &strategy))
+ Py_buffer zdict;
+ static char *kwlist[] = {"level", "method", "wbits",
+ "memLevel", "strategy", "zdict", NULL};
+
+ zdict.buf = NULL; /* Sentinel, so we can tell whether zdict was supplied. */
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iiiiiy*:compressobj",
+ kwlist, &level, &method, &wbits,
+ &memLevel, &strategy, &zdict))
return NULL;
self = newcompobject(&Comptype);
if (self==NULL)
- return(NULL);
+ goto error;
self->zst.zalloc = (alloc_func)NULL;
self->zst.zfree = (free_func)Z_NULL;
self->zst.next_in = NULL;
@@ -335,30 +364,58 @@ PyZlib_compressobj(PyObject *selfptr, PyObject *args)
switch(err) {
case (Z_OK):
self->is_initialised = 1;
- return (PyObject*)self;
+ if (zdict.buf == NULL) {
+ goto success;
+ } else {
+ err = deflateSetDictionary(&self->zst, zdict.buf, zdict.len);
+ switch (err) {
+ case (Z_OK):
+ goto success;
+ case (Z_STREAM_ERROR):
+ PyErr_SetString(PyExc_ValueError, "Invalid dictionary");
+ goto error;
+ default:
+ PyErr_SetString(PyExc_ValueError, "deflateSetDictionary()");
+ goto error;
+ }
+ }
case (Z_MEM_ERROR):
- Py_DECREF(self);
PyErr_SetString(PyExc_MemoryError,
"Can't allocate memory for compression object");
- return NULL;
+ goto error;
case(Z_STREAM_ERROR):
- Py_DECREF(self);
PyErr_SetString(PyExc_ValueError, "Invalid initialization option");
- return NULL;
+ goto error;
default:
zlib_error(self->zst, err, "while creating compression object");
- Py_DECREF(self);
- return NULL;
+ goto error;
}
+
+ error:
+ Py_XDECREF(self);
+ self = NULL;
+ success:
+ if (zdict.buf != NULL)
+ PyBuffer_Release(&zdict);
+ return (PyObject*)self;
}
static PyObject *
-PyZlib_decompressobj(PyObject *selfptr, PyObject *args)
+PyZlib_decompressobj(PyObject *selfptr, PyObject *args, PyObject *kwargs)
{
+ static char *kwlist[] = {"wbits", "zdict", NULL};
int wbits=DEF_WBITS, err;
compobject *self;
- if (!PyArg_ParseTuple(args, "|i:decompressobj", &wbits))
+ PyObject *zdict=NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:decompressobj",
+ kwlist, &wbits, &zdict))
return NULL;
+ if (zdict != NULL && !PyObject_CheckBuffer(zdict)) {
+ PyErr_SetString(PyExc_TypeError,
+ "zdict argument must support the buffer protocol");
+ return NULL;
+ }
self = newcompobject(&Decomptype);
if (self == NULL)
@@ -367,6 +424,10 @@ PyZlib_decompressobj(PyObject *selfptr, PyObject *args)
self->zst.zfree = (free_func)Z_NULL;
self->zst.next_in = NULL;
self->zst.avail_in = 0;
+ if (zdict != NULL) {
+ Py_INCREF(zdict);
+ self->zdict = zdict;
+ }
err = inflateInit2(&self->zst, wbits);
switch(err) {
case (Z_OK):
@@ -396,6 +457,7 @@ Dealloc(compobject *self)
#endif
Py_XDECREF(self->unused_data);
Py_XDECREF(self->unconsumed_tail);
+ Py_XDECREF(self->zdict);
PyObject_Del(self);
}
@@ -482,7 +544,7 @@ PyZlib_objcompress(compobject *self, PyObject *args)
*/
if (err != Z_OK && err != Z_BUF_ERROR) {
- zlib_error(self->zst, err, "while compressing");
+ zlib_error(self->zst, err, "while compressing data");
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
@@ -598,6 +660,27 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
err = inflate(&(self->zst), Z_SYNC_FLUSH);
Py_END_ALLOW_THREADS
+ if (err == Z_NEED_DICT && self->zdict != NULL) {
+ Py_buffer zdict_buf;
+ if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
+ Py_DECREF(RetVal);
+ RetVal = NULL;
+ goto error;
+ }
+ err = inflateSetDictionary(&(self->zst), zdict_buf.buf, zdict_buf.len);
+ PyBuffer_Release(&zdict_buf);
+ if (err != Z_OK) {
+ zlib_error(self->zst, err, "while decompressing data");
+ Py_DECREF(RetVal);
+ RetVal = NULL;
+ goto error;
+ }
+ /* Repeat the call to inflate. */
+ Py_BEGIN_ALLOW_THREADS
+ err = inflate(&(self->zst), Z_SYNC_FLUSH);
+ Py_END_ALLOW_THREADS
+ }
+
/* While Z_OK and the output buffer is full, there might be more output.
So extend the output buffer and try again.
*/
@@ -634,15 +717,16 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
goto error;
}
- /* This is the logical place to call inflateEnd, but the old behaviour of
- only calling it on flush() is preserved. */
-
- if (err != Z_STREAM_END && err != Z_OK && err != Z_BUF_ERROR) {
+ if (err == Z_STREAM_END) {
+ /* This is the logical place to call inflateEnd, but the old behaviour
+ of only calling it on flush() is preserved. */
+ self->eof = 1;
+ } else if (err != Z_OK && err != Z_BUF_ERROR) {
/* We will only get Z_BUF_ERROR if the output buffer was full
but there wasn't more output when we tried again, so it is
not an error condition.
*/
- zlib_error(self->zst, err, "while decompressing");
+ zlib_error(self->zst, err, "while decompressing data");
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
@@ -723,7 +807,7 @@ PyZlib_flush(compobject *self, PyObject *args)
if (err == Z_STREAM_END && flushmode == Z_FINISH) {
err = deflateEnd(&(self->zst));
if (err != Z_OK) {
- zlib_error(self->zst, err, "from deflateEnd()");
+ zlib_error(self->zst, err, "while finishing compression");
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
@@ -787,10 +871,14 @@ PyZlib_copy(compobject *self)
}
Py_INCREF(self->unused_data);
Py_INCREF(self->unconsumed_tail);
+ Py_XINCREF(self->zdict);
Py_XDECREF(retval->unused_data);
Py_XDECREF(retval->unconsumed_tail);
+ Py_XDECREF(retval->zdict);
retval->unused_data = self->unused_data;
retval->unconsumed_tail = self->unconsumed_tail;
+ retval->zdict = self->zdict;
+ retval->eof = self->eof;
/* Mark it as being initialized */
retval->is_initialised = 1;
@@ -838,10 +926,14 @@ PyZlib_uncopy(compobject *self)
Py_INCREF(self->unused_data);
Py_INCREF(self->unconsumed_tail);
+ Py_XINCREF(self->zdict);
Py_XDECREF(retval->unused_data);
Py_XDECREF(retval->unconsumed_tail);
+ Py_XDECREF(retval->zdict);
retval->unused_data = self->unused_data;
retval->unconsumed_tail = self->unconsumed_tail;
+ retval->zdict = self->zdict;
+ retval->eof = self->eof;
/* Mark it as being initialized */
retval->is_initialised = 1;
@@ -915,14 +1007,13 @@ PyZlib_unflush(compobject *self, PyObject *args)
goto error;
}
- /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free
- various data structures. Note we should only get Z_STREAM_END when
- flushmode is Z_FINISH */
+ /* If at end of stream, clean up any memory allocated by zlib. */
if (err == Z_STREAM_END) {
- err = inflateEnd(&(self->zst));
+ self->eof = 1;
self->is_initialised = 0;
+ err = inflateEnd(&(self->zst));
if (err != Z_OK) {
- zlib_error(self->zst, err, "from inflateEnd()");
+ zlib_error(self->zst, err, "while finishing decompression");
Py_DECREF(retval);
retval = NULL;
goto error;
@@ -971,6 +1062,7 @@ static PyMethodDef Decomp_methods[] =
static PyMemberDef Decomp_members[] = {
{"unused_data", T_OBJECT, COMP_OFF(unused_data), READONLY},
{"unconsumed_tail", T_OBJECT, COMP_OFF(unconsumed_tail), READONLY},
+ {"eof", T_BOOL, COMP_OFF(eof), READONLY},
{NULL},
};
@@ -1056,13 +1148,13 @@ static PyMethodDef zlib_methods[] =
adler32__doc__},
{"compress", (PyCFunction)PyZlib_compress, METH_VARARGS,
compress__doc__},
- {"compressobj", (PyCFunction)PyZlib_compressobj, METH_VARARGS,
+ {"compressobj", (PyCFunction)PyZlib_compressobj, METH_VARARGS|METH_KEYWORDS,
compressobj__doc__},
{"crc32", (PyCFunction)PyZlib_crc32, METH_VARARGS,
crc32__doc__},
{"decompress", (PyCFunction)PyZlib_decompress, METH_VARARGS,
decompress__doc__},
- {"decompressobj", (PyCFunction)PyZlib_decompressobj, METH_VARARGS,
+ {"decompressobj", (PyCFunction)PyZlib_decompressobj, METH_VARARGS|METH_KEYWORDS,
decompressobj__doc__},
{NULL, NULL}
};
@@ -1136,10 +1228,10 @@ PyDoc_STRVAR(zlib_module_documentation,
"\n"
"adler32(string[, start]) -- Compute an Adler-32 checksum.\n"
"compress(string[, level]) -- Compress string, with compression level in 1-9.\n"
-"compressobj([level]) -- Return a compressor object.\n"
+"compressobj([level[, ...]]) -- Return a compressor object.\n"
"crc32(string[, start]) -- Compute a CRC-32 checksum.\n"
"decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.\n"
-"decompressobj([wbits]) -- Return a decompressor object.\n"
+"decompressobj([wbits[, zdict]]]) -- Return a decompressor object.\n"
"\n"
"'wbits' is window buffer size.\n"
"Compressor objects support compress() and flush() methods; decompressor\n"
@@ -1193,6 +1285,10 @@ PyInit_zlib(void)
if (ver != NULL)
PyModule_AddObject(m, "ZLIB_VERSION", ver);
+ ver = PyUnicode_FromString(zlibVersion());
+ if (ver != NULL)
+ PyModule_AddObject(m, "ZLIB_RUNTIME_VERSION", ver);
+
PyModule_AddStringConstant(m, "__version__", "1.0");
return m;