You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
neptools/doc/formats/gbin.md

112 lines
3.4 KiB
Markdown

GBIN and GSTR
=============
GBIN (stored inside `.gbin` files in SYSTEM/database, and inside `.cl3`s) and
GSTR (stored in `.gstr` files in SYSTEM/database) are quite similar. All
integers are little-endian.
The sections described below (Header/Footer, Type descriptor, Struct and String
table) are aligned to 16 bytes in GBIN, but unaligned in GSTR...
Header/Footer
-------------
```c++
struct HeaderFooter
{
char magic[3];
char endian;
uint16_t field_04; // always 1
uint16_t field_06; // always 0
uint32_t field_08; // always 16
uint32_t field_0c; // always 4
uint32_t flags;
uint32_t struct_offset;
uint32_t struct_count;
uint32_t struct_size;
uint32_t types_count;
uint32_t types_offset;
uint32_t field_28; // ??
uint32_t string_offset;
uint32_t field_30; // 0 or 4
uint32_t padding[3]; // always 0
};
sizeof(HeaderFooter) == 0x40
```
In GSTR the above struct is a header, at the beginning of the file, magic string
is `GST`. In GBIN it's a footer (so it starts at `EOF-sizeof(HeaderFooter)`),
and the magic is `GBN`... Endian is denoted by `endian`, if `L` means
little-endian and `B` means big-endian.
`flags` is 1 if there's any string stored in the file (see Type descriptor
below), 0 otherwise. `struct_offset` is 0 in GBIN and 0x40 in GSTR files (but
other values should work too). Offsets are relative to the beginning of the
file.
Type descriptor
---------------
This file contains a list of some structure. However the structure is actually
defined inside the file, so you can figure out the types of each fields.
```c++
struct TypeDescriptor
{
uint16_t type;
uint16_t offset;
};
sizeof(TypeDescriptor) == 4;
```
They start at `header.types_offset`, and there's `header.types_count` of them.
They're sorted into ascending order by `offset`. Each entry describes a field
inside the struct, `offset` is an offset from the beginning of the struct. The
valid values for `type` are:
```c++
enum Type
{
UINT32 = 0,
UINT8 = 1,
UINT16 = 2,
FLOAT = 3,
STRING = 5,
};
```
`UINT16`, and `UINT32` are standard 16 bit and 32 bit integers (not sure if
they're signed or unsigned though, probably the format makes no difference
between them), `FLOAT` is a standard 32 bit float (as used by x86 CPUs).
`UINT8` is a bit special: it's normally a single byte, but can also mean a fixed
length zero terminated string. They both end up as `type=1`. This editor
currently uses a heuristic: if the offset of the next entry is this entry's
offset + 1 (taking aligning into account), it's probably a single byte,
otherwise a fixed length string.
`STRING` is a 32 bit integer, an offset into the string table. Sometimes it'll
be -1 (0xffffffff), that's an invalid string (maybe NULL pointer originally?).
The fields are aligned: `UINT32`, `FLOAT` and `STRING` are aligned to 4 bytes
and `UINT16` to 2 bytes.
Struct
------
The structs start at `header.struct_offset` and there are `header.struct_count`
of them. Every struct is `header.struct_size` bytes length, the fields are
described by the type descriptor.
String table
------------
This is optional, it only exists if `header.flags == 1`. It starts at
`header.string_offset`. Each contains a bunch of zero terminated strings
sequentially, and referenced inside `STRING` type fields.
There's an optimization in the original files: if the same string appears
multiple times, it's only stored once in the table, the identical `STRING`
fields will get the same offset.