Every .x file, text or binary, starts with the same 16 bytes of ASCII. They name the format, its version, how the rest of the file is encoded, and how wide its floating-point numbers are. Microsoft’s documentation calls this header compulsory.
The 16-byte header
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 0 | 4 | char[4] | Magic | xof , the letters x, o, f and a space: 78 6F 66 20 |
| 4 | 2 | char[2] | Major version | 03 |
| 6 | 2 | char[2] | Minor version | 02 or 03 |
| 8 | 4 | char[4] | Format type | How the rest of the file is encoded; see below |
| 12 | 4 | char[4] | Float size | 0032 for 32-bit floats or 0064 for 64-bit floats |
The version is two two-digit numbers written together, so 0302 is
version 3.2 and 0303 version 3.3. These are the two versions in use, and
readers such as Wine’s accept no others. In a text file the header is usually followed
by a line break; in a binary file the first token follows directly.
Format type
| Code | Bytes | Meaning |
|---|---|---|
txt | 74 78 74 20 | Text, described in Text encoding |
bin | 62 69 6E 20 | Binary tokens, described in Binary encoding |
tzip | 74 7A 69 70 | Text, compressed with MSZIP |
bzip | 62 7A 69 70 | Binary, compressed with MSZIP |
cmp | 63 6D 70 20 | Compressed, defined in Microsoft’s header constants but not described, and not met in practice |
Float size
The float size says how wide a FLOAT is in this file. It matters in the
binary encoding, where each value of a float list takes 4 bytes with 0032
and 8 bytes with 0064. Most files use 0032. In the text
encoding the numbers are written out as decimals either way.
Compressed files: tzip and bzip
Microsoft’s header page says compressed streams “are not currently supported and are therefore not detailed”, but D3DX reads and writes them. Their layout is known from the readers in Wine and Assimp. After the usual 16-byte header come:
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| 16 | 4 | uint32 | Uncompressed size | Size of the whole file once decompressed, including the 16-byte header |
| 20 | … | chunks | Chunks | One after another to the end of the file |
Each chunk is:
| Offset | Size | Type | Name | Description |
|---|---|---|---|---|
| +0 | 2 | uint16 | Uncompressed chunk size | Bytes this chunk produces, at most 32,768 |
| +2 | 2 | uint16 | Compressed chunk size | Bytes of MSZIP data that follow |
| +4 | 2 | char[2] | Signature | CK (43 4B), which starts every MSZIP block |
| +6 | … | bytes | Deflate data | A raw deflate stream, as in RFC 1951 |
All sizes are little-endian. MSZIP is the deflate variant used in Microsoft cabinet
files, in blocks of at most 32 KB that each start with CK. The
decompressed chunks, joined, are the body of a
txt or bin file without its header. Whether the
compressed size counts the two signature bytes is not stated anywhere official; the
two open readers treat the chunk headers slightly differently, so this layout should
be taken as reverse-engineered.
The Header template
Separate from the 16-byte file header, the format defines a special template called
Header, which an application may use for its own version information.
Direct3D Retained Mode, the first user of the format, defined it as:
template Header {
<3D82AB43-62DA-11cf-AB39-0020AF71E433>
WORD major;
WORD minor;
DWORD flags;
}
If a header object has a flags member, the file-format library reads it.
Only bit 0 is defined: when it is clear, the data that follows is binary, and when it
is set, the data that follows is text. Several header objects may switch a file
between binary and text. Header is not in the DirectX 9 list of
templates.
Versions
The format was introduced with Direct3D Retained Mode, and the binary encoding was added in DirectX 3.0. Microsoft does not document what changed between versions 3.2 and 3.3 of the header; readers treat them alike. The library that reads and writes the format in DirectX 9 is D3DX9, which Microsoft has since deprecated.