@@ -862,6 +862,8 @@ def make_zip64_file(
862862 self , file_size_64_set = False , file_size_extra = False ,
863863 compress_size_64_set = False , compress_size_extra = False ,
864864 header_offset_64_set = False , header_offset_extra = False ,
865+ extensible_data = b'' ,
866+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
865867 ):
866868 """Generate bytes sequence for a zip with (incomplete) zip64 data.
867869
@@ -915,6 +917,12 @@ def make_zip64_file(
915917
916918 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
917919 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
920+ if end_of_central_dir_size is None :
921+ end_of_central_dir_size = 44 + len (extensible_data )
922+ if offset_to_end_of_central_dir is None :
923+ offset_to_end_of_central_dir = (108
924+ + 8 * len (local_zip64_fields )
925+ + 8 * len (central_zip64_fields ))
918926
919927 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
920928 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -943,14 +951,17 @@ def make_zip64_file(
943951 + filename
944952 + central_extra
945953 # Zip64 end of central directory
946- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
947- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
954+ + b"PK\x06 \x06 "
955+ + struct .pack ('<Q' , end_of_central_dir_size )
956+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
948957 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
949958 + central_dir_size
950959 + offset_to_central_dir
960+ + extensible_data
951961 # Zip64 end of central directory locator
952- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
953- + b"\x00 \x00 \x00 "
962+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
963+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
964+ + b"\x01 \x00 \x00 \x00 "
954965 # end of central directory
955966 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
956967 + b"\x00 \x00 \x00 \x00 "
@@ -981,6 +992,7 @@ def test_bad_zip64_extra(self):
981992 with self .assertRaises (zipfile .BadZipFile ) as e :
982993 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
983994 self .assertIn ('file size' , str (e .exception ).lower ())
995+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
984996
985997 # zip64 file size present, zip64 compress size present, one field in
986998 # extra, expecting two, equals missing compress size.
@@ -992,6 +1004,7 @@ def test_bad_zip64_extra(self):
9921004 with self .assertRaises (zipfile .BadZipFile ) as e :
9931005 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
9941006 self .assertIn ('compress size' , str (e .exception ).lower ())
1007+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
9951008
9961009 # zip64 compress size present, no fields in extra, expecting one,
9971010 # equals missing compress size.
@@ -1001,6 +1014,7 @@ def test_bad_zip64_extra(self):
10011014 with self .assertRaises (zipfile .BadZipFile ) as e :
10021015 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10031016 self .assertIn ('compress size' , str (e .exception ).lower ())
1017+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10041018
10051019 # zip64 file size present, zip64 compress size present, zip64 header
10061020 # offset present, two fields in extra, expecting three, equals missing
@@ -1015,6 +1029,7 @@ def test_bad_zip64_extra(self):
10151029 with self .assertRaises (zipfile .BadZipFile ) as e :
10161030 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10171031 self .assertIn ('header offset' , str (e .exception ).lower ())
1032+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10181033
10191034 # zip64 compress size present, zip64 header offset present, one field
10201035 # in extra, expecting two, equals missing header offset
@@ -1027,6 +1042,7 @@ def test_bad_zip64_extra(self):
10271042 with self .assertRaises (zipfile .BadZipFile ) as e :
10281043 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10291044 self .assertIn ('header offset' , str (e .exception ).lower ())
1045+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10301046
10311047 # zip64 file size present, zip64 header offset present, one field in
10321048 # extra, expecting two, equals missing header offset
@@ -1039,6 +1055,7 @@ def test_bad_zip64_extra(self):
10391055 with self .assertRaises (zipfile .BadZipFile ) as e :
10401056 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10411057 self .assertIn ('header offset' , str (e .exception ).lower ())
1058+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10421059
10431060 # zip64 header offset present, no fields in extra, expecting one,
10441061 # equals missing header offset
@@ -1050,6 +1067,63 @@ def test_bad_zip64_extra(self):
10501067 with self .assertRaises (zipfile .BadZipFile ) as e :
10511068 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10521069 self .assertIn ('header offset' , str (e .exception ).lower ())
1070+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1071+
1072+ def test_bad_zip64_end_of_central_dir (self ):
1073+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1074+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1075+ zipfile .ZipFile (io .BytesIO (zipdata ))
1076+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1077+
1078+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1079+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1080+ zipfile .ZipFile (io .BytesIO (zipdata ))
1081+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1082+
1083+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1084+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1085+ zipfile .ZipFile (io .BytesIO (zipdata ))
1086+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1087+
1088+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1089+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1090+ zipfile .ZipFile (io .BytesIO (zipdata ))
1091+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1092+
1093+ def test_zip64_end_of_central_dir_record_not_found (self ):
1094+ zipdata = self .make_zip64_file ()
1095+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1096+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1097+ zipfile .ZipFile (io .BytesIO (zipdata ))
1098+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1099+
1100+ zipdata = self .make_zip64_file (
1101+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1102+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1103+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1104+ zipfile .ZipFile (io .BytesIO (zipdata ))
1105+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1106+
1107+ def test_zip64_extensible_data (self ):
1108+ # These values are what is set in the make_zip64_file method.
1109+ expected_file_size = 8
1110+ expected_compress_size = 8
1111+ expected_header_offset = 0
1112+ expected_content = b"test1234"
1113+
1114+ zipdata = self .make_zip64_file (
1115+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1116+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1117+ zinfo = zf .infolist ()[0 ]
1118+ self .assertEqual (zinfo .file_size , expected_file_size )
1119+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1120+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1121+ self .assertEqual (zf .read (zinfo ), expected_content )
1122+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1123+
1124+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1125+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1126+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10531127
10541128 def test_generated_valid_zip64_extra (self ):
10551129 # These values are what is set in the make_zip64_file method.
0 commit comments