Author: Armin Rigo <[email protected]>
Branch: py3.6
Changeset: r97765:3a35a0ae4463
Date: 2019-10-12 12:38 +0200
http://bitbucket.org/pypy/pypy/changeset/3a35a0ae4463/

Log:    #3090: lzma sometimes fails to decompress a file

        Fixed by back-porting CPython commit
        a3c53a1b45b05bcb69660eac5a271443b37ecc42

diff --git a/lib_pypy/_lzma.py b/lib_pypy/_lzma.py
--- a/lib_pypy/_lzma.py
+++ b/lib_pypy/_lzma.py
@@ -583,8 +583,16 @@
                 self.clear_input_buffer()
             elif lzs.avail_in == 0:
                 # completed successfully!
-                self.needs_input = True
                 lzs.next_in = ffi.NULL
+                if lzs.avail_out == 0:
+                    # (avail_in==0 && avail_out==0)
+                    # Maybe lzs's internal state still have a few bytes can
+                    # be output, try to output them next time.
+                    self.needs_input = False
+                    assert max_length >= 0   # if < 0, lzs.avail_out always > 0
+                else:
+                    # Input buffer exhausted, output buffer has space.
+                    self.needs_input = True
                 self.clear_input_buffer()
             else:
                 self.needs_input = False
@@ -599,9 +607,6 @@
         lzs.next_in = buf
         lzs.avail_in = buf_len
 
-        if buf_len == 0:
-            return b""
-
         bufsiz = self._bufsiz
         if not (max_length < 0 or max_length > io.DEFAULT_BUFFER_SIZE):
             bufsiz = max_length
@@ -616,7 +621,8 @@
 
         try:
             while True:
-                ret = catch_lzma_error(m.lzma_code, lzs, m.LZMA_RUN)
+                ret = catch_lzma_error(m.lzma_code, lzs, m.LZMA_RUN,
+                    ignore_buf_error=(lzs.avail_in == 0 and lzs.avail_out > 0))
                 data_size = int(ffi.cast('uintptr_t', lzs.next_out)) - 
int(ffi.cast('uintptr_t', orig_out))
                 # data_size is the amount lzma_code has already outputted
 
@@ -626,10 +632,11 @@
                 if ret == m.LZMA_STREAM_END:
                     self.eof = True
                     break
-                elif lzs.avail_in == 0:
-                    # it ate everything
-                    break
                 elif lzs.avail_out == 0:
+                    # Need to check lzs->avail_out before lzs->avail_in.
+                    # Maybe lzs's internal state still have a few bytes
+                    # can be output, grow the output buffer and continue
+                    # if max_lengh < 0.
                     if data_size == max_length:
                         break
                     # ran out of space in the output buffer, let's grow it
@@ -647,6 +654,9 @@
 
                     lzs.next_out = orig_out + data_size
                     lzs.avail_out = bufsiz - data_size
+                elif lzs.avail_in == 0:
+                    # it ate everything
+                    break
 
             result = ffi.buffer(orig_out, data_size)[:]
         finally:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to