Index: Doc/lib/libzlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libzlib.tex,v retrieving revision 1.23 diff -c -2 -r1.23 libzlib.tex *** Doc/lib/libzlib.tex 2000/10/18 17:43:06 1.23 --- Doc/lib/libzlib.tex 2001/02/22 12:05:44 *************** *** 117,121 **** \end{methoddesc} ! Decompression objects support the following methods, and a single attribute: \begin{memberdesc}{unused_data} --- 117,121 ---- \end{methoddesc} ! Decompression objects support the following methods, and two attributes: \begin{memberdesc}{unused_data} *************** *** 132,136 **** \end{memberdesc} ! \begin{methoddesc}[Decompress]{decompress}{string} Decompress \var{string}, returning a string containing the uncompressed data corresponding to at least part of the data in --- 132,136 ---- \end{memberdesc} ! \begin{methoddesc}[Decompress]{decompress}{string}{\optional{max_length}} Decompress \var{string}, returning a string containing the uncompressed data corresponding to at least part of the data in *************** *** 139,142 **** --- 139,150 ---- \method{decompress()} method. Some of the input data may be preserved in internal buffers for later processing. + If the optional parameter max_length is supplied then the return value + will be no longer than max_length. This may mean that not all of the + compressed input can be processed; and unconsumed data will be stored + in the attribute \member{unconsumed_tail}. This string must be passed to + a subsequent call to \method{decompress()} if decompression is to + continue. + If max_length is not supplied then the whole input is decompressed, and + \member{unconsumed_tail} set to None. \end{methoddesc} Index: Lib/test/test_zlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_zlib.py,v retrieving revision 1.13 diff -c -2 -r1.13 test_zlib.py *** Lib/test/test_zlib.py 2001/02/21 07:29:48 1.13 --- Lib/test/test_zlib.py 2001/02/22 12:06:43 *************** *** 77,80 **** --- 77,100 ---- print "decompressobj with init options succeeded" + print "should be None:",deco.unconsumed_tail + + deco = zlib.decompressobj(-12) + cb = combuf[:] + bufs = [] + while cb: + max_length = 1 + len(cb)/10 + chunk = deco.decompress(cb,max_length) + if len(chunk)>max_length: + print 'chunk too big (%d>%d)' % (len(chunk),max_length) + bufs.append(chunk) + cb = deco.unconsumed_tail + bufs.append(deco.flush()) + decomp2 = ''.join(buf) + if decomp2 != buf: + print "max_length decompressobj failed" + else: + print "max_length decompressobj succeeded" + + # Test flush() with the various options, using all the different levels # in order to provide more variations. Index: Lib/test/output/test_zlib =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/output/test_zlib,v retrieving revision 1.3 diff -c -2 -r1.3 test_zlib *** Lib/test/output/test_zlib 1998/04/24 18:31:28 1.3 --- Lib/test/output/test_zlib 2001/02/22 12:06:56 *************** *** 9,10 **** --- 9,12 ---- decompress with init options succeeded decompressobj with init options succeeded + should be None: None + max_length decompressobj succeeded Index: Modules/zlibmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/zlibmodule.c,v retrieving revision 2.39 diff -c -2 -r2.39 zlibmodule.c *** Modules/zlibmodule.c 2001/02/21 02:15:56 2.39 --- Modules/zlibmodule.c 2001/02/22 12:07:05 *************** *** 31,34 **** --- 31,35 ---- z_stream zst; PyObject *unused_data; + PyObject *unconsumed_tail; int is_initialised; } compobject; *************** *** 53,56 **** --- 54,58 ---- self->is_initialised = 0; self->unused_data = PyString_FromString(""); + self->unconsumed_tail = NULL; return self; } *************** *** 376,379 **** --- 378,382 ---- deflateEnd(&self->zst); Py_XDECREF(self->unused_data); + Py_XDECREF(self->unconsumed_tail); PyObject_Del(self); } *************** *** 385,388 **** --- 388,392 ---- inflateEnd(&self->zst); Py_XDECREF(self->unused_data); + Py_XDECREF(self->unconsumed_tail); PyObject_Del(self); } *************** *** 447,454 **** static char decomp_decompress__doc__[] = ! "decompress(data) -- Return a string containing the decompressed version of the data.\n\n" "After calling this function, some of the input data may still\n" "be stored in internal buffers for later processing.\n" ! "Call the flush() method to clear these buffers." ; --- 451,460 ---- static char decomp_decompress__doc__[] = ! "decompress(data,max_length) -- Return a string containing the decompressed version of the data.\n\n" "After calling this function, some of the input data may still\n" "be stored in internal buffers for later processing.\n" ! "Call the flush() method to clear these buffers.\n" ! "If the max_length parameter is specified then the return value will be no longer than max_length.\n" ! "Unconsumed input data will stored in the unconsumed_tail attribute." ; *************** *** 456,466 **** PyZlib_objdecompress(compobject *self, PyObject *args) { ! int err, inplen, length = DEFAULTALLOC; PyObject *RetVal; Byte *input; unsigned long start_total_out; ! if (!PyArg_ParseTuple(args, "s#:decompress", &input, &inplen)) return NULL; if (!(RetVal = PyString_FromStringAndSize(NULL, length))) { PyErr_SetString(PyExc_MemoryError, --- 462,482 ---- PyZlib_objdecompress(compobject *self, PyObject *args) { ! int err, inplen, old_length, length = DEFAULTALLOC; ! int max_length = 0; PyObject *RetVal; Byte *input; unsigned long start_total_out; ! Py_XDECREF(self->unconsumed_tail); ! self->unconsumed_tail = NULL; ! ! if (!PyArg_ParseTuple(args, "s#|i:decompress", &input, &inplen, &max_length)) ! return NULL; ! if (max_length<0) { ! PyErr_SetString(PyExc_ValueError, ! "max_length must be greater than zero"); return NULL; + } + if(max_length && length>max_length) length = max_length; if (!(RetVal = PyString_FromStringAndSize(NULL, length))) { PyErr_SetString(PyExc_MemoryError, *************** *** 476,490 **** /* 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) == -1) { PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); return NULL; } ! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + length; ! self->zst.avail_out = length; ! length = length << 1; err = inflate(&(self->zst), Z_SYNC_FLUSH); } /* The end of the compressed data has been reached, so set the unused_data attribute to a string containing the remainder of the data in the string. --- 492,518 ---- /* 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 && (!max_length || lengthmax_length) length = max_length; ! if (_PyString_Resize(&RetVal, length) == -1) { PyErr_SetString(PyExc_MemoryError, "Can't allocate memory to compress data"); return NULL; } ! self->zst.next_out = (unsigned char *)PyString_AsString(RetVal) + old_length; ! self->zst.avail_out = length-old_length; err = inflate(&(self->zst), Z_SYNC_FLUSH); } + /* Not all of the compressed data could be accomodated in the output buffer + of specified size. Return the unconsumed tail in an attribute.*/ + if(max_length) { + if(!(self->unconsumed_tail=PyString_FromStringAndSize(self->zst.next_in, self->zst.avail_in))) { + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory to unconsumed_tail"); + return NULL; + } + } + /* The end of the compressed data has been reached, so set the unused_data attribute to a string containing the remainder of the data in the string. *************** *** 658,661 **** --- 686,702 ---- Py_INCREF(self->unused_data); return self->unused_data; + } + if (strcmp(name, "unconsumed_tail") == 0) + { + if(self->unconsumed_tail) + { + Py_INCREF(self->unused_data); + return self->unused_data; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } } return Py_FindMethod(Decomp_methods, (PyObject *)self, name);