From owdev
Jump to: navigation, search

Format changed as of 1.14, old format (pre-1.13) is Legacy. The older format is still being used in some STU file types.


"void*" and any pointer (*) is an uint, not long.


uint             instance_count;
STUInstanceInfo* instance_list;             // Size is instance_count
uint             array_reference_count;
STUArrayRefInfo* array_reference_list;      // Size is array_reference_count
uint             instance_field_list_count;
STUFieldInfo*    instance_field_list;       // Size is instance_field_list_count
uint             array_buffer_size;
char*            array_buffer;              // Size is array_buffer_size
uint             data_offset;               // STU instances start at this offset.


This structure describes each STU in the file.

uint checksum; // CRC32 IEEE / CRC32b of the STU instance name
uint field;    // CRC32b of the parent field. Ignore if 0.
int  index;    // Index of the parent instance. Ignore if -1. instances[index][field] = this.
uint size;     // Absolute size of the instance.


This structure describes if any array needs STU pre-processing.

uint checksum; // CRC32 IEEE / CRC32b of the STU instance name
uint size;     // Absolute size of each entry(?) or padding bytes.


This structure describes a field array, there can be more than 1 field array per STU.

uint      count;  // Number of fields.
STUField* fields; // Size is count


This structure defines a field. The order is important.

uint checksum; // CRC32 IEEE / CRC32b of the STU field name
uint size;     // Absolute size of each field.

Zero size fields are nested structures.

Parsing STU Instances

Each instance is prefixed with an int. This value is the field info index. Use this field array to get information about a field.

STUs do not have any offsets stored that point to themselves.

Nested Structures

Nested structures are similar to STU instances, these will always have a field size of **zero**, indicating a dynamically sizing structure.

In this case you should read a single unsigned integer.

 uint field_size; // size of nested structure

This is the buffer size. Read field_size bytes as a buffer then parse it as a new instance. In the case of arrayed nested structures, you must shrink the buffer once reading is done and read a new instance. Repeat this until the buffer is length zero.


This structure describes the array, it's prefixed to each array.

uint  count;              // No. of entries
int   unknown; // Index of reference STU to process the value(s)?
void* data;               // Size is count. Each entry size is determined by the STU parsing the array.
uint  unknown;            // Zero

GUID Demangling

GUIDs can be mangled, in this case you need to run a CRC64-J (jones, polynomial 0x1AD93D23594C935A9) on the STU header (first 36 bytes), this will be the header checksum.

Then shift the field's hash to repeat itself once

 ulong field_hash = hash | (hash << 32);

Then XOR the mangled GUID with the header checksum and the double field hash.

 ulong demangled_guid = guid ^ header_hash ^ field_hash;

Then swap byte 0 with byte 3, byte 7 with byte 1, byte 2 with byte 6, byte 4 with byte 5.

You may have to XOR the final value with 0xFFFFFFFFFFFFFFFF.

Detecting mangled GUID fields

Has to do with the field CRC hash, TODO.


Chunked model files can contain STU instances. This is defined in the MSTU chunk.

The format contained within the MSTU is identical to a normal STU however, it's prefixed with the following:

char* buffer; // long, Size is size. Points to the STU instance.
ulong size;