BYAML (File Format)
BYAML is a generic file format used on Wii U and the Nintendo Switch in games like Mario Kart 8 and Mario Kart 8 Deluxe. BYML is basically the same, and is used in games like Super Mario 3D World and Super Mario Odyssey.
File Format
Header
The file starts with a 0x10 or 0x14 bytes long header. An offset can be 0 meaning it points to nothing.
Offset | Type | Description |
---|---|---|
0x00 | Char[2] | File magic. BY for big endian files, and YB for little endian files. |
0x02 | UInt16 | File format version. |
0x04 | UInt32 | Node name string table node offset. |
0x08 | UInt32 | String value string table node offset.. |
0x0C | UInt32 | Serialized data table node offset. Usually doesn't exist for BYML files. |
0x10 | UInt32 | Root node. Must be an array node or dictionary node. |
Nodes
The file consists of multiple nodes, stored in a hierarchy. There are two special-purpose nodes, string table node and serialized data table node, which can only be linked by the header and cannot be stored in the hierarchy of nodes. Only two nodes allow storing children, dictionary node and array node. Each child element consists of a 32-bit integer. If the child node is four bytes long, then the 32-bit integer represents the value of the child node. If the child node is larger than four bytes, then the 32-bit integer represents an absolute offset to the data of the node. For Int32 and Float, the data is stored directly since those are exactly four bytes long, but array node and Int64 are examples where an offset is stored.
The following table shows all available node types:
ID | Name | Available since version |
---|---|---|
0xA0 | String reference | 1 |
0xA1 | Serialized data reference | 1 |
0xC0 | Array | 1 |
0xC1 | Dictionary | 1 |
0xC2 | String table | 1 |
0xC3 | Serialized data table | 1 |
0xD0 | Boolean | 1 |
0xD1 | Int32 | 1 |
0xD2 | Float | 1 |
0xD3 | UInt32 | 2 |
0xD4 | Int64 | 2 or 3 |
0xD5 | UInt64 | 2 or 3 |
0xD6 | Double | 2 |
0xFF | Null | 2 or 3 |
Array Node
An array node consists a collection of child nodes, all of arbitrary types. An array node has the following structure:
Offset | Type | Description |
---|---|---|
0x00 | Byte | Node type. Must be 0xC0. |
0x01 | UInt24 | Number of child elements. |
0x04 | Byte[N] | Child node types. Each byte represents a node type. |
Align by 4. |
The child elements comes after the structure, altough at an offset aligned by four. If the size of the child node is four bytes, then the direct value is stored. Otherwise a 32-bit offset is stored, which points to the child data. See nodes.
Dictionary Node
A dictionary node consists of a named child nodes. Like an array node, it stores a collection of child nodes, although in a dictionary node all child nodes are named. A dictionary node has the following structure:
Offset | Type | Description |
---|---|---|
0x00 | Byte | Node type. Must be 0xC1. |
0x01 | UInt24 | Number of child elements. |
After that, each dictionary entry is stored, each of which describes a child node. It has the following structure:
Offset | Type | Description |
---|---|---|
0x00 | UInt24 | Name index. Index of string into the node name string table node linked in the header which represents the name of this node. |
0x03 | Byte | Child node type. See nodes. |
0x04 | UInt32 | Child element. If the size of the child node is four bytes, then the direct value is stored. Otherwise a 32-bit offset is stored, which points to the child data. See nodes. |
- Dictionary look-up
When looking up a string in a dictionary node, binary search is done twice. First, binary search is used to find the index of the name into the node name string table node. If the name doesn't exist, then there is no node in the dictionary with that name. However, if it does exist, binary search is used again to find if there is a node with a name index matching the index which was looked up earlier. In order for this to work, the dictionary entries must be sorted on name index.
String Table Node
A string table node stores strings and is accessed by an index in a dictionary node or string node. The node can only be linked in the header. All strings are null-terminated, and must be sorted on true UTF-8 order in order to allow binary search. The node starts with the following structure:
Offset | Type | Description |
---|---|---|
0x00 | Byte | Node type. Must be 0xC2. |
0x01 | UInt24 | Number of strings. |
0x04 | UInt32[N + 1] | String offsets. The last offset points to the end of the last string. The offsets are relative to the start of this node structure. |
Serialized Data Table Node
The serialized data table node stores a collection of generic data. What the data contains is game-specific. Serialized data is accessed by a serialized data node. The node starts with the following structure:
Offset | Type | Description |
---|---|---|
0x00 | Byte | Node type. Must be 0xC3. |
0x01 | UInt24 | Number of serialized data elements. |
0x04 | UInt32[N + 1] | Serialized data offsets. The last offset points to the end of the last entry. The offsets are relative to the start of this node structure. The size of each entry is known by looking at the next data offset. |
Value Nodes
The following table shows all nodes which cannot contain children and are not special-purpose.
ID | Name | Size | Descrption |
---|---|---|---|
0xA0 | String reference | 4 | 32-bit integer which represents an index into the string value string table linked in the header. |
0xA1 | Serialized data reference | 4 | 32-bit integer which represents an index into the serialized data table node linked in the header. |
0xD0 | Boolean | 4 | 32-bit integer boolean, where 1 represents true and 0 represents false. |
0xD1 | Int32 | 4 | 32-bit signed integer. |
0xD2 | Float | 4 | 32-bit floating-point. |
0xD3 | UInt32 | 4 | 32-bit unsigned integer. |
0xD4 | Int64 | 8 | 64-bit signed integer. |
0xD5 | UInt64 | 8 | 64-bit unsigned integer. |
0xD6 | Double | 8 | 64-bit floating-point. |
0xFF | Null | 4 | Null. Generally this is used to specify a null value for a string. A 32-bit zero value is stored as a dummy value. |
Tools
The following tools can handle BYAML/BYML files:
- (none)