@@ -884,6 +884,8 @@ def make_zip64_file(
884884 self , file_size_64_set = False , file_size_extra = False ,
885885 compress_size_64_set = False , compress_size_extra = False ,
886886 header_offset_64_set = False , header_offset_extra = False ,
887+ extensible_data = b'' ,
888+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
887889 ):
888890 """Generate bytes sequence for a zip with (incomplete) zip64 data.
889891
@@ -937,6 +939,12 @@ def make_zip64_file(
937939
938940 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
939941 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
942+ if end_of_central_dir_size is None :
943+ end_of_central_dir_size = 44 + len (extensible_data )
944+ if offset_to_end_of_central_dir is None :
945+ offset_to_end_of_central_dir = (108
946+ + 8 * len (local_zip64_fields )
947+ + 8 * len (central_zip64_fields ))
940948
941949 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
942950 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -965,14 +973,17 @@ def make_zip64_file(
965973 + filename
966974 + central_extra
967975 # Zip64 end of central directory
968- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
969- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
976+ + b"PK\x06 \x06 "
977+ + struct .pack ('<Q' , end_of_central_dir_size )
978+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
970979 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
971980 + central_dir_size
972981 + offset_to_central_dir
982+ + extensible_data
973983 # Zip64 end of central directory locator
974- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
975- + b"\x00 \x00 \x00 "
984+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
985+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
986+ + b"\x01 \x00 \x00 \x00 "
976987 # end of central directory
977988 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
978989 + b"\x00 \x00 \x00 \x00 "
@@ -1003,6 +1014,7 @@ def test_bad_zip64_extra(self):
10031014 with self .assertRaises (zipfile .BadZipFile ) as e :
10041015 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
10051016 self .assertIn ('file size' , str (e .exception ).lower ())
1017+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
10061018
10071019 # zip64 file size present, zip64 compress size present, one field in
10081020 # extra, expecting two, equals missing compress size.
@@ -1014,6 +1026,7 @@ def test_bad_zip64_extra(self):
10141026 with self .assertRaises (zipfile .BadZipFile ) as e :
10151027 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10161028 self .assertIn ('compress size' , str (e .exception ).lower ())
1029+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10171030
10181031 # zip64 compress size present, no fields in extra, expecting one,
10191032 # equals missing compress size.
@@ -1023,6 +1036,7 @@ def test_bad_zip64_extra(self):
10231036 with self .assertRaises (zipfile .BadZipFile ) as e :
10241037 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10251038 self .assertIn ('compress size' , str (e .exception ).lower ())
1039+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10261040
10271041 # zip64 file size present, zip64 compress size present, zip64 header
10281042 # offset present, two fields in extra, expecting three, equals missing
@@ -1037,6 +1051,7 @@ def test_bad_zip64_extra(self):
10371051 with self .assertRaises (zipfile .BadZipFile ) as e :
10381052 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10391053 self .assertIn ('header offset' , str (e .exception ).lower ())
1054+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10401055
10411056 # zip64 compress size present, zip64 header offset present, one field
10421057 # in extra, expecting two, equals missing header offset
@@ -1049,6 +1064,7 @@ def test_bad_zip64_extra(self):
10491064 with self .assertRaises (zipfile .BadZipFile ) as e :
10501065 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10511066 self .assertIn ('header offset' , str (e .exception ).lower ())
1067+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10521068
10531069 # zip64 file size present, zip64 header offset present, one field in
10541070 # extra, expecting two, equals missing header offset
@@ -1061,6 +1077,7 @@ def test_bad_zip64_extra(self):
10611077 with self .assertRaises (zipfile .BadZipFile ) as e :
10621078 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10631079 self .assertIn ('header offset' , str (e .exception ).lower ())
1080+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10641081
10651082 # zip64 header offset present, no fields in extra, expecting one,
10661083 # equals missing header offset
@@ -1072,6 +1089,63 @@ def test_bad_zip64_extra(self):
10721089 with self .assertRaises (zipfile .BadZipFile ) as e :
10731090 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10741091 self .assertIn ('header offset' , str (e .exception ).lower ())
1092+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1093+
1094+ def test_bad_zip64_end_of_central_dir (self ):
1095+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1096+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1097+ zipfile .ZipFile (io .BytesIO (zipdata ))
1098+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1099+
1100+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1101+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1102+ zipfile .ZipFile (io .BytesIO (zipdata ))
1103+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1104+
1105+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1106+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1107+ zipfile .ZipFile (io .BytesIO (zipdata ))
1108+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1109+
1110+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1111+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1112+ zipfile .ZipFile (io .BytesIO (zipdata ))
1113+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1114+
1115+ def test_zip64_end_of_central_dir_record_not_found (self ):
1116+ zipdata = self .make_zip64_file ()
1117+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1118+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1119+ zipfile .ZipFile (io .BytesIO (zipdata ))
1120+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1121+
1122+ zipdata = self .make_zip64_file (
1123+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1124+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1125+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1126+ zipfile .ZipFile (io .BytesIO (zipdata ))
1127+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1128+
1129+ def test_zip64_extensible_data (self ):
1130+ # These values are what is set in the make_zip64_file method.
1131+ expected_file_size = 8
1132+ expected_compress_size = 8
1133+ expected_header_offset = 0
1134+ expected_content = b"test1234"
1135+
1136+ zipdata = self .make_zip64_file (
1137+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1138+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1139+ zinfo = zf .infolist ()[0 ]
1140+ self .assertEqual (zinfo .file_size , expected_file_size )
1141+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1142+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1143+ self .assertEqual (zf .read (zinfo ), expected_content )
1144+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1145+
1146+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1147+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1148+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10751149
10761150 def test_generated_valid_zip64_extra (self ):
10771151 # These values are what is set in the make_zip64_file method.
0 commit comments