Skip to content

BA2 Archive Format

.ba2 is Bethesda's archive format introduced in Fallout 4, replacing the .bsa format used in Skyrim and earlier games. It packages game assets (meshes, textures, sounds, scripts) into a single compressed file.

The file begins with a fixed header:

magic          char[4]   — "BTDX"
version        uint32    — 1 for base game; ≥2 adds two unknown trailing uint32s
archive_type   char[4]   — "GNRL", "DX10", or "GNMF"
num_files      uint32    — number of file entries
name_table_offset uint64 — byte offset to the filename string table
[unknown1]     uint32    — only present if version ≥ 2
[unknown2]     uint32    — only present if version ≥ 2

Archive types:

Code Contents
GNRL General files — meshes, materials, audio, scripts, etc.
DX10 DirectX textures — stored as raw mip chunks with a reconstructed DDS header
GNMF PlayStation GNF textures (console builds)

GNRL File Entries

Immediately after the header, num_files entries of 36 bytes each:

name_hash       uint32   — hash of the filename
extension       char[4]  — file extension, zero-padded (e.g. "nif\0")
dir_hash        uint32   — hash of the directory path
flags           uint32
data_offset     uint64   — absolute byte offset to the file data
packed_size     uint32   — compressed size; 0 means uncompressed
unpacked_size   uint32   — uncompressed size
align           uint32   — alignment padding (always 0xBAADF00D in practice)

Compression: when packed_size != 0, the data at data_offset is DEFLATE-compressed (zlib/RFC 1951 without header). Decompress packed_size bytes to unpacked_size bytes.


DX10 Texture Entries

Each DX10 entry has a fixed prefix followed by a variable-length chunk table:

name_hash          uint32
extension          char[4]
dir_hash           uint32
unknown            uint8
num_chunks         uint8
chunk_header_size  uint16
height             uint16
width              uint16
num_mips           uint8
format             uint8    — DXGI_FORMAT enum value
is_cubemap         uint8    — 1 if cubemap
tile_mode          uint8    — 8 = PC layout; other = Xbox tiled

Followed by num_chunks chunk records (24 bytes each):

data_offset    uint64
packed_size    uint32   — 0 = uncompressed
unpacked_size  uint32
start_mip      uint16
end_mip        uint16
align          uint32

To reconstruct the DDS file: build a DDS header from width, height, num_mips, format (mapped to the appropriate DDSPF / DX10 extended header), then concatenate the decompressed chunk data in order.

Xbox layout: tile_mode != 8 indicates an Xbox One tiled texture. The data layout differs from standard PC DDS (Morton/swizzle order) and requires detiling before use on PC.


Name Table

Located at name_table_offset bytes from the start of the file. For each file entry in index order:

str_length  int16    — byte length of the following string
str_data    char[]   — file path, not null-terminated

Paths use backslashes as separators. If name_table_offset is 0, no name table exists and files can only be identified by their name/dir hashes.


Hashing Algorithm

Bethesda uses two hash functions to identify files without storing full paths in the entry table:

Filename hash (applied to the filename without extension): - Sum of characters + various shift/XOR operations on specific character positions - Exact algorithm matches the BSA hash used since Oblivion

Directory hash (applied to the directory path): - Same algorithm applied to the full directory portion of the path

The hashes allow O(1) lookup by path but provide no ordering guarantee.


DXGI Format Values (common)

Value Format Usage
28 DXGI_FORMAT_R8G8B8A8_UNORM Uncompressed RGBA
71 DXGI_FORMAT_BC1_UNORM DXT1 — opaque diffuse
74 DXGI_FORMAT_BC2_UNORM DXT3 — diffuse with punch-through alpha
77 DXGI_FORMAT_BC3_UNORM DXT5 — diffuse with smooth alpha
80 DXGI_FORMAT_BC4_UNORM ATI1 — single-channel (grayscale/specular masks)
83 DXGI_FORMAT_BC5_UNORM ATI2 — two-channel normal maps (X, Y)
98 DXGI_FORMAT_BC7_UNORM High-quality RGBA
99 DXGI_FORMAT_BC7_UNORM_SRGB BC7 with sRGB gamma

Normal maps in FO4 are typically BC5 (two channels), with the Z component reconstructed as sqrt(1 - X² - Y²).