The original format uses 16-bit counts and 32-bit sizes and offsets, which stop at 65,535 members and 4 GiB. ZIP64 adds 64-bit copies of those values. The old fields stay in place with a sentinel value in them, so the layout of the original records does not change. Any member that needs ZIP64 requires version needed 4.5.
The sentinels: when each field moves
A field too small for its value is set to all ones, 0xFFFF or
0xFFFFFFFF, and the real value goes in a ZIP64 field. A value of exactly
0xFFFFFFFF also has to move, because in that field it can only mean “see
ZIP64”.
| Record | Field | Sentinel | Real value is in |
|---|---|---|---|
| End record | Disk number | 0xFFFF | ZIP64 end record |
| Directory disk | 0xFFFF | ||
| Entries on this disk | 0xFFFF | ||
| Total entries | 0xFFFF | ||
| Directory size | 0xFFFFFFFF | ||
| Directory offset | 0xFFFFFFFF | ||
| Central header | Uncompressed size | 0xFFFFFFFF | That header’s 0x0001 extra block |
| Compressed size | 0xFFFFFFFF | ||
| Local header offset | 0xFFFFFFFF | ||
| Disk number | 0xFFFF | ||
| Local header | Uncompressed size | 0xFFFFFFFF | That header’s 0x0001 extra block, holding both sizes |
| Compressed size | 0xFFFFFFFF | ||
| Data descriptor | Both sizes | none | The descriptor’s own sizes become 8 bytes |
Each field moves on its own, so a member can have a ZIP64 offset and 32-bit sizes. A reader treats a value as moved only if the field holds its sentinel. A sentinel with no matching ZIP64 data is a damaged archive. The explorer reports that case, and uses a sentinel in the end record only when a ZIP64 end record is present.
ZIP64 end of central directory record
Comes after the central directory, and any digital signature, and before the locator.
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | Signature | 50 4B 06 06, the value 0x06064B50. |
4 | 8 | Record size | The size of the rest of the record, without the first 12 bytes. 44 for version 1 with no extensible data. |
12 | 2 | Version made by | As in the central directory. |
14 | 2 | Version needed | At least 45. |
16 | 4 | Disk number | The number of this disk. |
20 | 4 | Directory disk | The disk the central directory starts on. |
24 | 8 | Entries on this disk | The number of central directory entries on this disk. |
32 | 8 | Total entries | The total number of entries. |
40 | 8 | Directory size | The size of the central directory. |
48 | 8 | Directory offset | The offset of the start of the central directory on its first disk. |
56 | varies | Extensible data | Reserved for PKWARE’s use. Readers should skip it, using the record size. |
Version 2 of the record
When the central directory is encrypted, the version needed is 62 and these fields follow directory offset, where the extensible data would be. The entry count for this disk is zero.
| Offset | Size | Name | Description |
|---|---|---|---|
56 | 2 | Compression method | The method used to compress the central directory. |
58 | 8 | Compressed size | The compressed size of the central directory. |
66 | 8 | Original size | The uncompressed size of the central directory. |
74 | 2 | AlgId | The encryption algorithm. |
76 | 2 | BitLen | The key length in bits. |
78 | 2 | Flags | The encryption flags. |
80 | 2 | HashID | The hash used for the central directory: 0x0000 none, 0x0001 CRC-32, 0x8003 MD5, 0x8004 SHA-1, 0x8007 RIPEMD-160, 0x800C SHA-256, 0x800D SHA-384, 0x800E SHA-512. |
82 | 2 | Hash length | The hash length, 0 if unhashed. |
84 | hash length | Hash data | The hash. |
ZIP64 end of central directory locator
A fixed 20-byte record immediately before the end record. Finding it there is how a reader knows the archive uses ZIP64.
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | Signature | 50 4B 06 07, the value 0x07064B50. |
4 | 4 | ZIP64 end disk | The disk holding the ZIP64 end record. |
8 | 8 | ZIP64 end offset | The offset of the ZIP64 end record. |
16 | 4 | Total disks | The number of disks in the archive. 1 for a single file. |
The offset counts from the start of the disk it refers to, so an archive with data in front can need shifting here as well. The locator must be on the same disk as the end record.
The 0x0001 extra field
| Size | Name | Description |
|---|---|---|
| 2 | Header ID | 0x0001. |
| 2 | Data size | The total size of the fields that follow. |
| 8 | Original size | The uncompressed size, if that header field is 0xFFFFFFFF. |
| 8 | Compressed size | The compressed size, if that header field is 0xFFFFFFFF. |
| 8 | Local header offset | The offset, if that header field is 0xFFFFFFFF. |
| 4 | Disk number | The disk number, if that header field is 0xFFFF. |
The order of the fields is fixed, and each appears only if the matching field in the record is set to its sentinel. So the field’s position depends on which earlier fields are present.
Note that the order here is original size then compressed size, the opposite of their order in the headers.
In a local header, the block must hold both sizes whenever it is used, even if only one of them overflows. If the central directory is encrypted and bit 13 is set, the original size in the local header is stored as zero.
The presence of this block on a member with a data descriptor tells a reader to expect the descriptor’s 64-bit sizes. Writers that do not yet know the sizes when they write the local header differ in what they put in it, so a reader should take the sizes from the central directory where it has one.
Reading ZIP64
- Find the end record. Look 20 bytes before it for the locator signature.
- If the locator is present, read the ZIP64 end record at its offset. Check that it
lies before the locator and carries the
50 4B 06 06signature. - Take each value from the end record unless it holds a sentinel, in which case take the 64-bit value from the ZIP64 record.
- Walk the central directory. For each header, read its 0x0001 block for each field that holds a sentinel, in the fixed order.
Writing ZIP64
- Use ZIP64 fields for the values that need them. They are also allowed for smaller values, and APPNOTE permits a writer to use them regardless of a file’s size.
- Write the ZIP64 end record and locator whenever any end record field holds a sentinel.
- Set the version needed to at least 45 on every member using ZIP64.
- Keep total values and per-disk counts consistent, and write the locator’s disk count as 1 for a single file.