The ZIP format, as LiveZip uses it¶
LiveZip only needs a small subset of PKZIP / ZIP64. This page lists the records it emits, in the order it emits them, and explains the two techniques that make streaming possible.
Archive layout¶
flowchart TB
subgraph entry["For each file"]
LH["Local file header<br/>(PK\x03\x04)"]
DATA["Payload bytes<br/>(stored or DEFLATE)"]
DD["Data descriptor<br/>(PK\x07\x08)"]
LH --> DATA --> DD
end
entry --> CD["Central directory<br/>one entry per file (PK\x01\x02)"]
CD --> Z64["ZIP64 end of central directory (PK\x06\x06)<br/>ZIP64 locator (PK\x06\x07)<br/><i>only when needed</i>"]
Z64 --> EOCD["End of central directory (PK\x05\x06)<br/>always last, carries the archive comment"]
Everything before the central directory is a pure function of the payloads;
everything from the central directory onward is a pure function of the offsets
computed in prepare(). That split is why LiveZip can stream.
The records¶
| Record | Signature | Model | Purpose |
|---|---|---|---|
| Local file header | PK\x03\x04 |
LocalFileHeader |
Entry name, method, timestamp. Sizes and CRC zeroed. |
| Data descriptor | PK\x07\x08 |
DataDescriptor |
CRC and both sizes, written after the payload. |
| Central directory entry | PK\x01\x02 |
CentralDirectoryFile |
The authoritative index entry, with real sizes/CRC/offset. |
| ZIP64 EOCD record | PK\x06\x06 |
Zip64EndOfCentralDirectoryRecord |
64-bit counts and offsets. Optional. |
| ZIP64 EOCD locator | PK\x06\x07 |
Zip64EndOfCentralDirectoryLocator |
Points at the ZIP64 EOCD record. Optional. |
| End of central directory | PK\x05\x06 |
EndOfCentralDirectoryRecord |
32-bit summary, archive comment. Always last. |
All multi-byte integers are little-endian. Dates use the DOS format (clamped to 1980–2099, expressed in UTC).
Technique 1: the streaming flag¶
The local file header comes before the payload, but the CRC32 and the compressed/uncompressed sizes are only known after the payload has been read. Classic writers solve this by buffering each file or by seeking back to patch the header. LiveZip does neither.
Instead it sets general-purpose bit 3 (the "streaming" flag) and:
- writes
crc32 = 0,compressed_size = 0,uncompressed_size = 0in the local header, and - appends a data descriptor carrying the real values after the payload.
Readers that understand bit 3 look for the descriptor. Python's own zipfile
reads sizes and CRC from the central directory and therefore never even needs to
parse it — which is why LiveZip archives open cleanly everywhere.
sequenceDiagram
participant W as Writer
participant R as Reader
W->>R: local header (sizes = 0, bit 3 set)
W->>R: payload…
Note over W: CRC computed while streaming
W->>R: data descriptor (crc, sizes)
W->>R: …central directory (authoritative)
Technique 2: the ZIP64 extra field¶
ZIP64 is a set of escape hatches for values that overflow the original 32-bit
fields. The rule is precise: a ZIP64 extra field (id 0x0001) is present on a
central directory entry only when at least one of its 32-bit fields is set to
0xFFFFFFFF, and it contains only the fields that overflowed, in a fixed
order.
flowchart TD
A["central directory entry"] --> B{"compressed, uncompressed<br/>or header offset > 4 GiB?"}
B -- no --> C["no extra field"]
B -- yes --> D["ZIP64 extra field (id 0x0001)<br/>packing only the overflowed fields:<br/>original size, compressed size,<br/>header offset, disk start"]
LiveZip follows this exactly. The threshold is the 32-bit boundary
(0xFFFFFFFF), not the 16-bit one: the central directory stores sizes on 32
bits, so an entry only needs ZIP64 once it exceeds 4 GiB. Helper:
models.needs_zip64_sizes().
The data descriptor widens to 8-byte sizes under the same condition, so a single file larger than 4 GiB still streams correctly.
ZIP64 EOCD is a different switch
The ZIP64 end-of-central-directory records are emitted when the archive
exceeds 65 535 entries or a central-directory offset overflows its 32-bit
field — not when a single file is large.
Zip64EndOfCentralDirectoryRecordSegment.is_required is the single source of
truth for this.
What LiveZip always sets¶
| Flag / field | Value | Reason |
|---|---|---|
| General purpose, bit 3 | set | Streaming; sizes/CRC live in the data descriptor. |
| General purpose, bit 11 | set | Entry names are UTF-8. |
| Version needed / made by | 4.5 | ZIP64-capable reader required. |
| Compression method | 0 (store) or 8 (deflate) |
Chosen by the storage strategy. |
Further reading¶
- PKWARE APPNOTE — sections 4.3.7 (local header), 4.3.9 (data descriptor), 4.3.12 (central directory), 4.3.14–4.3.16 (EOCD records), 4.5.3 (ZIP64 extra field).
src/livezip/models.py— the models themselves.