@@ -557,11 +557,16 @@ def _read_directory(archive):
557
557
)
558
558
559
559
_importing_zlib = False
560
+ _zlib_decompress = None
560
561
561
562
# Return the zlib.decompress function object, or NULL if zlib couldn't
562
563
# be imported. The function is cached when found, so subsequent calls
563
564
# 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
+
565
570
global _importing_zlib
566
571
if _importing_zlib :
567
572
# Someone has a zlib.py[co] in their Zip file
@@ -571,15 +576,62 @@ def _get_decompress_func():
571
576
572
577
_importing_zlib = True
573
578
try :
574
- from zlib import decompress
579
+ from zlib import decompress as _zlib_decompress
575
580
except Exception :
576
581
_bootstrap ._verbose_message ('zipimport: zlib UNAVAILABLE' )
577
582
raise ZipImportError ("can't decompress data; zlib not available" )
578
583
finally :
579
584
_importing_zlib = False
580
585
581
586
_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
+
583
635
584
636
# Given a path to a Zip file and a toc_entry, return the (uncompressed) data.
585
637
def _get_data (archive , toc_entry ):
@@ -613,16 +665,23 @@ def _get_data(archive, toc_entry):
613
665
if len (raw_data ) != data_size :
614
666
raise OSError ("zipimport: can't read data" )
615
667
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 } " )
626
685
627
686
628
687
# Lenient date/time comparison function. The precision of the mtime
0 commit comments