@@ -557,11 +557,16 @@ def _read_directory(archive):
557557)
558558
559559_importing_zlib = False
560+ _zlib_decompress = None
560561
561562# Return the zlib.decompress function object, or NULL if zlib couldn't
562563# be imported. The function is cached when found, so subsequent calls
563564# don't import zlib again.
564- def _get_decompress_func ():
565+ def _get_zlib_decompress_func ():
566+ global _zlib_decompress
567+ if _zlib_decompress :
568+ return _zlib_decompress
569+
565570 global _importing_zlib
566571 if _importing_zlib :
567572 # Someone has a zlib.py[co] in their Zip file
@@ -571,15 +576,62 @@ def _get_decompress_func():
571576
572577 _importing_zlib = True
573578 try :
574- from zlib import decompress
579+ from zlib import decompress as _zlib_decompress
575580 except Exception :
576581 _bootstrap ._verbose_message ('zipimport: zlib UNAVAILABLE' )
577582 raise ZipImportError ("can't decompress data; zlib not available" )
578583 finally :
579584 _importing_zlib = False
580585
581586 _bootstrap ._verbose_message ('zipimport: zlib available' )
582- return decompress
587+ return _zlib_decompress
588+
589+
590+ _importing_zstd = False
591+ _zstd_decompressor_class = None
592+
593+ # Return the _zstd.ZstdDecompressor function object, or NULL if _zstd couldn't
594+ # be imported. The result is cached when found.
595+ def _get_zstd_decompressor_class ():
596+ global _zstd_decompressor_class
597+ if _zstd_decompressor_class :
598+ return _zstd_decompressor_class
599+
600+ global _importing_zstd
601+ if _importing_zstd :
602+ # Someone has a _zstd.py[co] in their Zip file
603+ # let's avoid a stack overflow.
604+ _bootstrap ._verbose_message ("zipimport: zstd UNAVAILABLE" )
605+ raise ZipImportError ("can't decompress data; zstd not available" )
606+
607+ _importing_zstd = True
608+ try :
609+ from _zstd import ZstdDecompressor as _zstd_decompressor_class
610+ except Exception :
611+ _bootstrap ._verbose_message ("zipimport: zstd UNAVAILABLE" )
612+ raise ZipImportError ("can't decompress data; zstd not available" )
613+ finally :
614+ _importing_zstd = False
615+
616+ _bootstrap ._verbose_message ("zipimport: zstd available" )
617+ return _zstd_decompressor_class
618+
619+
620+ def _zstd_decompress (data ):
621+ # A simple version of compression.zstd.decompress() as we cannot import
622+ # that here as the stdlib itself could be being zipimported.
623+ results = []
624+ while True :
625+ decomp = _get_zstd_decompressor_class ()()
626+ results .append (decomp .decompress (data ))
627+ if not decomp .eof :
628+ raise ZipImportError ("zipimport: zstd compressed data ended before "
629+ "the end-of-stream marker" )
630+ data = decomp .unused_data
631+ if not data :
632+ break
633+ return b"" .join (results )
634+
583635
584636# Given a path to a Zip file and a toc_entry, return the (uncompressed) data.
585637def _get_data (archive , toc_entry ):
@@ -613,16 +665,23 @@ def _get_data(archive, toc_entry):
613665 if len (raw_data ) != data_size :
614666 raise OSError ("zipimport: can't read data" )
615667
616- if compress == 0 :
617- # data is not compressed
618- return raw_data
619-
620- # Decompress with zlib
621- try :
622- decompress = _get_decompress_func ()
623- except Exception :
624- raise ZipImportError ("can't decompress data; zlib not available" )
625- return decompress (raw_data , - 15 )
668+ match compress :
669+ case 0 : # stored
670+ return raw_data
671+ case 8 : # deflate aka zlib
672+ try :
673+ decompress = _get_zlib_decompress_func ()
674+ except Exception :
675+ raise ZipImportError ("can't decompress data; zlib not available" )
676+ return decompress (raw_data , - 15 )
677+ case 93 : # zstd
678+ try :
679+ return _zstd_decompress (raw_data )
680+ except Exception :
681+ raise ZipImportError ("could not decompress zstd data" )
682+ # bz2 and lzma could be added, but are largely obsolete.
683+ case _:
684+ raise ZipImportError (f"zipimport: unsupported compression { compress } " )
626685
627686
628687# Lenient date/time comparison function. The precision of the mtime
0 commit comments