A cabinet is a CFHEADER, then one CFFOLDER for each folder,
then one CFFILE for each file, then the CFDATA blocks of each
folder. This page follows Microsoft’s “Microsoft Cabinet File Format” document from the
Cabinet SDK, which [MS-CAB] repeats. Numbers are little-endian; the format version is
1.3.
CFHEADER
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | signature | MSCF (4D 53 43 46). |
4 | 4 | reserved1 | Zero. |
8 | 4 | cbCabinet | Size of this cabinet file in bytes. |
12 | 4 | reserved2 | Zero. |
16 | 4 | coffFiles | Offset of the first CFFILE from the start of the file. |
20 | 4 | reserved3 | Zero. |
24 | 1 | versionMinor | 3. |
25 | 1 | versionMajor | 1. |
26 | 2 | cFolders | Number of CFFOLDER entries. |
28 | 2 | cFiles | Number of CFFILE entries. |
30 | 2 | flags | See header flags. |
32 | 2 | setID | A number chosen at random, the same in every cabinet of a set. |
34 | 2 | iCabinet | This cabinet’s number in the set, from 0. |
36 | 2 | cbCFHeader | Only with cfhdrRESERVE_PRESENT: size of abReserve below, 0 to 60,000. |
38 | 1 | cbCFFolder | Same condition: size of the reserved area in each CFFOLDER, 0 to 255. |
39 | 1 | cbCFData | Same condition: size of the reserved area in each CFDATA, 0 to 255. |
| … | cbCFHeader | abReserve | Same condition: data for the application. Authenticode signatures of cabinets are found through here. |
| … | ≤ 256 | szCabinetPrev | Only with cfhdrPREV_CABINET: file name of the previous cabinet, NUL-terminated. |
| … | ≤ 256 | szDiskPrev | Same condition: name of the disk holding it, for prompting the user. |
| … | ≤ 256 | szCabinetNext | Only with cfhdrNEXT_CABINET: file name of the next cabinet. |
| … | ≤ 256 | szDiskNext | Same condition: name of its disk. |
Without reserved areas or neighbours the header is 36 bytes. (The Cabinet SDK text
says once that cbCFData is absent when the reserve flag is set; that is a
slip, as the flag’s own definition and every reader include it.)
Header flags
| Value | Name | Meaning |
|---|---|---|
0001 | cfhdrPREV_CABINET | Not the first cabinet of a set: the previous cabinet and disk names are present. |
0002 | cfhdrNEXT_CABINET | Not the last cabinet of a set: the next cabinet and disk names are present. |
0004 | cfhdrRESERVE_PRESENT | The three reserve sizes and the header’s reserved area are present. |
All other bits are reserved.
CFFOLDER
A folder is a run of files compressed together as one stream.
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | coffCabStart | Offset of the folder’s first CFDATA block, from the start of the file. |
4 | 2 | cCFData | Number of CFDATA blocks of this folder in this cabinet. |
6 | 2 | typeCompress | Compression of every block in the folder. See compression types. |
8 | cbCFFolder | abReserve | Reserved area, when present. |
Compression types
The low four bits are the method; the higher bits carry its parameter. The names
and masks are those of the Cabinet SDK’s fdi.h; the cabinet document
itself leaves the values to each method’s specification.
| Value or mask | Name | Meaning |
|---|---|---|
000F | tcompMASK_TYPE | Mask for the method. |
0000 | tcompTYPE_NONE | Stored: each block’s data is the bytes themselves. |
0001 | tcompTYPE_MSZIP | MSZIP: Deflate. |
0002 | tcompTYPE_QUANTUM | Quantum, David Stafford’s arithmetic-coded LZ method. |
0003 | tcompTYPE_LZX | LZX, LZ77 with Huffman coding. |
000F | tcompBAD | Not a valid method; used inside the SDK for errors. |
00F0 | tcompMASK_QUANTUM_LEVEL | Quantum compression level, 1 to 7 (0010 to 0070), shift 4. |
1F00 | tcompMASK_QUANTUM_MEM | Quantum window, 10 to 21 (0A00 to 1500), shift 8: the window is 2n bytes. |
1F00 | tcompMASK_LZX_WINDOW | LZX window, 15 to 21 (0F00 to 1500), shift 8: the window is 2n bytes, 32 KiB to 2 MiB. |
So 1503 is LZX with a 2 MiB window, and 0001 MSZIP. The LZX
window decides the number of position slots: 30, 32, 34, 36, 38, 40 and 42 for
windows of 32 KiB to 2 MiB.
CFFILE
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | cbFile | Uncompressed size of the file. |
4 | 4 | uoffFolderStart | Where the file starts in its folder’s uncompressed data. |
8 | 2 | iFolder | Index of the folder, from 0, or a continuation code. |
10 | 2 | date | ((year − 1980) << 9) + (month << 5) + day. |
12 | 2 | time | (hour << 11) + (minute << 5) + seconds ÷ 2. |
14 | 2 | attribs | See attributes. |
16 | … | szName | The file name and path, NUL-terminated. Folders are separated by \. |
Folder index codes
| Value | Name | Meaning |
|---|---|---|
FFFD | ifoldCONTINUED_FROM_PREV | The file starts in the previous cabinet; its data is in folder 0 of this one. |
FFFE | ifoldCONTINUED_TO_NEXT | The file continues into the next cabinet; it is in the last folder here. |
FFFF | ifoldCONTINUED_PREV_AND_NEXT | The file comes from the previous cabinet and goes on into the next; this cabinet’s single folder holds its middle. |
Attributes
| Value | Name | Meaning |
|---|---|---|
01 | _A_RDONLY | Read-only. |
02 | _A_HIDDEN | Hidden. |
04 | _A_SYSTEM | System file. |
20 | _A_ARCH | Changed since the last backup. |
40 | _A_EXEC | Run the file after extracting it. |
80 | _A_NAME_IS_UTF | szName is UTF-8; otherwise it is in the system’s code page. |
All other bits are reserved.
CFDATA
| Offset | Size | Name | Description |
|---|---|---|---|
0 | 4 | csum | Checksum of the block, or 0 for none. |
4 | 2 | cbData | Bytes of compressed data in this block. |
6 | 2 | cbUncomp | Uncompressed size of the block, at most 32,768; only the folder’s last block may be smaller. 0 when the block is split and continues in the next cabinet. |
8 | cbCFData | abReserve | Reserved area, when present. |
| … | cbData | ab | The compressed data. LZX blocks may be up to 32,768 + 6,144 bytes. |
Checksum
The checksum XORs 32-bit words together. Start from a seed; take the data four bytes at a time as little-endian words and XOR each into the sum; put the last one to three bytes into a zero word, low byte first, and XOR that in.
- Sum the
abbytes with seed 0. - Sum the block header from
cbDatato the end ofabReserve, with the first result as the seed. The result iscsum.
A block split across two cabinets has a checksum in each part: the first part has
cbUncomp = 0, the second has the full uncompressed size, and each covers
its own bytes and header. Microsoft’s extractors do not check the sum.
MSZIP blocks
In an MSZIP folder each block’s data is the two bytes 43 4B
(CK) followed by Deflate data (RFC 1951) that produces exactly
cbUncomp bytes. The Deflate history carries on from one block to the next
in the same folder, so the blocks must be decoded in order. This comes from
Microsoft’s separate “MSZIP Data Compression Format” document.
Spanning several cabinets
When a folder does not fit, its data goes on in the next cabinet: the last block may
be split there, the next cabinet starts with a folder that continues it, and the
files involved use the continuation codes. Every cabinet of the
set shares setID and numbers itself with iCabinet.