@@ -603,11 +603,16 @@ def _read_directory(archive):
603603)
604604
605605_importing_zlib = False
606+ _zlib_decompress = None
606607
607608# Return the zlib.decompress function object, or NULL if zlib couldn't
608609# be imported. The function is cached when found, so subsequent calls
609610# don't import zlib again.
610- def _get_decompress_func ():
611+ def _get_zlib_decompress_func ():
612+ global _zlib_decompress
613+ if _zlib_decompress :
614+ return _zlib_decompress
615+
611616 global _importing_zlib
612617 if _importing_zlib :
613618 # Someone has a zlib.py[co] in their Zip file
@@ -617,15 +622,62 @@ def _get_decompress_func():
617622
618623 _importing_zlib = True
619624 try :
620- from zlib import decompress
625+ from zlib import decompress as _zlib_decompress
621626 except Exception :
622627 _bootstrap ._verbose_message ('zipimport: zlib UNAVAILABLE' )
623628 raise ZipImportError ("can't decompress data; zlib not available" )
624629 finally :
625630 _importing_zlib = False
626631
627632 _bootstrap ._verbose_message ('zipimport: zlib available' )
628- return decompress
633+ return _zlib_decompress
634+
635+
636+ _importing_zstd = False
637+ _zstd_decompressor_class = None
638+
639+ # Return the _zstd.ZstdDecompressor function object, or NULL if _zstd couldn't
640+ # be imported. The result is cached when found.
641+ def _get_zstd_decompressor_class ():
642+ global _zstd_decompressor_class
643+ if _zstd_decompressor_class :
644+ return _zstd_decompressor_class
645+
646+ global _importing_zstd
647+ if _importing_zstd :
648+ # Someone has a _zstd.py[co] in their Zip file
649+ # let's avoid a stack overflow.
650+ _bootstrap ._verbose_message ("zipimport: zstd UNAVAILABLE" )
651+ raise ZipImportError ("can't decompress data; zstd not available" )
652+
653+ _importing_zstd = True
654+ try :
655+ from _zstd import ZstdDecompressor as _zstd_decompressor_class
656+ except Exception :
657+ _bootstrap ._verbose_message ("zipimport: zstd UNAVAILABLE" )
658+ raise ZipImportError ("can't decompress data; zstd not available" )
659+ finally :
660+ _importing_zstd = False
661+
662+ _bootstrap ._verbose_message ("zipimport: zstd available" )
663+ return _zstd_decompressor_class
664+
665+
666+ def _zstd_decompress (data ):
667+ # A simple version of compression.zstd.decompress() as we cannot import
668+ # that here as the stdlib itself could be being zipimported.
669+ results = []
670+ while True :
671+ decomp = _get_zstd_decompressor_class ()()
672+ results .append (decomp .decompress (data ))
673+ if not decomp .eof :
674+ raise ZipImportError ("zipimport: zstd compressed data ended before "
675+ "the end-of-stream marker" )
676+ data = decomp .unused_data
677+ if not data :
678+ break
679+ return b"" .join (results )
680+
629681
630682# Given a path to a Zip file and a toc_entry, return the (uncompressed) data.
631683def _get_data (archive , toc_entry ):
@@ -659,16 +711,23 @@ def _get_data(archive, toc_entry):
659711 if len (raw_data ) != data_size :
660712 raise OSError ("zipimport: can't read data" )
661713
662- if compress == 0 :
663- # data is not compressed
664- return raw_data
665-
666- # Decompress with zlib
667- try :
668- decompress = _get_decompress_func ()
669- except Exception :
670- raise ZipImportError ("can't decompress data; zlib not available" )
671- return decompress (raw_data , - 15 )
714+ match compress :
715+ case 0 : # stored
716+ return raw_data
717+ case 8 : # deflate aka zlib
718+ try :
719+ decompress = _get_zlib_decompress_func ()
720+ except Exception :
721+ raise ZipImportError ("can't decompress data; zlib not available" )
722+ return decompress (raw_data , - 15 )
723+ case 93 : # zstd
724+ try :
725+ return _zstd_decompress (raw_data )
726+ except Exception :
727+ raise ZipImportError ("could not decompress zstd data" )
728+ # bz2 and lzma could be added, but are largely obsolete.
729+ case _:
730+ raise ZipImportError (f"zipimport: unsupported compression { compress } " )
672731
673732
674733# Lenient date/time comparison function. The precision of the mtime
0 commit comments