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);
 
openSUSE Build Service is sponsored by