@@ -603,11 +603,16 @@ def _read_directory(archive):
603
603
)
604
604
605
605
_importing_zlib = False
606
+ _zlib_decompress = None
606
607
607
608
# Return the zlib.decompress function object, or NULL if zlib couldn't
608
609
# be imported. The function is cached when found, so subsequent calls
609
610
# 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
+
611
616
global _importing_zlib
612
617
if _importing_zlib :
613
618
# Someone has a zlib.py[co] in their Zip file
@@ -617,15 +622,62 @@ def _get_decompress_func():
617
622
618
623
_importing_zlib = True
619
624
try :
620
- from zlib import decompress
625
+ from zlib import decompress as _zlib_decompress
621
626
except Exception :
622
627
_bootstrap ._verbose_message ('zipimport: zlib UNAVAILABLE' )
623
628
raise ZipImportError ("can't decompress data; zlib not available" )
624
629
finally :
625
630
_importing_zlib = False
626
631
627
632
_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
+
629
681
630
682
# Given a path to a Zip file and a toc_entry, return the (uncompressed) data.
631
683
def _get_data (archive , toc_entry ):
@@ -659,16 +711,23 @@ def _get_data(archive, toc_entry):
659
711
if len (raw_data ) != data_size :
660
712
raise OSError ("zipimport: can't read data" )
661
713
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 } " )
672
731
673
732
674
733
# Lenient date/time comparison function. The precision of the mtime
0 commit comments