Source code for zipwire._zipinfo

"""ZipInfo subclass that is fully compatible with stdlib zipfile.ZipInfo."""

from __future__ import annotations

import struct
import typing
import zipfile

from zipwire._constants import ZIP64_EXTRA_FIELD_ID

if typing.TYPE_CHECKING:
    from zipwire._parser import CentralDirEntry


[docs] class RemoteZipInfo(zipfile.ZipInfo): """A ZipInfo subclass for entries from a remote ZIP archive. ``isinstance(info, zipfile.ZipInfo)`` returns True. All standard attributes and methods (is_dir, FileHeader, etc.) are available. """ @classmethod def _from_central_dir_entry(cls, entry: CentralDirEntry) -> RemoteZipInfo: """Construct a ZipInfo from a parsed central directory entry.""" # Decode filename # Bit 11 of flags indicates UTF-8 encoding if entry.flags & 0x800: filename = entry.filename.decode("utf-8") else: filename = entry.filename.decode("cp437") info = cls(filename) # Convert DOS date/time to tuple info.date_time = ( ((entry.mod_date >> 9) & 0x7F) + 1980, # year (entry.mod_date >> 5) & 0x0F, # month entry.mod_date & 0x1F, # day (entry.mod_time >> 11) & 0x1F, # hour (entry.mod_time >> 5) & 0x3F, # minute (entry.mod_time & 0x1F) * 2, # second ) info.compress_type = entry.compression_method info.CRC = entry.crc32 info.compress_size = entry.compressed_size info.file_size = entry.uncompressed_size info.header_offset = entry.header_offset info.internal_attr = entry.internal_attr info.external_attr = entry.external_attr info.create_system = (entry.version_made_by >> 8) & 0xFF info.create_version = entry.version_made_by & 0xFF info.extract_version = entry.version_needed info.flag_bits = entry.flags info.volume = entry.disk_start info.extra = entry.extra info.comment = entry.comment # Handle ZIP64 extra field _apply_zip64_extra(info) return info
def _apply_zip64_extra(info: RemoteZipInfo) -> None: """Parse ZIP64 extra field and update sizes/offset if present.""" extra = info.extra if not extra: return offset = 0 while offset + 4 <= len(extra): header_id, data_size = struct.unpack_from("<HH", extra, offset) offset += 4 if header_id == ZIP64_EXTRA_FIELD_ID: # ZIP64 extended information extra field # Fields appear in order only if the corresponding regular field is 0xFFFFFFFF idx = 0 if info.file_size == 0xFFFFFFFF and idx + 8 <= data_size: info.file_size = struct.unpack_from("<Q", extra, offset + idx)[0] idx += 8 if info.compress_size == 0xFFFFFFFF and idx + 8 <= data_size: info.compress_size = struct.unpack_from("<Q", extra, offset + idx)[0] idx += 8 if info.header_offset == 0xFFFFFFFF and idx + 8 <= data_size: info.header_offset = struct.unpack_from("<Q", extra, offset + idx)[0] idx += 8 if info.volume == 0xFFFF and idx + 4 <= data_size: info.volume = struct.unpack_from("<I", extra, offset + idx)[0] return offset += data_size