@@ -898,6 +898,8 @@ def make_zip64_file(
898898 self , file_size_64_set = False , file_size_extra = False ,
899899 compress_size_64_set = False , compress_size_extra = False ,
900900 header_offset_64_set = False , header_offset_extra = False ,
901+ extensible_data = b'' ,
902+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
901903 ):
902904 """Generate bytes sequence for a zip with (incomplete) zip64 data.
903905
@@ -951,6 +953,12 @@ def make_zip64_file(
951953
952954 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
953955 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
956+ if end_of_central_dir_size is None :
957+ end_of_central_dir_size = 44 + len (extensible_data )
958+ if offset_to_end_of_central_dir is None :
959+ offset_to_end_of_central_dir = (108
960+ + 8 * len (local_zip64_fields )
961+ + 8 * len (central_zip64_fields ))
954962
955963 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
956964 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -979,14 +987,17 @@ def make_zip64_file(
979987 + filename
980988 + central_extra
981989 # Zip64 end of central directory
982- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
983- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
990+ + b"PK\x06 \x06 "
991+ + struct .pack ('<Q' , end_of_central_dir_size )
992+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
984993 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
985994 + central_dir_size
986995 + offset_to_central_dir
996+ + extensible_data
987997 # Zip64 end of central directory locator
988- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
989- + b"\x00 \x00 \x00 "
998+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
999+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
1000+ + b"\x01 \x00 \x00 \x00 "
9901001 # end of central directory
9911002 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
9921003 + b"\x00 \x00 \x00 \x00 "
@@ -1017,6 +1028,7 @@ def test_bad_zip64_extra(self):
10171028 with self .assertRaises (zipfile .BadZipFile ) as e :
10181029 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
10191030 self .assertIn ('file size' , str (e .exception ).lower ())
1031+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
10201032
10211033 # zip64 file size present, zip64 compress size present, one field in
10221034 # extra, expecting two, equals missing compress size.
@@ -1028,6 +1040,7 @@ def test_bad_zip64_extra(self):
10281040 with self .assertRaises (zipfile .BadZipFile ) as e :
10291041 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10301042 self .assertIn ('compress size' , str (e .exception ).lower ())
1043+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10311044
10321045 # zip64 compress size present, no fields in extra, expecting one,
10331046 # equals missing compress size.
@@ -1037,6 +1050,7 @@ def test_bad_zip64_extra(self):
10371050 with self .assertRaises (zipfile .BadZipFile ) as e :
10381051 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10391052 self .assertIn ('compress size' , str (e .exception ).lower ())
1053+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10401054
10411055 # zip64 file size present, zip64 compress size present, zip64 header
10421056 # offset present, two fields in extra, expecting three, equals missing
@@ -1051,6 +1065,7 @@ def test_bad_zip64_extra(self):
10511065 with self .assertRaises (zipfile .BadZipFile ) as e :
10521066 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10531067 self .assertIn ('header offset' , str (e .exception ).lower ())
1068+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10541069
10551070 # zip64 compress size present, zip64 header offset present, one field
10561071 # in extra, expecting two, equals missing header offset
@@ -1063,6 +1078,7 @@ def test_bad_zip64_extra(self):
10631078 with self .assertRaises (zipfile .BadZipFile ) as e :
10641079 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10651080 self .assertIn ('header offset' , str (e .exception ).lower ())
1081+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10661082
10671083 # zip64 file size present, zip64 header offset present, one field in
10681084 # extra, expecting two, equals missing header offset
@@ -1075,6 +1091,7 @@ def test_bad_zip64_extra(self):
10751091 with self .assertRaises (zipfile .BadZipFile ) as e :
10761092 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10771093 self .assertIn ('header offset' , str (e .exception ).lower ())
1094+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10781095
10791096 # zip64 header offset present, no fields in extra, expecting one,
10801097 # equals missing header offset
@@ -1086,6 +1103,63 @@ def test_bad_zip64_extra(self):
10861103 with self .assertRaises (zipfile .BadZipFile ) as e :
10871104 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10881105 self .assertIn ('header offset' , str (e .exception ).lower ())
1106+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1107+
1108+ def test_bad_zip64_end_of_central_dir (self ):
1109+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1110+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1111+ zipfile .ZipFile (io .BytesIO (zipdata ))
1112+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1113+
1114+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1115+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1116+ zipfile .ZipFile (io .BytesIO (zipdata ))
1117+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1118+
1119+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1120+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1121+ zipfile .ZipFile (io .BytesIO (zipdata ))
1122+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1123+
1124+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1125+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1126+ zipfile .ZipFile (io .BytesIO (zipdata ))
1127+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1128+
1129+ def test_zip64_end_of_central_dir_record_not_found (self ):
1130+ zipdata = self .make_zip64_file ()
1131+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1132+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1133+ zipfile .ZipFile (io .BytesIO (zipdata ))
1134+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1135+
1136+ zipdata = self .make_zip64_file (
1137+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1138+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1139+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1140+ zipfile .ZipFile (io .BytesIO (zipdata ))
1141+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1142+
1143+ def test_zip64_extensible_data (self ):
1144+ # These values are what is set in the make_zip64_file method.
1145+ expected_file_size = 8
1146+ expected_compress_size = 8
1147+ expected_header_offset = 0
1148+ expected_content = b"test1234"
1149+
1150+ zipdata = self .make_zip64_file (
1151+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1152+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1153+ zinfo = zf .infolist ()[0 ]
1154+ self .assertEqual (zinfo .file_size , expected_file_size )
1155+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1156+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1157+ self .assertEqual (zf .read (zinfo ), expected_content )
1158+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1159+
1160+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1161+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1162+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10891163
10901164 def test_generated_valid_zip64_extra (self ):
10911165 # These values are what is set in the make_zip64_file method.
0 commit comments