@@ -885,6 +885,8 @@ def make_zip64_file(
885885 self , file_size_64_set = False , file_size_extra = False ,
886886 compress_size_64_set = False , compress_size_extra = False ,
887887 header_offset_64_set = False , header_offset_extra = False ,
888+ extensible_data = b'' ,
889+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
888890 ):
889891 """Generate bytes sequence for a zip with (incomplete) zip64 data.
890892
@@ -938,6 +940,12 @@ def make_zip64_file(
938940
939941 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
940942 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
943+ if end_of_central_dir_size is None :
944+ end_of_central_dir_size = 44 + len (extensible_data )
945+ if offset_to_end_of_central_dir is None :
946+ offset_to_end_of_central_dir = (108
947+ + 8 * len (local_zip64_fields )
948+ + 8 * len (central_zip64_fields ))
941949
942950 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
943951 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -966,14 +974,17 @@ def make_zip64_file(
966974 + filename
967975 + central_extra
968976 # Zip64 end of central directory
969- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
970- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
977+ + b"PK\x06 \x06 "
978+ + struct .pack ('<Q' , end_of_central_dir_size )
979+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
971980 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
972981 + central_dir_size
973982 + offset_to_central_dir
983+ + extensible_data
974984 # Zip64 end of central directory locator
975- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
976- + b"\x00 \x00 \x00 "
985+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
986+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
987+ + b"\x01 \x00 \x00 \x00 "
977988 # end of central directory
978989 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
979990 + b"\x00 \x00 \x00 \x00 "
@@ -1004,6 +1015,7 @@ def test_bad_zip64_extra(self):
10041015 with self .assertRaises (zipfile .BadZipFile ) as e :
10051016 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
10061017 self .assertIn ('file size' , str (e .exception ).lower ())
1018+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
10071019
10081020 # zip64 file size present, zip64 compress size present, one field in
10091021 # extra, expecting two, equals missing compress size.
@@ -1015,6 +1027,7 @@ def test_bad_zip64_extra(self):
10151027 with self .assertRaises (zipfile .BadZipFile ) as e :
10161028 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10171029 self .assertIn ('compress size' , str (e .exception ).lower ())
1030+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10181031
10191032 # zip64 compress size present, no fields in extra, expecting one,
10201033 # equals missing compress size.
@@ -1024,6 +1037,7 @@ def test_bad_zip64_extra(self):
10241037 with self .assertRaises (zipfile .BadZipFile ) as e :
10251038 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10261039 self .assertIn ('compress size' , str (e .exception ).lower ())
1040+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10271041
10281042 # zip64 file size present, zip64 compress size present, zip64 header
10291043 # offset present, two fields in extra, expecting three, equals missing
@@ -1038,6 +1052,7 @@ def test_bad_zip64_extra(self):
10381052 with self .assertRaises (zipfile .BadZipFile ) as e :
10391053 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10401054 self .assertIn ('header offset' , str (e .exception ).lower ())
1055+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10411056
10421057 # zip64 compress size present, zip64 header offset present, one field
10431058 # in extra, expecting two, equals missing header offset
@@ -1050,6 +1065,7 @@ def test_bad_zip64_extra(self):
10501065 with self .assertRaises (zipfile .BadZipFile ) as e :
10511066 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10521067 self .assertIn ('header offset' , str (e .exception ).lower ())
1068+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10531069
10541070 # zip64 file size present, zip64 header offset present, one field in
10551071 # extra, expecting two, equals missing header offset
@@ -1062,6 +1078,7 @@ def test_bad_zip64_extra(self):
10621078 with self .assertRaises (zipfile .BadZipFile ) as e :
10631079 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10641080 self .assertIn ('header offset' , str (e .exception ).lower ())
1081+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10651082
10661083 # zip64 header offset present, no fields in extra, expecting one,
10671084 # equals missing header offset
@@ -1073,6 +1090,63 @@ def test_bad_zip64_extra(self):
10731090 with self .assertRaises (zipfile .BadZipFile ) as e :
10741091 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10751092 self .assertIn ('header offset' , str (e .exception ).lower ())
1093+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1094+
1095+ def test_bad_zip64_end_of_central_dir (self ):
1096+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1097+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1098+ zipfile .ZipFile (io .BytesIO (zipdata ))
1099+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1100+
1101+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1102+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1103+ zipfile .ZipFile (io .BytesIO (zipdata ))
1104+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1105+
1106+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1107+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1108+ zipfile .ZipFile (io .BytesIO (zipdata ))
1109+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1110+
1111+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1112+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1113+ zipfile .ZipFile (io .BytesIO (zipdata ))
1114+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1115+
1116+ def test_zip64_end_of_central_dir_record_not_found (self ):
1117+ zipdata = self .make_zip64_file ()
1118+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1119+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1120+ zipfile .ZipFile (io .BytesIO (zipdata ))
1121+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1122+
1123+ zipdata = self .make_zip64_file (
1124+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1125+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1126+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1127+ zipfile .ZipFile (io .BytesIO (zipdata ))
1128+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1129+
1130+ def test_zip64_extensible_data (self ):
1131+ # These values are what is set in the make_zip64_file method.
1132+ expected_file_size = 8
1133+ expected_compress_size = 8
1134+ expected_header_offset = 0
1135+ expected_content = b"test1234"
1136+
1137+ zipdata = self .make_zip64_file (
1138+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1139+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1140+ zinfo = zf .infolist ()[0 ]
1141+ self .assertEqual (zinfo .file_size , expected_file_size )
1142+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1143+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1144+ self .assertEqual (zf .read (zinfo ), expected_content )
1145+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1146+
1147+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1148+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1149+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10761150
10771151 def test_generated_valid_zip64_extra (self ):
10781152 # These values are what is set in the make_zip64_file method.
0 commit comments