Created
November 14, 2024 20:29
-
-
Save VladRassokhin/9299bb8fbe3169b96e7bc31f91553815 to your computer and use it in GitHub Desktop.
Generate Zip64 archive with data in zip64 end-of-archive record
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import struct | |
import zipfile | |
from zipfile import * | |
structCentralDir = "<4s4B4HL2L5H2L" | |
stringCentralDir = b"PK\001\002" | |
sizeCentralDir = struct.calcsize(structCentralDir) | |
structEndArchive = b"<4s4H2LH" | |
stringEndArchive = b"PK\005\006" | |
sizeEndCentDir = struct.calcsize(structEndArchive) | |
structEndArchive64Locator = "<4sLQL" | |
stringEndArchive64Locator = b"PK\x06\x07" | |
sizeEndCentDir64Locator = struct.calcsize(structEndArchive64Locator) | |
structEndArchive64 = "<4sQ2H2L4Q" | |
stringEndArchive64 = b"PK\x06\x06" | |
sizeEndCentDir64 = struct.calcsize(structEndArchive64) | |
class SpecialZipFile(zipfile.ZipFile): | |
def _write_end_record(self): | |
# Write central directory | |
for zinfo in self.filelist: | |
dt = zinfo.date_time | |
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2] | |
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2) | |
file_size = zinfo.file_size | |
compress_size = zinfo.compress_size | |
header_offset = zinfo.header_offset | |
extra_data = zinfo.extra | |
min_version = 0 | |
extract_version = max(min_version, zinfo.extract_version) | |
create_version = max(min_version, zinfo.create_version) | |
filename, flag_bits = zinfo._encodeFilenameFlags() | |
centdir = struct.pack(structCentralDir, | |
stringCentralDir, create_version, | |
zinfo.create_system, extract_version, zinfo.reserved, | |
flag_bits, zinfo.compress_type, dostime, dosdate, | |
zinfo.CRC, compress_size, file_size, | |
len(filename), len(extra_data), len(zinfo.comment), | |
0, zinfo.internal_attr, zinfo.external_attr, | |
header_offset) | |
self.fp.write(centdir) | |
self.fp.write(filename) | |
self.fp.write(extra_data) | |
self.fp.write(zinfo.comment) | |
pos2 = self.fp.tell() | |
# Write end-of-zip-archive record | |
centDirCount = len(self.filelist) | |
centDirSize = pos2 - self.start_dir | |
centDirOffset = self.start_dir | |
# Write the ZIP64 end-of-archive records | |
if not self._allowZip64: | |
raise LargeZipFile("Require ZIP64 extensions") | |
additionalData = b"additional data at the end of ZIP64 EOCD record" | |
zip64endrec = struct.pack( | |
structEndArchive64, stringEndArchive64, | |
44 + len(additionalData), 45, 45, 0, 0, centDirCount, centDirCount, | |
centDirSize, centDirOffset) | |
self.fp.write(zip64endrec) | |
self.fp.write(additionalData) | |
zip64locrec = struct.pack( | |
structEndArchive64Locator, | |
stringEndArchive64Locator, 0, pos2, 1) | |
self.fp.write(zip64locrec) | |
centDirCount = min(centDirCount, 0xFFFF) | |
centDirSize = min(centDirSize, 0xFFFFFFFF) | |
centDirOffset = min(centDirOffset, 0xFFFFFFFF) | |
endrec = struct.pack(structEndArchive, stringEndArchive, | |
0, 0, centDirCount, centDirCount, | |
centDirSize, centDirOffset, 0) | |
self.fp.write(endrec) | |
if self.mode == "a": | |
self.fp.truncate() | |
self.fp.flush() | |
def run(): | |
with SpecialZipFile("archive.zip", mode="w", | |
compression=ZIP_DEFLATED, compresslevel=0, | |
allowZip64=True) as zf: | |
with zf.open("file.txt", mode="w", force_zip64=True) as zi: | |
zi.write(b"content") | |
if __name__ == '__main__': | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment