Data Structures and Types

December 12, 2025 · View on GitHub

This document defines many data structures. This section describes the notation used for those data structures.

Structures are defined using pseudo-C code, using the struct { ... } syntax. Unlike C, structures defined in this document may be variable-length and may contain variable-length fields. Variable-length fields of structures may be arrays of fixed-size structures, arrays of variable-size structures, NUL-terminated strings, the Number type, or a reference to another variable-length structure defined in this document.

Range syntax

Numeric ranges are specified using start-end, where both start and end are inclusive bounds. For example, "bits 3-5" means "bits 3, 4, and 5".

Fixed-size Integers

This document uses the C/C++ integer types defined in <stdint.h>. All integer values are in LSB-first (little-endian) encoding, unless specified otherwise.

These are the integer types used in this document:

NameUsage
uint8_t(obvious)
uint16_t
uint32_t
uint64_t
int8_t
int16_t
int32_t
int64_t
char8_t8-bit value used for encoding code units of UTF-8 strings.

GUID

The well-known GUID type is imported from Windows. It is a 16-byte quantity.

Embedded arrays

Variable-length arrays may be directly embedded within a structure. It is not the case that a fixed amount of storage is reserved. Instead, the elements are directly embedded within the structure, followed by the next field (if any). The number of elements in the array is usually given as an expression within the array’s square brackets.

Example:

struct Garden {
  uint32_t num_apples;
  Apple apples[num_apples];
};

If the last field of a structure is an array field, and the number of elements is implied by the length of the entire encoded structure, then the length may be omitted. Example:

struct MoreGarden {
  uint32_t num_apples;
  Apple apples[num_apples];
  Tomato tomatoes[];   // the rest of the storage is tomatoes
};

It is not legal to have another field follow an array with implicit length, unless the meaning is clarified by context. The following is an example of an illegal structure definition:

struct BadDefinition {
  uint32_t numbers[];
  uint32_t x;
};

Strings: strz

The data type strz represents a NUL-terminated string, using UTF-8 encoding. For example:

struct Foo {
    uint32_t month;   // fixed-length header
    uint32_t day;
    uint32_t year;

    strz flavor;      // variable-length fields
    strz build;
}

This syntax means that the string data is directly stored in the structure, and that the structure is variable-length. It is not the case that a fixed number of characters are allocated for the string; instead, character data is written, followed by a NUL (a zero byte), followed by the next field (if any).

The Number type

The Number type represents a numeric constant. Numbers may have different sizes and representations. Each Number value is at least 2 bytes in size. These first 2 bytes specify either an immediate value or specify the encoding to use for the entire value.

See: Numbers

Example of using Number:

struct NamedConstant {
    strz name;
    Number value;
}

Both of the fields of NamedConstant are variable-length.

TypeIndex: Pointer into TPI Stream

TypeIndex is an alias for uint32_t, with a specific interpretation. Each TypeIndex either refers to a record within the Type Database (TPI Stream), which is described later in this document, or refers to a primitive (well-known / intrinsic) type. See the Type Database section for more information.

ItemId: Pointer into IPI Stream

ItemId is an alias for uint32_t, with a specific interpretation. Each ItemId refers to a record within the IPI Stream, or to NIL (no record). The value of NIL is zero. ItemId counts records, not bytes.

See ItemId.

NameIndex

NameIndex is an alias for uint32_t which points into the Names Stream.