Datasheet: Difference between revisions
imported>Leoetlino (main field -> root field / mention pointer relocation) |
imported>Leoetlino (→Header) |
||
(9 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
'''GSHT''' (G?sheet) is a custom Grezzo binary serialization file format that is used to store structured, strongly typed data. GSHT documents are called '''datasheets'''. | '''GSHT''' (G?sheet) is a custom Grezzo binary serialization file format that is used to store structured, strongly typed data. GSHT documents are called '''datasheets'''. | ||
A datasheet contains structure type information followed by arrays of structures. Optionally, one of the structure fields may be declared as a key field, in which case the contents are a dictionary rather than a array. | A datasheet contains structure type information followed by arrays of structures. Optionally, one of the structure fields may be declared as a key field, in which case the contents are treated as a dictionary/mapping rather than a array. | ||
== Format == | == Format == | ||
Documents are little endian and their sizes are always 0x10 | Documents are little endian and their sizes are always rounded up to be a multiple of 0x10. | ||
Pointers are encoded as absolute offsets and relocated when the document is loaded by the game. | Pointers are encoded as absolute offsets and relocated when the document is loaded by the game. | ||
Line 17: | Line 17: | ||
|0x0 | |0x0 | ||
|char[4] | |char[4] | ||
|Magic (<code> | |Magic (<code>gsht</code>) | ||
After pointer relocation, the magic is set to <code>GSHT</code>. | |||
|- | |- | ||
|0x4 | |0x4 | ||
|int | |int | ||
|Version (must be 1) | |Version (must be 1) | ||
|- | |||
|0x8 | |||
|u32 | |||
|? Some kind of hash? (unused {{check}}) | |||
|- | |- | ||
|0xC | |0xC | ||
Line 33: | Line 39: | ||
|0xE | |0xE | ||
|u8 | |u8 | ||
| | |Alignment (usually 4 or 8) | ||
|- | |- | ||
|0x10 | |0x10 | ||
|const char* | |const char* | ||
|Name | |Name (must be non-null) | ||
|- | |- | ||
|0x18 | |0x18 | ||
Line 57: | Line 63: | ||
|0x2C | |0x2C | ||
|u32 | |u32 | ||
| | |Size of each value | ||
|} | |} | ||
The header is immediately followed by the root fields (a <code>Field[num_root_fields]</code> array). | |||
=== Field === | === Field === | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
enum class Type : | enum class Type : u8 { | ||
Struct = 0, | Struct = 0, | ||
Bool = 1, | Bool = 1, | ||
Line 74: | Line 82: | ||
IsArray = 1 << 1, | IsArray = 1 << 1, | ||
IsKey = 1 << 2, | IsKey = 1 << 2, | ||
b3 = 1 << 3, | b3 = 1 << 3, // unknown | ||
IsEnum = 1 << 4, | IsEnum = 1 << 4, | ||
b5 = 1 << 5, | b5 = 1 << 5, // unknown | ||
}; | }; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 90: | Line 98: | ||
|0x8 | |0x8 | ||
|const char* | |const char* | ||
|Type name | |Type name (must be non-null) | ||
|- | |- | ||
|0x10 | |0x10 | ||
Line 106: | Line 114: | ||
|0x14 | |0x14 | ||
|u16 | |u16 | ||
| | |Offset of this field in the value structure | ||
|- | |- | ||
|0x16 | |0x16 | ||
|u16 | |u16 | ||
| | |Size of this field in the value structure | ||
For strings and arrays, this is always 0x10. | |||
|- | |- | ||
|0x18 | |0x18 | ||
|u16 | |u16 | ||
| | |Size of the data | ||
For strings and inline types (inline structs, ints, floats, bools), this is the same as the size in the value structure. | |||
|- | |- | ||
|0x1A | |0x1A | ||
|u16 | |u16 | ||
| | |[For structs] Number of fields | ||
|- | |- | ||
|0x20 | |0x20 | ||
|Field* | |Field* | ||
| | |[For structs] Fields | ||
|- | |- | ||
|0x28 | |0x28 | ||
Line 135: | Line 147: | ||
=== Value === | === Value === | ||
Combining all the root fields gives a structure (in the sense of a C or C++ structure). That structure is called a Value in this documentation. | |||
{| class="wikitable" | {| class="wikitable" | ||
|+Field data serialization | |+Field data serialization | ||
Line 160: | Line 174: | ||
|String | |String | ||
|<code>struct { const char* data; u32 length; }</code> (aligned to 0x10 bytes) | |<code>struct { const char* data; u32 length; }</code> (aligned to 0x10 bytes) | ||
For empty strings ''that are Nullable'', data is nullptr and length is 0. Empty strings that are ''not'' Nullable have a 0 length but still point to a null byte. | |||
|} | |} | ||
== Usage in ''Link's Awakening'' == | == Usage in ''Link's Awakening'' == |
Latest revision as of 18:53, 13 April 2020
File format | |
---|---|
Magic | gsht |
Endianness | little |
Version | 1 |
This article is about the file format in general. For actual values, check the game RomFS. |
GSHT (G?sheet) is a custom Grezzo binary serialization file format that is used to store structured, strongly typed data. GSHT documents are called datasheets.
A datasheet contains structure type information followed by arrays of structures. Optionally, one of the structure fields may be declared as a key field, in which case the contents are treated as a dictionary/mapping rather than a array.
Format
Documents are little endian and their sizes are always rounded up to be a multiple of 0x10.
Pointers are encoded as absolute offsets and relocated when the document is loaded by the game.
Header
Offset | Type | Description |
---|---|---|
0x0 | char[4] | Magic (gsht )
After pointer relocation, the magic is set to |
0x4 | int | Version (must be 1) |
0x8 | u32 | ? Some kind of hash? (unused [check]) |
0xC | u8 | Bool type size (must be 1) |
0xD | u8 | Pointer size (must be 8) |
0xE | u8 | Alignment (usually 4 or 8) |
0x10 | const char* | Name (must be non-null) |
0x18 | u32 | Number of root fields |
0x1C | u32 | Number of fields in total |
0x20 | Value* | Values |
0x28 | u32 | Number of values |
0x2C | u32 | Size of each value |
The header is immediately followed by the root fields (a Field[num_root_fields]
array).
Field
enum class Type : u8 {
Struct = 0,
Bool = 1,
Int = 2,
Float = 3,
String = 4,
};
enum class Flag : u16 {
IsNullable = 1 << 0,
IsArray = 1 << 1,
IsKey = 1 << 2,
b3 = 1 << 3, // unknown
IsEnum = 1 << 4,
b5 = 1 << 5, // unknown
};
Offset | Type | Description |
---|---|---|
0x0 | const char* | Name (must be non-null) |
0x8 | const char* | Type name (must be non-null) |
0x10 | Field::Type | Type |
0x11 | u8 | ?[check] |
0x12 | Field::Flag | Flags |
0x14 | u16 | Offset of this field in the value structure |
0x16 | u16 | Size of this field in the value structure
For strings and arrays, this is always 0x10. |
0x18 | u16 | Size of the data
For strings and inline types (inline structs, ints, floats, bools), this is the same as the size in the value structure. |
0x1A | u16 | [For structs] Number of fields |
0x20 | Field* | [For structs] Fields |
0x28 | Field* | Parent (filled in during parsing; always 0xdeadbeefdeadbeef when serialized) |
Fields must be properly aligned to 0x30 byte boundaries.
Key fields cannot be arrays or Nullable types.
Key fields must be of type String or Int.
Value
Combining all the root fields gives a structure (in the sense of a C or C++ structure). That structure is called a Value in this documentation.
Type | Serialized data format |
---|---|
Nullable<T> (non-strings) | struct { T* data; } (nullptr if no value)
|
Array<T> | struct { T* data; u32 size; } (aligned to 0x10 bytes[check])
|
Struct | struct { Fields...; }
|
Bool | bool (1-byte) |
Int | s32 |
Float | f32 |
String | struct { const char* data; u32 length; } (aligned to 0x10 bytes)
For empty strings that are Nullable, data is nullptr and length is 0. Empty strings that are not Nullable have a 0 length but still point to a null byte. |
Usage in Link's Awakening
Datasheets are extensively used to configure game logic and to store miscellaneous data. They are located in rom:/region_common/datasheets and their file extension is .gsheet.
Text versions of datasheets are available in the leoetlino/la-re-notes repository on GitHub.