File add-zlib-eof-attribute.patch of Package python.42782
From 1c38546e49e3f4bd53c0d470bcaaa9fb2f823401 Mon Sep 17 00:00:00 2001
From: Nadeem Vawda <nadeem.vawda@gmail.com>
Date: Sat, 13 Aug 2011 15:22:40 +0200
Subject: [PATCH] Issue #12646: Add an 'eof' attribute to zlib.Decompress.
This will make it easier to detect truncated input streams.
Also, make zlib's error messages more consistent.
---
Doc/library/zlib.rst | 18 ++++++++++--------
Lib/test/test_zlib.py | 20 ++++++++++++++++++++
Modules/zlibmodule.c | 20 +++++++++++++++-----
3 files changed, 45 insertions(+), 13 deletions(-)
Index: Python-2.7.18/Doc/library/zlib.rst
===================================================================
--- Python-2.7.18.orig/Doc/library/zlib.rst 2020-04-19 23:13:39.000000000 +0200
+++ Python-2.7.18/Doc/library/zlib.rst 2026-02-14 00:23:40.791367404 +0100
@@ -225,7 +225,7 @@
.. versionadded:: 2.5
-Decompression objects support the following methods, and two attributes:
+Decompression objects support the following methods and attributes:
.. attribute:: Decompress.unused_data
@@ -235,13 +235,6 @@
available. If the whole string turned out to contain compressed data, this is
``""``, the empty string.
- The only way to determine where a string of compressed data ends is by actually
- decompressing it. This means that when compressed data is contained part of a
- larger file, you can only find the end of it by reading data and feeding it
- followed by some non-empty string into a decompression object's
- :meth:`decompress` method until the :attr:`unused_data` attribute is no longer
- the empty string.
-
.. attribute:: Decompress.unconsumed_tail
@@ -252,6 +245,15 @@
:meth:`decompress` method call in order to get correct output.
+.. attribute:: Decompress.eof
+
+ A boolean indicating whether the end of the compressed data stream has been
+ reached.
+
+ This makes it possible to distinguish between a properly-formed compressed
+ stream, and an incomplete or truncated one.
+
+
.. method:: Decompress.decompress(string[, max_length])
Decompress *string*, returning a string containing the uncompressed data
Index: Python-2.7.18/Lib/test/test_zlib.py
===================================================================
--- Python-2.7.18.orig/Lib/test/test_zlib.py 2020-04-19 23:13:39.000000000 +0200
+++ Python-2.7.18/Lib/test/test_zlib.py 2026-02-14 00:23:40.791724086 +0100
@@ -462,6 +462,26 @@
y += dco.flush()
self.assertEqual(y, 'foo')
+ def test_decompress_eof(self):
+ x = 'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E' # 'foo'
+ dco = zlib.decompressobj()
+ self.assertFalse(dco.eof)
+ dco.decompress(x[:-5])
+ self.assertFalse(dco.eof)
+ dco.decompress(x[-5:])
+ self.assertTrue(dco.eof)
+ dco.flush()
+ self.assertTrue(dco.eof)
+
+ def test_decompress_eof_incomplete_stream(self):
+ x = 'x\x9cK\xcb\xcf\x07\x00\x02\x82\x01E' # 'foo'
+ dco = zlib.decompressobj()
+ self.assertFalse(dco.eof)
+ dco.decompress(x[:-5])
+ self.assertFalse(dco.eof)
+ dco.flush()
+ self.assertFalse(dco.eof)
+
def test_flush_with_freed_input(self):
# Issue #16411: decompressor accesses input to last decompress() call
# in flush(), even if this object has been freed in the meanwhile.
Index: Python-2.7.18/Modules/zlibmodule.c
===================================================================
--- Python-2.7.18.orig/Modules/zlibmodule.c 2020-04-19 23:13:39.000000000 +0200
+++ Python-2.7.18/Modules/zlibmodule.c 2026-02-14 00:23:40.792076279 +0100
@@ -67,6 +67,7 @@
z_stream zst;
PyObject *unused_data;
PyObject *unconsumed_tail;
+ char eof;
int is_initialised;
} compobject;
@@ -116,6 +117,7 @@
self = PyObject_New(compobject, type);
if (self == NULL)
return NULL;
+ self->eof = 0;
self->is_initialised = 0;
self->unused_data = PyString_FromString("");
if (self->unused_data == NULL) {
@@ -364,7 +366,7 @@
err = inflateEnd(&zst);
if (err != Z_OK) {
- zlib_error(zst, err, "while finishing data decompression");
+ zlib_error(zst, err, "while finishing decompression");
goto error;
}
@@ -652,12 +654,15 @@
/* 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) {
+ self->eof = 1;
+ }
if (err != Z_STREAM_END && 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");
goto abort;
}
@@ -727,7 +732,7 @@
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_CLEAR(RetVal);
goto error;
}
@@ -789,6 +794,7 @@
Py_XSETREF(retval->unused_data, self->unused_data);
Py_INCREF(self->unconsumed_tail);
Py_XSETREF(retval->unconsumed_tail, self->unconsumed_tail);
+ retval->eof = self->eof;
/* Mark it as being initialized */
retval->is_initialised = 1;
@@ -838,6 +844,7 @@
Py_XSETREF(retval->unused_data, self->unused_data);
Py_INCREF(self->unconsumed_tail);
Py_XSETREF(retval->unconsumed_tail, self->unconsumed_tail);
+ retval->eof = self->eof;
/* Mark it as being initialized */
retval->is_initialised = 1;
@@ -915,10 +922,11 @@
various data structures. Note we should only get Z_STREAM_END when
flushmode is Z_FINISH */
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");
goto abort;
}
}
@@ -982,6 +990,8 @@
} else if (strcmp(name, "unconsumed_tail") == 0) {
Py_INCREF(self->unconsumed_tail);
retval = self->unconsumed_tail;
+ } else if (strcmp(name, "eof") == 0) {
+ retval = PyBool_FromLong(self->eof);
} else
retval = Py_FindMethod(Decomp_methods, (PyObject *)self, name);