@@ -1628,8 +1628,14 @@ def _validate_local_file_entry(self, fp, offset, end_offset):
16281628 zip64 = fheader [_FH_UNCOMPRESSED_SIZE ] == 0xffffffff
16291629
16301630 dd = self ._scan_data_descriptor (fp , pos , end_offset , zip64 )
1631- if dd is None and not self .strict_descriptor :
1632- dd = self ._scan_data_descriptor_no_sig (fp , pos , end_offset , zip64 )
1631+ if dd is None :
1632+ dd = self ._scan_data_descriptor_no_sig_by_decompression (
1633+ fp , pos , end_offset , zip64 , fheader [_FH_COMPRESSION_METHOD ])
1634+ if dd is False :
1635+ if not self .strict_descriptor :
1636+ dd = self ._scan_data_descriptor_no_sig (fp , pos , end_offset , zip64 )
1637+ else :
1638+ dd = None
16331639 if dd is None :
16341640 return None
16351641
@@ -1705,6 +1711,56 @@ def _scan_data_descriptor_no_sig(self, fp, offset, end_offset, zip64, chunk_size
17051711
17061712 return None
17071713
1714+ def _scan_data_descriptor_no_sig_by_decompression (self , fp , offset , end_offset , zip64 , method ):
1715+ dd_fmt = '<LQQ' if zip64 else '<LLL'
1716+ dd_size = struct .calcsize (dd_fmt )
1717+
1718+ if offset + dd_size > end_offset :
1719+ return False
1720+
1721+ try :
1722+ decompressor = _get_decompressor (method )
1723+ except NotImplementedError :
1724+ return False
1725+
1726+ if decompressor is None :
1727+ return False
1728+
1729+ # Current LZMADecompressor is unreliable since it's `.eof` is usually
1730+ # not set as expected.
1731+ if isinstance (decompressor , LZMADecompressor ):
1732+ return False
1733+
1734+ try :
1735+ pos = self ._find_compression_end_offset (fp , offset , end_offset - dd_size , decompressor )
1736+ except Exception :
1737+ return None
1738+
1739+ fp .seek (pos )
1740+ dd = fp .read (dd_size )
1741+ crc , compress_size , file_size = struct .unpack (dd_fmt , dd )
1742+ if pos - offset != compress_size :
1743+ return None
1744+
1745+ return crc , compress_size , file_size , dd_size
1746+
1747+ def _find_compression_end_offset (self , fp , offset , end_offset , decompressor , chunk_size = 4096 ):
1748+ fp .seek (offset )
1749+ read_size = 0
1750+ while True :
1751+ chunk = fp .read (min (chunk_size , end_offset - offset - read_size ))
1752+ if not chunk :
1753+ raise EOFError ('Unexpected EOF while decompressing' )
1754+
1755+ # may raise on error
1756+ decompressor .decompress (chunk )
1757+
1758+ read_size += len (chunk )
1759+
1760+ if decompressor .eof :
1761+ unused_len = len (decompressor .unused_data )
1762+ return offset + read_size - unused_len
1763+
17081764 def _calc_local_file_entry_size (self , fp , zinfo ):
17091765 fp .seek (zinfo .header_offset )
17101766 fheader = self ._read_local_file_header (fp )
0 commit comments