Untelo/Sandbox – User

From Bohemia Interactive Community
Jump to navigation Jump to search
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[[Category:Sandbox]]
[[Category:Sandbox]]
== Introduction ==
The ALB1 format is a generic object graph serialization format used by at least Visitor 4 (Terrain Builder).
The ALB1 format is a generic object graph serialization format used by at least Visitor 4 (Terrain Builder).


Line 10: Line 7:
The file begins with a header describing its version, as well as some other so far unknown attributes.
The file begins with a header describing its version, as well as some other so far unknown attributes.


  struct Header
<syntaxhighlight lang="cpp">
  {
struct Header
    uint8_t magic[4]; // "ALB1"
{
    uint32_t version;
uint8_t magic[4]; // "ALB1"
    uint32_t unknown1;
uint32_t version;
    uint32_t unknown2;
uint32_t unknown1;
  };
uint32_t unknown2;
};
</syntaxhighlight>


The header is followed by two tables containing the names of classes and fields.
The header is followed by two tables containing the names of classes and fields.


  struct TagTables
<syntaxhighlight lang="cpp">
  {
struct TagTables
    TagTable fieldTable; // The id of the table is always 2, corresponding to "tags" in the field table.
{
    TagTable classTable; // The id of the table is always 3, corresponding to "classes" in the field table.
TagTable fieldTable; // The id of the table is always 2, corresponding to "tags" in the field table.
  };
TagTable classTable; // The id of the table is always 3, corresponding to "classes" in the field table.
};
</syntaxhighlight>


The tag table contains a header similar to a field, but its type of pair does not match the usual meaning.
The tag table contains a header similar to a field, but its type of pair does not match the usual meaning.


  struct TagTable
<syntaxhighlight lang="cpp">
  {
struct TagTable
    uint16_t id;
{
    FieldType type; // The type is always pair (0x0F).
uint16_t id;
 
FieldType type; // The type is always pair (0x0F).
    uint32_t size;
 
    TagTableEntry data[size];
uint32_t size;
  };
TagTableEntry data[size];
};
</syntaxhighlight>


Each tag table entry contains an identifier and a string specifying the name of the tag. Note that the tag identifier does not correlate with the index of the entry in the table.
Each tag table entry contains an identifier and a string specifying the name of the tag. Note that the tag identifier does not correlate with the index of the entry in the table.


  struct TagTableEntry
<syntaxhighlight lang="cpp">
  {
struct TagTableEntry
    uint16_t id;
{
    Field_string name;
uint16_t id;
  };
Field_string name;
};
</syntaxhighlight>


=== Root object ===
=== Root object ===


Following the header, there is a single root object filling the rest of the file. However the root object is not a field, and so it does not contain the usual field header.
Following the header and tag tables, there is a single root object filling the rest of the file. However the root object is not a field, and so it does not contain the usual field header.


Thus the entire file can be described using the following structure:
Thus the entire file can be described using the following structure:


  struct ALB1
<syntaxhighlight lang="cpp">
  {
struct ALB1
    Header header;
{
    TagTables tables;
Header header;
    Field_object object;
TagTables tables;
  };
Field_object object;
};
</syntaxhighlight>


=== Field ===
=== Field ===
Line 62: Line 69:
The format uses fields prefixed with name and type. The name is given as an identifier corresponding to an entry in the tag table. The type is one of the value from the FieldType enumeration.
The format uses fields prefixed with name and type. The name is given as an identifier corresponding to an entry in the tag table. The type is one of the value from the FieldType enumeration.


  enum FieldType : uint8_t
<syntaxhighlight lang="cpp">
  {
enum FieldType : uint8_t
    signed_char         = 0x01, // 8 bit signed
{
    unsigned_char       = 0x02, // 8 bit unsigned
signed_char = 0x01, // 8 bit signed
    signed_short       = 0x03, // 16 bit signed
unsigned_char = 0x02, // 8 bit unsigned
    unsigned_short     = 0x04, // 16 bit unsigned
signed_short = 0x03, // 16 bit signed
    signed_int         = 0x05, // 32 bit signed
unsigned_short = 0x04, // 16 bit unsigned
    unsigned_int       = 0x06, // 32 bit unsigned
signed_int = 0x05, // 32 bit signed
    signed_long         = 0x07, // 32 bit signed
unsigned_int = 0x06, // 32 bit unsigned
    unsigned_long       = 0x08, // 32 bit unsigned
signed_long = 0x07, // 32 bit signed
    bool               = 0x09,
unsigned_long = 0x08, // 32 bit unsigned
    float               = 0x0A,
bool = 0x09,
    string             = 0x0B,
float = 0x0A,
    array               = 0x0C,
string = 0x0B,
    object             = 0x0D,
array = 0x0C,
    object_pointer     = 0x0E,
object = 0x0D,
    pair               = 0x0F,
object_pointer = 0x0E,
    array_signed_short = 0x10,
pair = 0x0F,
    array_signed_int   = 0x11,
array_signed_short = 0x10,
    array_float         = 0x12,
array_signed_int = 0x11,
    empty               = 0x13,
array_float = 0x12,
    double             = 0x14,
empty = 0x13,
    array_double       = 0x15,
double = 0x14,
  };
array_double = 0x15,
};
</syntaxhighlight>


  struct Field
<syntaxhighlight lang="cpp">
  {
struct Field
    uint16 tag; // Corresponds to an entry in the tag table.
{
    FieldType type;
uint16 tag; // Corresponds to an entry in the tag table.
    byte data[]; // Followed by polymorphic data blob which content is determined by the type field.
FieldType type;
  };
byte data[]; // Followed by polymorphic data blob which content is determined by the type field.
};
</syntaxhighlight>


=== Fundamental types ===
=== Fundamental types ===
Line 105: Line 116:


The string data type is a length-prefixed non-null-terminated string, using a 16 bit length prefix:
The string data type is a length-prefixed non-null-terminated string, using a 16 bit length prefix:
  struct Field_string
<syntaxhighlight lang="cpp">
  {
struct Field_string
    uint16_t size;
{
    char data[size];
uint16_t size;
  };
char data[size];
};
</syntaxhighlight>


=== Size prefixed data blobs ===
=== Size prefixed data blobs ===
Line 115: Line 128:
Fields with the array or object data types are both length-prefixed using a 32 bit length describing the size of the data blob, excluding the prefix.
Fields with the array or object data types are both length-prefixed using a 32 bit length describing the size of the data blob, excluding the prefix.


  struct DataBlob
<syntaxhighlight lang="cpp">
  {
struct DataBlob
    uint32_t size;
{
    byte blob[size];
uint32_t size;
  };
byte blob[size];
};
</syntaxhighlight>


=== Array ===
=== Array ===


The generic array data type contains an array of fields, their number given by a second size prefix.
The generic array data type contains an array of fields, their number given by a second size prefix.
  struct Field_array
<syntaxhighlight lang="cpp">
  {
struct Field_array
    uint32_t size;
{
    Field data[size];
uint32_t size;
  };
Field data[size];
};
</syntaxhighlight>


=== Object and object pointer ===
=== Object and object pointer ===
Line 134: Line 151:
Both the object and object pointer data types share a common header. The header contains a class type identifier corresponding to an entry in the class table, and an address field uniquely identifying the object in the entire graph. The unique identifier is presumably the 32 bit runtime address of the object at the time of serialization. It is used for linking pointers in the object graph during deserialization.
Both the object and object pointer data types share a common header. The header contains a class type identifier corresponding to an entry in the class table, and an address field uniquely identifying the object in the entire graph. The unique identifier is presumably the 32 bit runtime address of the object at the time of serialization. It is used for linking pointers in the object graph during deserialization.


  struct ObjectHeader
<syntaxhighlight lang="cpp">
  {
struct ObjectHeader
    int16_t class; // Corresponds to an entry in the class table.
{
    uint32_t address;
int16_t class; // Corresponds to an entry in the class table.
  };
uint32_t address;
};
</syntaxhighlight>


The object data type contains a number of fields. The number of fields is not given, but the size of the data blob is used to determine the end of the object. Note that object fields contain the blob size prefix mentioned previously.
The object data type contains a number of fields. The number of fields is not given, but the size of the data blob is used to determine the end of the object. Note that object fields contain the blob size prefix mentioned previously.


  struct Field_object
<syntaxhighlight lang="cpp">
  {
struct Field_object
    ObjectHeader header;
{
    Field fields[]; // Arbitrary number of fields.
ObjectHeader header;
  };
Field fields[]; // Arbitrary number of fields.
};
</syntaxhighlight>


The object pointer data type is a stripped down version of the header of the object data type. However it only contains the type and address of the object, with the address corresponding to an object somewhere in the graph.
The object pointer data type is a stripped down version of the header of the object data type. However it only contains the type and address of the object, with the address corresponding to an object somewhere in the graph.


  struct Field_object_pointer
<syntaxhighlight lang="cpp">
  {
struct Field_object_pointer
    ObjectHeader header; // header.address corresponds to the header.address of some object in the graph.
{
  };
ObjectHeader header; // header.address corresponds to the header.address of some object in the graph.
};
</syntaxhighlight>


=== Pair ===
=== Pair ===
Line 159: Line 182:
The pair data type simply holds two fields. It is primarily used by associative containers.
The pair data type simply holds two fields. It is primarily used by associative containers.


  struct Field_pair
<syntaxhighlight lang="cpp">
  {
struct Field_pair
    Field first;
{
    Field second;
Field first;
  };
Field second;
};
</syntaxhighlight>

Latest revision as of 15:04, 28 April 2021

The ALB1 format is a generic object graph serialization format used by at least Visitor 4 (Terrain Builder).

Structure

Header

The file begins with a header describing its version, as well as some other so far unknown attributes.

struct Header
{
	uint8_t magic[4]; // "ALB1"
	uint32_t version;
	uint32_t unknown1;
	uint32_t unknown2;
};

The header is followed by two tables containing the names of classes and fields.

struct TagTables
{
	TagTable fieldTable; // The id of the table is always 2, corresponding to "tags" in the field table.
	TagTable classTable; // The id of the table is always 3, corresponding to "classes" in the field table.
};

The tag table contains a header similar to a field, but its type of pair does not match the usual meaning.

struct TagTable
{
	uint16_t id;
	FieldType type; // The type is always pair (0x0F).

	uint32_t size;
	TagTableEntry data[size];
};

Each tag table entry contains an identifier and a string specifying the name of the tag. Note that the tag identifier does not correlate with the index of the entry in the table.

struct TagTableEntry
{
	uint16_t id;
	Field_string name;
};

Root object

Following the header and tag tables, there is a single root object filling the rest of the file. However the root object is not a field, and so it does not contain the usual field header.

Thus the entire file can be described using the following structure:

struct ALB1
{
	Header header;
	TagTables tables;
	Field_object object;
};

Field

The format uses fields prefixed with name and type. The name is given as an identifier corresponding to an entry in the tag table. The type is one of the value from the FieldType enumeration.

enum FieldType : uint8_t
{
	signed_char				= 0x01, // 8 bit signed
	unsigned_char			= 0x02, // 8 bit unsigned
	signed_short			= 0x03, // 16 bit signed
	unsigned_short			= 0x04, // 16 bit unsigned
	signed_int				= 0x05, // 32 bit signed
	unsigned_int			= 0x06, // 32 bit unsigned
	signed_long				= 0x07, // 32 bit signed
	unsigned_long			= 0x08, // 32 bit unsigned
	bool					= 0x09,
	float					= 0x0A,
	string					= 0x0B,
	array					= 0x0C,
	object					= 0x0D,
	object_pointer			= 0x0E,
	pair					= 0x0F,
	array_signed_short		= 0x10,
	array_signed_int		= 0x11,
	array_float				= 0x12,
	empty					= 0x13,
	double					= 0x14,
	array_double			= 0x15,
};
struct Field
{
	uint16 tag; // Corresponds to an entry in the tag table.
	FieldType type;
	byte data[]; // Followed by polymorphic data blob which content is determined by the type field.
};

Fundamental types

For fundamental C types, the field data contains only that value using the Microsoft x86 ABI. This means that the signed and unsigned long data types have a width of 32 bits, the same as signed and unsigned int.

All integers use little endian, and the floating point types conform to IEEE-754 binary32 and binary64 for float and double respectively.

When deserializing, some fields are implicitly converted to the types used by the program if there is a mismatch. Conversions may be applied between integers and floating points. However the sign of the value may not change. Also not all fields are subject to conversion. In particular a type mismatch in certain version fields may cause a deserialization failure.

String

The string data type is a length-prefixed non-null-terminated string, using a 16 bit length prefix:

struct Field_string
{
	uint16_t size;
	char data[size];
};

Size prefixed data blobs

Fields with the array or object data types are both length-prefixed using a 32 bit length describing the size of the data blob, excluding the prefix.

struct DataBlob
{
	uint32_t size;
	byte blob[size];
};

Array

The generic array data type contains an array of fields, their number given by a second size prefix.

struct Field_array
{
	uint32_t size;
	Field data[size];
};

Object and object pointer

Both the object and object pointer data types share a common header. The header contains a class type identifier corresponding to an entry in the class table, and an address field uniquely identifying the object in the entire graph. The unique identifier is presumably the 32 bit runtime address of the object at the time of serialization. It is used for linking pointers in the object graph during deserialization.

struct ObjectHeader
{
	int16_t class; // Corresponds to an entry in the class table.
	uint32_t address;
};

The object data type contains a number of fields. The number of fields is not given, but the size of the data blob is used to determine the end of the object. Note that object fields contain the blob size prefix mentioned previously.

struct Field_object
{
	ObjectHeader header;
	Field fields[]; // Arbitrary number of fields.
};

The object pointer data type is a stripped down version of the header of the object data type. However it only contains the type and address of the object, with the address corresponding to an object somewhere in the graph.

struct Field_object_pointer
{
	ObjectHeader header; // header.address corresponds to the header.address of some object in the graph.
};

Pair

The pair data type simply holds two fields. It is primarily used by associative containers.

struct Field_pair
{
	Field first;
	Field second;
};