@@ -887,6 +887,8 @@ def make_zip64_file(
887887 self , file_size_64_set = False , file_size_extra = False ,
888888 compress_size_64_set = False , compress_size_extra = False ,
889889 header_offset_64_set = False , header_offset_extra = False ,
890+ extensible_data = b'' ,
891+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
890892 ):
891893 """Generate bytes sequence for a zip with (incomplete) zip64 data.
892894
@@ -940,6 +942,12 @@ def make_zip64_file(
940942
941943 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
942944 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
945+ if end_of_central_dir_size is None :
946+ end_of_central_dir_size = 44 + len (extensible_data )
947+ if offset_to_end_of_central_dir is None :
948+ offset_to_end_of_central_dir = (108
949+ + 8 * len (local_zip64_fields )
950+ + 8 * len (central_zip64_fields ))
943951
944952 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
945953 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -968,14 +976,17 @@ def make_zip64_file(
968976 + filename
969977 + central_extra
970978 # Zip64 end of central directory
971- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
972- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
979+ + b"PK\x06 \x06 "
980+ + struct .pack ('<Q' , end_of_central_dir_size )
981+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
973982 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
974983 + central_dir_size
975984 + offset_to_central_dir
985+ + extensible_data
976986 # Zip64 end of central directory locator
977- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
978- + b"\x00 \x00 \x00 "
987+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
988+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
989+ + b"\x01 \x00 \x00 \x00 "
979990 # end of central directory
980991 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
981992 + b"\x00 \x00 \x00 \x00 "
@@ -1006,6 +1017,7 @@ def test_bad_zip64_extra(self):
10061017 with self .assertRaises (zipfile .BadZipFile ) as e :
10071018 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
10081019 self .assertIn ('file size' , str (e .exception ).lower ())
1020+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
10091021
10101022 # zip64 file size present, zip64 compress size present, one field in
10111023 # extra, expecting two, equals missing compress size.
@@ -1017,6 +1029,7 @@ def test_bad_zip64_extra(self):
10171029 with self .assertRaises (zipfile .BadZipFile ) as e :
10181030 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10191031 self .assertIn ('compress size' , str (e .exception ).lower ())
1032+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10201033
10211034 # zip64 compress size present, no fields in extra, expecting one,
10221035 # equals missing compress size.
@@ -1026,6 +1039,7 @@ def test_bad_zip64_extra(self):
10261039 with self .assertRaises (zipfile .BadZipFile ) as e :
10271040 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10281041 self .assertIn ('compress size' , str (e .exception ).lower ())
1042+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10291043
10301044 # zip64 file size present, zip64 compress size present, zip64 header
10311045 # offset present, two fields in extra, expecting three, equals missing
@@ -1040,6 +1054,7 @@ def test_bad_zip64_extra(self):
10401054 with self .assertRaises (zipfile .BadZipFile ) as e :
10411055 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10421056 self .assertIn ('header offset' , str (e .exception ).lower ())
1057+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10431058
10441059 # zip64 compress size present, zip64 header offset present, one field
10451060 # in extra, expecting two, equals missing header offset
@@ -1052,6 +1067,7 @@ def test_bad_zip64_extra(self):
10521067 with self .assertRaises (zipfile .BadZipFile ) as e :
10531068 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10541069 self .assertIn ('header offset' , str (e .exception ).lower ())
1070+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10551071
10561072 # zip64 file size present, zip64 header offset present, one field in
10571073 # extra, expecting two, equals missing header offset
@@ -1064,6 +1080,7 @@ def test_bad_zip64_extra(self):
10641080 with self .assertRaises (zipfile .BadZipFile ) as e :
10651081 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10661082 self .assertIn ('header offset' , str (e .exception ).lower ())
1083+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10671084
10681085 # zip64 header offset present, no fields in extra, expecting one,
10691086 # equals missing header offset
@@ -1075,6 +1092,63 @@ def test_bad_zip64_extra(self):
10751092 with self .assertRaises (zipfile .BadZipFile ) as e :
10761093 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10771094 self .assertIn ('header offset' , str (e .exception ).lower ())
1095+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1096+
1097+ def test_bad_zip64_end_of_central_dir (self ):
1098+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1099+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1100+ zipfile .ZipFile (io .BytesIO (zipdata ))
1101+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1102+
1103+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1104+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1105+ zipfile .ZipFile (io .BytesIO (zipdata ))
1106+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1107+
1108+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1109+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1110+ zipfile .ZipFile (io .BytesIO (zipdata ))
1111+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1112+
1113+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1114+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1115+ zipfile .ZipFile (io .BytesIO (zipdata ))
1116+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1117+
1118+ def test_zip64_end_of_central_dir_record_not_found (self ):
1119+ zipdata = self .make_zip64_file ()
1120+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1121+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1122+ zipfile .ZipFile (io .BytesIO (zipdata ))
1123+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1124+
1125+ zipdata = self .make_zip64_file (
1126+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1127+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1128+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1129+ zipfile .ZipFile (io .BytesIO (zipdata ))
1130+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1131+
1132+ def test_zip64_extensible_data (self ):
1133+ # These values are what is set in the make_zip64_file method.
1134+ expected_file_size = 8
1135+ expected_compress_size = 8
1136+ expected_header_offset = 0
1137+ expected_content = b"test1234"
1138+
1139+ zipdata = self .make_zip64_file (
1140+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1141+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1142+ zinfo = zf .infolist ()[0 ]
1143+ self .assertEqual (zinfo .file_size , expected_file_size )
1144+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1145+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1146+ self .assertEqual (zf .read (zinfo ), expected_content )
1147+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1148+
1149+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1150+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1151+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10781152
10791153 def test_generated_valid_zip64_extra (self ):
10801154 # These values are what is set in the make_zip64_file method.
0 commit comments