@@ -859,6 +859,8 @@ def make_zip64_file(
859859 self , file_size_64_set = False , file_size_extra = False ,
860860 compress_size_64_set = False , compress_size_extra = False ,
861861 header_offset_64_set = False , header_offset_extra = False ,
862+ extensible_data = b'' ,
863+ end_of_central_dir_size = None , offset_to_end_of_central_dir = None ,
862864 ):
863865 """Generate bytes sequence for a zip with (incomplete) zip64 data.
864866
@@ -912,6 +914,12 @@ def make_zip64_file(
912914
913915 central_dir_size = struct .pack ('<Q' , 58 + 8 * len (central_zip64_fields ))
914916 offset_to_central_dir = struct .pack ('<Q' , 50 + 8 * len (local_zip64_fields ))
917+ if end_of_central_dir_size is None :
918+ end_of_central_dir_size = 44 + len (extensible_data )
919+ if offset_to_end_of_central_dir is None :
920+ offset_to_end_of_central_dir = (108
921+ + 8 * len (local_zip64_fields )
922+ + 8 * len (central_zip64_fields ))
915923
916924 local_extra_length = struct .pack ("<H" , 4 + 8 * len (local_zip64_fields ))
917925 central_extra_length = struct .pack ("<H" , 4 + 8 * len (central_zip64_fields ))
@@ -940,14 +948,17 @@ def make_zip64_file(
940948 + filename
941949 + central_extra
942950 # Zip64 end of central directory
943- + b"PK\x06 \x06 ,\x00 \x00 \x00 \x00 \x00 \x00 \x00 -\x00 -"
944- + b"\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
951+ + b"PK\x06 \x06 "
952+ + struct .pack ('<Q' , end_of_central_dir_size )
953+ + b"-\x00 -\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 "
945954 + b"\x00 \x00 \x01 \x00 \x00 \x00 \x00 \x00 \x00 \x00 "
946955 + central_dir_size
947956 + offset_to_central_dir
957+ + extensible_data
948958 # Zip64 end of central directory locator
949- + b"PK\x06 \x07 \x00 \x00 \x00 \x00 l\x00 \x00 \x00 \x00 \x00 \x00 \x00 \x01 "
950- + b"\x00 \x00 \x00 "
959+ + b"PK\x06 \x07 \x00 \x00 \x00 \x00 "
960+ + struct .pack ('<Q' , offset_to_end_of_central_dir )
961+ + b"\x01 \x00 \x00 \x00 "
951962 # end of central directory
952963 + b"PK\x05 \x06 \x00 \x00 \x00 \x00 \x01 \x00 \x01 \x00 :\x00 \x00 \x00 2\x00 "
953964 + b"\x00 \x00 \x00 \x00 "
@@ -978,6 +989,7 @@ def test_bad_zip64_extra(self):
978989 with self .assertRaises (zipfile .BadZipFile ) as e :
979990 zipfile .ZipFile (io .BytesIO (missing_file_size_extra ))
980991 self .assertIn ('file size' , str (e .exception ).lower ())
992+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_file_size_extra )))
981993
982994 # zip64 file size present, zip64 compress size present, one field in
983995 # extra, expecting two, equals missing compress size.
@@ -989,6 +1001,7 @@ def test_bad_zip64_extra(self):
9891001 with self .assertRaises (zipfile .BadZipFile ) as e :
9901002 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
9911003 self .assertIn ('compress size' , str (e .exception ).lower ())
1004+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
9921005
9931006 # zip64 compress size present, no fields in extra, expecting one,
9941007 # equals missing compress size.
@@ -998,6 +1011,7 @@ def test_bad_zip64_extra(self):
9981011 with self .assertRaises (zipfile .BadZipFile ) as e :
9991012 zipfile .ZipFile (io .BytesIO (missing_compress_size_extra ))
10001013 self .assertIn ('compress size' , str (e .exception ).lower ())
1014+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_compress_size_extra )))
10011015
10021016 # zip64 file size present, zip64 compress size present, zip64 header
10031017 # offset present, two fields in extra, expecting three, equals missing
@@ -1012,6 +1026,7 @@ def test_bad_zip64_extra(self):
10121026 with self .assertRaises (zipfile .BadZipFile ) as e :
10131027 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10141028 self .assertIn ('header offset' , str (e .exception ).lower ())
1029+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10151030
10161031 # zip64 compress size present, zip64 header offset present, one field
10171032 # in extra, expecting two, equals missing header offset
@@ -1024,6 +1039,7 @@ def test_bad_zip64_extra(self):
10241039 with self .assertRaises (zipfile .BadZipFile ) as e :
10251040 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10261041 self .assertIn ('header offset' , str (e .exception ).lower ())
1042+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10271043
10281044 # zip64 file size present, zip64 header offset present, one field in
10291045 # extra, expecting two, equals missing header offset
@@ -1036,6 +1052,7 @@ def test_bad_zip64_extra(self):
10361052 with self .assertRaises (zipfile .BadZipFile ) as e :
10371053 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10381054 self .assertIn ('header offset' , str (e .exception ).lower ())
1055+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
10391056
10401057 # zip64 header offset present, no fields in extra, expecting one,
10411058 # equals missing header offset
@@ -1047,6 +1064,63 @@ def test_bad_zip64_extra(self):
10471064 with self .assertRaises (zipfile .BadZipFile ) as e :
10481065 zipfile .ZipFile (io .BytesIO (missing_header_offset_extra ))
10491066 self .assertIn ('header offset' , str (e .exception ).lower ())
1067+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (missing_header_offset_extra )))
1068+
1069+ def test_bad_zip64_end_of_central_dir (self ):
1070+ zipdata = self .make_zip64_file (end_of_central_dir_size = 0 )
1071+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1072+ zipfile .ZipFile (io .BytesIO (zipdata ))
1073+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1074+
1075+ zipdata = self .make_zip64_file (end_of_central_dir_size = 100 )
1076+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1077+ zipfile .ZipFile (io .BytesIO (zipdata ))
1078+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1079+
1080+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 0 )
1081+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*record' ):
1082+ zipfile .ZipFile (io .BytesIO (zipdata ))
1083+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1084+
1085+ zipdata = self .make_zip64_file (offset_to_end_of_central_dir = 1000 )
1086+ with self .assertRaisesRegex (zipfile .BadZipFile , 'Corrupt.*locator' ):
1087+ zipfile .ZipFile (io .BytesIO (zipdata ))
1088+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1089+
1090+ def test_zip64_end_of_central_dir_record_not_found (self ):
1091+ zipdata = self .make_zip64_file ()
1092+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1093+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1094+ zipfile .ZipFile (io .BytesIO (zipdata ))
1095+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1096+
1097+ zipdata = self .make_zip64_file (
1098+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1099+ zipdata = zipdata .replace (b"PK\x06 \x06 " , b'\x00 ' * 4 )
1100+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1101+ zipfile .ZipFile (io .BytesIO (zipdata ))
1102+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (zipdata )))
1103+
1104+ def test_zip64_extensible_data (self ):
1105+ # These values are what is set in the make_zip64_file method.
1106+ expected_file_size = 8
1107+ expected_compress_size = 8
1108+ expected_header_offset = 0
1109+ expected_content = b"test1234"
1110+
1111+ zipdata = self .make_zip64_file (
1112+ extensible_data = b'\xca \xfe \x04 \x00 \x00 \x00 data' )
1113+ with zipfile .ZipFile (io .BytesIO (zipdata )) as zf :
1114+ zinfo = zf .infolist ()[0 ]
1115+ self .assertEqual (zinfo .file_size , expected_file_size )
1116+ self .assertEqual (zinfo .compress_size , expected_compress_size )
1117+ self .assertEqual (zinfo .header_offset , expected_header_offset )
1118+ self .assertEqual (zf .read (zinfo ), expected_content )
1119+ self .assertTrue (zipfile .is_zipfile (io .BytesIO (zipdata )))
1120+
1121+ with self .assertRaisesRegex (zipfile .BadZipFile , 'record not found' ):
1122+ zipfile .ZipFile (io .BytesIO (b'prepended' + zipdata ))
1123+ self .assertFalse (zipfile .is_zipfile (io .BytesIO (b'prepended' + zipdata )))
10501124
10511125 def test_generated_valid_zip64_extra (self ):
10521126 # These values are what is set in the make_zip64_file method.
0 commit comments