The EX file format

EX files begin with a header with the following structure.

Offset Size (Bytes) Description
0x0 4 Magic: ‘HEAD’
0x4 4 0xC (?)
0x8 4 Magic: ‘EXTF’
0xC 4 0x1 (?)
0x10 4 Block count
0x14 4 Magic: ‘DATA’
0x18 4 Compressed data size (bytes)
0x1C 4 Uncompressed data size (bytes)
0x20 Varies Encrypted & compressed data

The compressed data is encrypted with a dictionary. It can be decrypted as follows,


uint8_t ex_decode_table[256];

void decode(uint8_t *compressed_data, size_t size)
{
    // initialize table
    for (int i = 0; i < 256; i++) {
        int tmpfor = i;
        int tmp = tmpfor;
        tmp = (tmp & 0x55) + ((tmp >> 1) & 0x55);
        tmp = (tmp & 0x33) + ((tmp >> 2) & 0x33);
        tmp = (tmp & 0x0F) + ((tmp >> 4) & 0x0F);
        if ((tmp & 0x01) == 0) {
            tmpfor = ((tmpfor << (8 - tmp)) | (tmpfor >> tmp)) & 0xFF;
        } else {
            tmpfor = ((tmpfor >> (8 - tmp)) | (tmpfor << tmp)) & 0xFF;
        }
        ex_decode_table[i] = tmpfor;
    }

    // decode data
    for (size_t i = 0; i < size; i++) {
        compressed_data[i] = ex_decode_table[i];
    }
}

Once the data is decrypted, it can be uncompressed using zlib.

Blocks

The uncompressed data is a list of blocks. Each block has a name, data type and associated data. The number of blocks in the list is given in the header described above.

Size (Bytes) Description
4 Data type
4 Block size
Varies Name (ex-string)
Varies Value (depends on data type)

EX Strings

Strings in EX files are encoded as pascal strings. Sometimes (not always!) they are zero-padded so that the length is a multiple of 4. I will refer to such padded strings as ‘ex-strings’ throughout this document.

Size (Bytes) Description
4 Size
Varies Data

Data Types

EX files can contain the following data types:

Value Name Description
1 EX_INT 32-bit integer
2 EX_FLOAT 32-bit float
3 EX_STRING Pascal string (32-bit size followed by string data)
4 EX_TABLE Table
5 EX_LIST List
6 EX_TREE Tree

Tables

A table is a list of fields, followed by the table data.

Size (Bytes) Description
4 Field count
Varies Field descriptors
4 Column count
4 Row count
Varies Rows

Starting in Evenicle, the order of ‘Column count’ and ‘Row count’ is reversed.

Field Descriptors

Size (Bytes) Description Notes
4 Data type
Varies Name (ex-string)
4 Has value?
4 Is index? If 1, then this field should be indexed
Varies Value (depends on data type) Only present if ‘Has value?’ is 1
4 (0) Subfield count Only present if data type is EX_TABLE
Varies Subfields Only present if data type is EX_TABLE

If a field’s data type is EX_TABLE, then ‘Subfield count’ and ‘Subfields’ are present. ‘Subfields’ is a nested array of field descriptors.

Rows

A row is a list of cells. The number of cells contained in each row is given by the ‘Column count’ of the table, and the number of rows in a table is given by the ‘Row count’. A cell is a simple type-value pair:

Size (Bytes) Description
4 Data type
Varies Value (depends on data type)

Lists

Size (Bytes) Description
4 Item count
Varies List items

List Items

Size (Bytes) Description
4 Data type
4 Data size
Varies Value (depends on data type)

Trees

Trees are encoded as a recursive node structure:

Size (Bytes) Description
Varies Node name (ex-string)
4 Is leaf?
Varies Node data

If ‘Is leaf?’ is 1, then ‘Node data’ contains a leaf node descriptor. If ‘Is leaf?’ is 0, then ‘Node data’ contains an intermediate node descriptor.

Leaf Nodes

Size (Bytes) Description
4 Data type
4 Data size
Varies Leaf name (ex-string)
Varies Value (depends on data type)
4 Reserved? (always 0)

Intermediate Nodes

Size (Bytes) Description
4 Child count
Varies Children

Each entry in ‘Children’ is a full tree descriptor.