Kaydet (Commit) 8d3342b4 authored tarafından Georg Brandl's avatar Georg Brandl

Patch #1435422: zlib's compress and decompress objects now have a

copy() method.
üst 5f5d99c2
...@@ -123,6 +123,12 @@ prevents compressing any more data. After calling ...@@ -123,6 +123,12 @@ prevents compressing any more data. After calling
action is to delete the object. action is to delete the object.
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}[Compress]{copy}{}
Returns a copy of the compression object. This can be used to efficiently
compress a set of data that share a common initial prefix.
\versionadded{2.5}
\end{methoddesc}
Decompression objects support the following methods, and two attributes: Decompression objects support the following methods, and two attributes:
\begin{memberdesc}{unused_data} \begin{memberdesc}{unused_data}
...@@ -176,6 +182,13 @@ The optional parameter \var{length} sets the initial size of the ...@@ -176,6 +182,13 @@ The optional parameter \var{length} sets the initial size of the
output buffer. output buffer.
\end{methoddesc} \end{methoddesc}
\begin{methoddesc}[Decompress]{copy}{}
Returns a copy of the decompression object. This can be used to save the
state of the decompressor midway through the data stream in order to speed up
random seeks into the stream at a future point.
\versionadded{2.5}
\end{methoddesc}
\begin{seealso} \begin{seealso}
\seemodule{gzip}{Reading and writing \program{gzip}-format files.} \seemodule{gzip}{Reading and writing \program{gzip}-format files.}
\seeurl{http://www.zlib.net}{The zlib library home page.} \seeurl{http://www.zlib.net}{The zlib library home page.}
......
...@@ -302,6 +302,63 @@ class CompressObjectTestCase(unittest.TestCase): ...@@ -302,6 +302,63 @@ class CompressObjectTestCase(unittest.TestCase):
dco = zlib.decompressobj() dco = zlib.decompressobj()
self.assertEqual(dco.flush(), "") # Returns nothing self.assertEqual(dco.flush(), "") # Returns nothing
def test_compresscopy(self):
# Test copying a compression object
data0 = HAMLET_SCENE
data1 = HAMLET_SCENE.swapcase()
c0 = zlib.compressobj(zlib.Z_BEST_COMPRESSION)
bufs0 = []
bufs0.append(c0.compress(data0))
c1 = c0.copy()
bufs1 = bufs0[:]
bufs0.append(c0.compress(data0))
bufs0.append(c0.flush())
s0 = ''.join(bufs0)
bufs1.append(c1.compress(data1))
bufs1.append(c1.flush())
s1 = ''.join(bufs1)
self.assertEqual(zlib.decompress(s0),data0+data0)
self.assertEqual(zlib.decompress(s1),data0+data1)
def test_badcompresscopy(self):
# Test copying a compression object in an inconsistent state
c = zlib.compressobj()
c.compress(HAMLET_SCENE)
c.flush()
self.assertRaises(ValueError, c.copy)
def test_decompresscopy(self):
# Test copying a decompression object
data = HAMLET_SCENE
comp = zlib.compress(data)
d0 = zlib.decompressobj()
bufs0 = []
bufs0.append(d0.decompress(comp[:32]))
d1 = d0.copy()
bufs1 = bufs0[:]
bufs0.append(d0.decompress(comp[32:]))
s0 = ''.join(bufs0)
bufs1.append(d1.decompress(comp[32:]))
s1 = ''.join(bufs1)
self.assertEqual(s0,s1)
self.assertEqual(s0,data)
def test_baddecompresscopy(self):
# Test copying a compression object in an inconsistent state
data = zlib.compress(HAMLET_SCENE)
d = zlib.decompressobj()
d.decompress(data)
d.flush()
self.assertRaises(ValueError, d.copy)
def genblock(seed, length, step=1024, generator=random): def genblock(seed, length, step=1024, generator=random):
"""length-byte stream of random data from a seed (in step-byte blocks).""" """length-byte stream of random data from a seed (in step-byte blocks)."""
......
...@@ -28,6 +28,9 @@ Core and builtins ...@@ -28,6 +28,9 @@ Core and builtins
Extension Modules Extension Modules
----------------- -----------------
- Patch #1435422: zlib's compress and decompress objects now have a
copy() method.
- On Win32, os.listdir now supports arbitrarily-long Unicode path names - On Win32, os.listdir now supports arbitrarily-long Unicode path names
(up to the system limit of 32K characters). (up to the system limit of 32K characters).
......
...@@ -653,6 +653,104 @@ PyZlib_flush(compobject *self, PyObject *args) ...@@ -653,6 +653,104 @@ PyZlib_flush(compobject *self, PyObject *args)
return RetVal; return RetVal;
} }
PyDoc_STRVAR(comp_copy__doc__,
"copy() -- Return a copy of the compression object.");
static PyObject *
PyZlib_copy(compobject *self)
{
compobject *retval = NULL;
int err;
retval = newcompobject(&Comptype);
if (!retval) return NULL;
/* Copy the zstream state
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
*/
ENTER_ZLIB
err = deflateCopy(&retval->zst, &self->zst);
switch(err) {
case(Z_OK):
break;
case(Z_STREAM_ERROR):
PyErr_SetString(PyExc_ValueError, "Inconsistent stream state");
goto error;
case(Z_MEM_ERROR):
PyErr_SetString(PyExc_MemoryError,
"Can't allocate memory for compression object");
goto error;
default:
zlib_error(self->zst, err, "while copying compression object");
goto error;
}
retval->unused_data = self->unused_data;
retval->unconsumed_tail = self->unconsumed_tail;
Py_INCREF(retval->unused_data);
Py_INCREF(retval->unconsumed_tail);
/* Mark it as being initialized */
retval->is_initialised = 1;
LEAVE_ZLIB
return (PyObject *)retval;
error:
LEAVE_ZLIB
Py_XDECREF(retval);
return NULL;
}
PyDoc_STRVAR(decomp_copy__doc__,
"copy() -- Return a copy of the decompression object.");
static PyObject *
PyZlib_uncopy(compobject *self)
{
compobject *retval = NULL;
int err;
retval = newcompobject(&Decomptype);
if (!retval) return NULL;
/* Copy the zstream state
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
*/
ENTER_ZLIB
err = inflateCopy(&retval->zst, &self->zst);
switch(err) {
case(Z_OK):
break;
case(Z_STREAM_ERROR):
PyErr_SetString(PyExc_ValueError, "Inconsistent stream state");
goto error;
case(Z_MEM_ERROR):
PyErr_SetString(PyExc_MemoryError,
"Can't allocate memory for decompression object");
goto error;
default:
zlib_error(self->zst, err, "while copying decompression object");
goto error;
}
retval->unused_data = self->unused_data;
retval->unconsumed_tail = self->unconsumed_tail;
Py_INCREF(retval->unused_data);
Py_INCREF(retval->unconsumed_tail);
/* Mark it as being initialized */
retval->is_initialised = 1;
LEAVE_ZLIB
return (PyObject *)retval;
error:
LEAVE_ZLIB
Py_XDECREF(retval);
return NULL;
}
PyDoc_STRVAR(decomp_flush__doc__, PyDoc_STRVAR(decomp_flush__doc__,
"flush( [length] ) -- Return a string containing any remaining\n" "flush( [length] ) -- Return a string containing any remaining\n"
"decompressed data. length, if given, is the initial size of the\n" "decompressed data. length, if given, is the initial size of the\n"
...@@ -725,6 +823,8 @@ static PyMethodDef comp_methods[] = ...@@ -725,6 +823,8 @@ static PyMethodDef comp_methods[] =
comp_compress__doc__}, comp_compress__doc__},
{"flush", (binaryfunc)PyZlib_flush, METH_VARARGS, {"flush", (binaryfunc)PyZlib_flush, METH_VARARGS,
comp_flush__doc__}, comp_flush__doc__},
{"copy", (PyCFunction)PyZlib_copy, METH_NOARGS,
comp_copy__doc__},
{NULL, NULL} {NULL, NULL}
}; };
...@@ -734,6 +834,8 @@ static PyMethodDef Decomp_methods[] = ...@@ -734,6 +834,8 @@ static PyMethodDef Decomp_methods[] =
decomp_decompress__doc__}, decomp_decompress__doc__},
{"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS, {"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS,
decomp_flush__doc__}, decomp_flush__doc__},
{"copy", (PyCFunction)PyZlib_uncopy, METH_NOARGS,
decomp_copy__doc__},
{NULL, NULL} {NULL, NULL}
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment