patches from Andrew

NOTE: There is still a bug of some sort in the behavior of zlib.  In
at least one case, inflate returns Z_OK (which is typically
interpreted to mean that more output space is needed) when it has
finished inflating a buffer.  This has been reported as a bug to the
zlib maintainers; we may need to change the Python interface.
This commit is contained in:
Jeremy Hylton 1998-12-18 22:13:11 +00:00
parent 1924a0677d
commit a37e244536
1 changed files with 51 additions and 23 deletions

View File

@ -80,7 +80,7 @@ PyZlib_compress(self, args)
"Can't allocate memory to compress data"); "Can't allocate memory to compress data");
return NULL; return NULL;
} }
zst.zalloc=(alloc_func)NULL;
zst.zfree=(free_func)Z_NULL; zst.zfree=(free_func)Z_NULL;
zst.next_out=(Byte *)output; zst.next_out=(Byte *)output;
zst.next_in =(Byte *)input; zst.next_in =(Byte *)input;
@ -212,6 +212,8 @@ PyZlib_decompress(self, args)
do do
{ {
err=inflate(&zst, Z_FINISH); err=inflate(&zst, Z_FINISH);
fprintf(stderr, "err=%d avail_in=%d avail_out=%d\n",
err, zst.avail_in, zst.avail_out);
switch(err) switch(err)
{ {
case(Z_STREAM_END): case(Z_STREAM_END):
@ -488,8 +490,11 @@ PyZlib_objdecompress(self, args)
} }
static char comp_flush__doc__[] = static char comp_flush__doc__[] =
"flush() -- Return a string containing any remaining compressed data. " "flush( [mode] ) -- Return a string containing any remaining compressed data.\n"
"The compressor object can no longer be used after this call." "mode can be one of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH; the \n"
"default value used when mode is not specified is Z_FINISH.\n"
"If mode == Z_FINISH, the compressor object can no longer be used after\n"
"calling the flush() method. Otherwise, more data can still be compressed.\n"
; ;
static PyObject * static PyObject *
@ -499,9 +504,19 @@ PyZlib_flush(self, args)
{ {
int length=DEFAULTALLOC, err = Z_OK; int length=DEFAULTALLOC, err = Z_OK;
PyObject *RetVal; PyObject *RetVal;
int flushmode = Z_FINISH;
unsigned long start_total_out;
if (!PyArg_NoArgs(args)) if (!PyArg_ParseTuple(args, "|i", &flushmode))
return NULL; return NULL;
/* 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);
}
self->zst.avail_in = 0; self->zst.avail_in = 0;
self->zst.next_in = Z_NULL; self->zst.next_in = Z_NULL;
if (!(RetVal = PyString_FromStringAndSize(NULL, length))) { if (!(RetVal = PyString_FromStringAndSize(NULL, length))) {
@ -509,10 +524,14 @@ PyZlib_flush(self, args)
"Can't allocate memory to compress data"); "Can't allocate memory to compress data");
return NULL; return NULL;
} }
start_total_out = self->zst.total_out;
self->zst.next_out = (unsigned char *)PyString_AsString(RetVal); self->zst.next_out = (unsigned char *)PyString_AsString(RetVal);
self->zst.avail_out = length; self->zst.avail_out = length;
while (err == Z_OK)
{ /* When flushing the zstream, there's no input data.
If zst.avail_out == 0, that means that more output space is
needed to complete the flush operation. */
do {
err = deflate(&(self->zst), Z_FINISH); err = deflate(&(self->zst), Z_FINISH);
if (self->zst.avail_out <= 0) { if (self->zst.avail_out <= 0) {
if (_PyString_Resize(&RetVal, length << 1) == -1) { if (_PyString_Resize(&RetVal, length << 1) == -1) {
@ -524,31 +543,34 @@ PyZlib_flush(self, args)
self->zst.avail_out = length; self->zst.avail_out = length;
length = length << 1; length = length << 1;
} }
} } while (self->zst.avail_out == 0);
if (err!=Z_STREAM_END) {
if (err!=Z_OK && err != Z_STREAM_END)
{
if (self->zst.msg == Z_NULL) if (self->zst.msg == Z_NULL)
PyErr_Format(ZlibError, "Error %i while compressing", PyErr_Format(ZlibError, "Error %i while flushing",
err); err);
else else
PyErr_Format(ZlibError, "Error %i while compressing: %.200s", PyErr_Format(ZlibError, "Error %i while flushing: %.200s",
err, self->zst.msg); err, self->zst.msg);
Py_DECREF(RetVal); Py_DECREF(RetVal);
return NULL; return NULL;
} }
err=deflateEnd(&(self->zst)); if (flushmode == Z_FINISH) {
if (err!=Z_OK) { err=deflateEnd(&(self->zst));
if (err!=Z_OK) {
if (self->zst.msg == Z_NULL) if (self->zst.msg == Z_NULL)
PyErr_Format(ZlibError, "Error %i while flushing compression object", PyErr_Format(ZlibError, "Error %i from deflateEnd()",
err); err);
else else
PyErr_Format(ZlibError, PyErr_Format(ZlibError,
"Error %i while flushing compression object: %.200s", "Error %i from deflateEnd(): %.200s",
err, self->zst.msg); err, self->zst.msg);
Py_DECREF(RetVal); Py_DECREF(RetVal);
return NULL; return NULL;
}
} }
_PyString_Resize(&RetVal, _PyString_Resize(&RetVal, self->zst.total_out - start_total_out);
(char *)self->zst.next_out - PyString_AsString(RetVal));
return RetVal; return RetVal;
} }
@ -627,7 +649,7 @@ PyZlib_unflush(self, args)
static PyMethodDef comp_methods[] = static PyMethodDef comp_methods[] =
{ {
{"compress", (binaryfunc)PyZlib_objcompress, 1, comp_compress__doc__}, {"compress", (binaryfunc)PyZlib_objcompress, 1, comp_compress__doc__},
{"flush", (binaryfunc)PyZlib_flush, 0, comp_flush__doc__}, {"flush", (binaryfunc)PyZlib_flush, 1, comp_flush__doc__},
{NULL, NULL} {NULL, NULL}
}; };
@ -805,6 +827,12 @@ PyInit_zlib()
insint(d, "Z_FILTERED", Z_FILTERED); insint(d, "Z_FILTERED", Z_FILTERED);
insint(d, "Z_HUFFMAN_ONLY", Z_HUFFMAN_ONLY); insint(d, "Z_HUFFMAN_ONLY", Z_HUFFMAN_ONLY);
insint(d, "Z_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); insint(d, "Z_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY);
insint(d, "Z_FINISH", Z_FINISH);
insint(d, "Z_NO_FLUSH", Z_NO_FLUSH);
insint(d, "Z_SYNC_FLUSH", Z_SYNC_FLUSH);
insint(d, "Z_FULL_FLUSH", Z_FULL_FLUSH);
ver = PyString_FromString(ZLIB_VERSION); ver = PyString_FromString(ZLIB_VERSION);
PyDict_SetItemString(d, "ZLIB_VERSION", ver); PyDict_SetItemString(d, "ZLIB_VERSION", ver);
} }