Skip to content

Commit

Permalink
Support ZIP64 #4
Browse files Browse the repository at this point in the history
  • Loading branch information
saulpw committed Jun 30, 2022
1 parent bb0ef3a commit 7490d86
Showing 1 changed file with 57 additions and 8 deletions.
65 changes: 57 additions & 8 deletions unzip_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,36 @@ class RemoteZipInfo:
compress_size:int = 0
file_size:int = 0

def parse_extra(self, extra):
i = 0
while i < len(extra):
fieldid, fieldsz = struct.unpack_from('<HH', extra, i)
i += 4

if fieldid == 0x0001: # ZIP64
if fieldsz == 8: fmt = '<Q'
elif fieldsz == 16: fmt = '<QQ'
elif fieldsz == 24: fmt = '<QQQ'
elif fieldsz == 28: fmt = '<QQQI'

vals = list(struct.unpack_from(fmt, extra, i))
if self.file_size == 0xffffffff:
self.file_size = vals.pop(0)

if self.compress_size == 0xffffffff:
self.compress_size = vals.pop(0)

if self.header_offset == 0xffffffff:
self.header_offset = vals.pop(0)

i += fieldsz


class RemoteZipFile:
fmt_endcdir = 'IHHHHIIH'
fmt_cdirentry = '<IHHHHIIIIHHHHHII'
fmt_localhdr = '<IHHHIIIIHH'
fmt_eocd = '<IHHHHIIH' # end of central directory
fmt_eocd64 = '<IQHHIIQQQQ' # end of central directory ZIP64
fmt_cdirentry = '<IHHHHIIIIHHHHHII' # central directory entry
fmt_localhdr = '<IHHHIIIIHH' # local directory header

def __init__(self, url):
self.url = url
Expand All @@ -45,9 +70,23 @@ def infolist(self):

sz = int(resp.headers['Content-Length'])
resp = self.get_range(sz-65536, 65536)
i = resp.data.rfind(b'\x50\x4b\x05\x06')

magic, disk_num, disk_start, disk_num_records, total_num_records, cdir_bytes, cdir_start, comment_len = struct.unpack_from(self.fmt_endcdir, resp.data, offset=i)
eocdloc = eocd = eocd64 = None

cdir_start = 0
i = resp.data.rfind(b'\x50\x4b\x06\x06')
if i >= 0:
magic, eocd_sz, create_ver, min_ver, disk_num, disk_start, disk_num_records, total_num_records, \
cdir_bytes, cdir_start = struct.unpack_from(self.fmt_eocd64, resp.data, offset=i)
else:
i = resp.data.rfind(b'\x50\x4b\x05\x06')
if i >= 0:
magic, \
disk_num, disk_start, disk_num_records, total_num_records, \
cdir_bytes, cdir_start, comment_len = struct.unpack_from(self.fmt_eocd, resp.data, offset=i)

if cdir_start <= 0 or cdir_start > sz:
error('cannot find central directory')

filehdr_index = 65536 - (sz - cdir_start)
cdir_end = filehdr_index + cdir_bytes
Expand All @@ -59,11 +98,21 @@ def infolist(self):
disknum_start, internal_attr, external_attr, local_header_ofs = \
struct.unpack_from(self.fmt_cdirentry, resp.data, offset=filehdr_index)

filename = resp.data[filehdr_index+sizeof_cdirentry:filehdr_index+sizeof_cdirentry+fnlen]
filehdr_index += sizeof_cdirentry

filename = resp.data[filehdr_index:filehdr_index+fnlen]
filehdr_index += fnlen

extra = resp.data[filehdr_index:filehdr_index+extralen]
filehdr_index += extralen

comment = resp.data[filehdr_index:filehdr_index+commentlen]
filehdr_index += commentlen

filehdr_index += sizeof_cdirentry + fnlen + extralen + commentlen
rzi = RemoteZipInfo(filename.decode(), date_time, local_header_ofs, method, complen, uncomplen)

yield RemoteZipInfo(filename.decode(), date_time, local_header_ofs, method, complen, uncomplen)
rzi.parse_extra(extra)
yield rzi

def get_range(self, start, n):
return self.http.request('GET', self.url, headers={'Range': f'bytes={start}-{start+n-1}'}, preload_content=False)
Expand Down

0 comments on commit 7490d86

Please sign in to comment.