* u8 = unsigned 8-bit integer * u16 = unsigned 16-bit integer * u32 = unsigned 32-bit integer struct STableHeader { u8 type; // Offset 0, Length 1 u8 last_update[3]; // Offset 1, Length 3 u32 records; // Offset 4, Length 4 u16 first_record; // Offset 8, Length 2 u16 record_length; // Offset 10, Length 2 u8 rsvrd1[16]; // Offset 12, Length 16 u8 flags; // Offset 28, Length 1 u8 code_page; // Offset 29, Length 1 u8 rsvrd2[2]; // Offset 30, Length 2 // Total: 32 bytes };It's followed by a repeating structure of field records for the number of fields. This is also why the field names of a free table can only be 10 characters long:
struct SFieldRecord { u8 name[11]; // Offset 0, Length 11 u8 type; // offset 11, Length 1 u32 offset; // Offset 12, Length 4 u8 length; // Offset 16, Length 1 u8 decimals; // Offset 17, Length 1 u8 flags; // Offset 18, Length 1 u32 autoIncNext; // Offset 19, Length 4 u8 autoIncStep; // Offset 23, Length 1 u8 rsrvd1; // Offset 24, Length 1 u8 rsvrd2; // Offset 25, Length 1 u8 rsvrd3; // Ofsfet 26, Length 1 u8 rsvrd4; // Offset 27, Length 1 u32 rsvrd5; // Offset 28, Length 4 // Total: 32 bytes };And then the data proceeds in the file beginning at first_record offset. The offset of each field is within each record size. It repeats as a very straight-forward data structure throughout.