BLP

A **BLP** file is a container for binary-serialized assets such as textures and models. It is new to Civilization VI.

## Format

### Header

All values in this file are stored little-endian. The file begins with a header:

```
struct BLPHeader {
    char magic[6];            // 'CIVBLP'
    uint16 version;           // 1
    uint32 packageDataOffset; // Generally 0x200
    uint32 packageDataSize;
    uint32 bigDataOffset;     // packageDataOffset + packageDataSize
    uint32 bigDataCount;
    uint32 fileSize;
};

```

### Package Headers

At `packageDataOffset` bytes in the file, there is a `PackagePreamble` followed immediately by a `PackageHeader`:

```
struct PackagePreamble {
    uint32 uiPackageVersion;        // 5
    uint16 uiSizeOfVoidPointer;     // 8
    uint16 uiAlignOf64BitStructure; // 8
    uint32 uiSizeOfPackageHeader;   // 0x48
    uint32 uiEndianField;           // 1
};
struct PackageHeader {
    struct StripeInfo { // A stripe is a block of serialized data
        uint32 uiStart; // This is an offset from the start of the PackagePreamble value
        uint32 uiSize;
    };
    StripeInfo kResourceLinkerDataStripe;
    StripeInfo kPackageBlockStripe;        // This stripe contains package objects.
    StripeInfo kTempDataStripe;            // This stripe contains linker data (which is information on how to fixup pointers), the root object, and String::Global objects.
    StripeInfo kTypeInfoStripe;            // This stripe contains another package with type information for all the objects serialized in packageData
    StripeInfo kRootTypeName;              // The root object of the package is this type; it is stored at the start of TempDataStripe
    uint32 uiLinkerDataOffset;             // This is an offset from the start of TempDataStripe; it contains an array of PackageAllocation
    uint32 uiResourceListOffset;
    uint32 uiLargestResource;
    uint32 uiSecondLargestResource;
    uint32 uiPackageBlockAlignment;        // 0x10
    uint32 uiSizeOfTypeInfoStripe;         // 0x30
    uint32 uiSizeOfPackageAllocation;      // 0x28
    uint32 uiSizeOfResourceAllocationDesc; // 0x10
};

```

The `TypeInfoStripe` contains another `PackagePreamble` and `PackageHeader`, in which a `TypeInfoStripe` struct is serialized.

### Pointer Fixup

Every pointer value in a BLP file is stored as a `uint64`. If this value is 0, then the pointer is null. Otherwise, to resolve the pointer to a location in the file, the value minus 1 is used as an index in to the array of `PackageAllocation` specified by `uiLinkerDataOffset` in the `PackageHeader`.

```
struct PackageAllocation {
    uint8 byStripe;           // 0: PackageBlockStripe; 1: TempDataStripe
    uint8 byAllocType;
    uint8 byPadding[4];
    uint16 wParentAlloc;
    uint32 dwOffset;
    uint32 dwAllocSize;
    uint32 dwElementCount;
    uint64 qwUserData;
    String::Global sTypeName; // String::Global is a pointer to char
};

```

From the `PackageAllocation` value, `byStripe` is used to determine which stripe the pointed-to object is in, and `dwOffset` is the byte offset in to that stripe to the object.

To do fixup on all pointers in the package, iterate the `PackageAllocation` array, and do fixup for the values in each allocation, using `sTypeName` and the `TypeInfoStripe` to fixup all pointer values in the allocation.

### Type Information

The `TypeInfoStripe` contains type information for all objects serialized in the BLP file.

```
struct LinearAlloc {
    template <typename T>
    struct LinearBlock {
        ptr64<T> pBlock;
        uint32 nElements;
    };
};

namespace Types {
    template <typename T>
    struct Vector { // Note: sizeof(Vector) is 0x18 due to padding
        LinearAlloc::LinearBlock<T> m_kBlock;
        uint32 m_nCurrSize;
    };
};

namespace String {
    struct Global {
        ptr64<char> m_sz;
    };
};

struct TypeInfoStripe {
    struct FieldVersion {
        String::Global m_sFieldName;
        String::Global m_sTypeName;  // type of the field value
        uint32 m_uiVersion;
        uint32 m_uiAddress;          // byte offset of the field in the struct
    };
    struct TypeVersion {
        String::Global m_sTypeName;
        String::Global m_sUnderlyingTypeName;
        // Note:  fields are not ordered as they are defined in the struct.
        // Inherited fields are included in this vector.
        Types::Vector<FieldVersion> m_Fields;
        uint32 m_uiVersion;
        uint32 m_uiSize;
        // 0x01: is array
        // 0x02: is pointer
        // 0x04: is fundamental (scalar -- int, float, etc.)
        // 0x10: is polymorphic (has a virtual table)
        uint32 m_uiTypeTraitFlags;
    };
    struct EnumVersion {
        struct EnumConstant {
            String::Global sName;
            int32 iValue;
        };
        String::Global m_sTypeName;
        Types::Vector<EnumConstant> m_Constants;
    };

    Types::Vector<TypeVersion> m_Types;
    Types::Vector<EnumVersion> m_Enums;
};

```

### Strings

`String::BasicT` has a discrepancy between its type information and its
actual layout. Note that it is still a pointer, but it does not point directly to
the string data:

```
namespace String {
template <typename Allocator, typename Encoding>
struct BasicT {
    struct Storage {
        uint32 capacity;
        uint32 length;
        char str[1];
    };
    String::Basic::Storage *m_sz;
    const char *CStr() const {
        return m_sz->str;
    }
};
};

```