Oblivion Mod:BSA File Format

Mod / Oblivion: Oblivion Mod: Modding

OverviewEdit

BSA files are the resource archive files used by Oblivion. If you're familiar with the Morrowind BSA file format, Oblivion BSA format is similar, but not identical to it (if you're familiar with the generic IFF format, you'll find it very easy to understand --- BSA, ESM/ESP and ESS are IFF variants).

See also
Hash Calculation
Tools and Programmers for BSA unpacking tools.
Tes3 and 4 Utilities by Ghostwheel

Files and Dirs orderEdit

Inside an archive, folders and files in folders must be sorted in ascending order by hash value. Sort all folders, then all files within the folders, keeping the folders contiguous.

File StructureEdit

Type/Size Info
struct
(36 bytes)
Header
char[4] - Four character code (constant: "BSA\0")
uint32 - Version (always 103 for Oblivion)
uint32 - Offset of beginning of folder records. All headers are the same size, therefore this value is 36.
uint32 - List of archive flags:
Bit Description
1 (0x1)¹ Archive has names for directories. (The game may not load a BSA without this bit set.)
2 (0x2)¹ Archive has names for files. (The game may not load a BSA without this bit set.)
3 (0x4) Files are compressed by default.
4 (0x8)² Unknown, but observed being checked for in Oblivion.exe. Possibly instructs the game to retain directory names in memory.
5 (0x10)² Unknown, but observed being set in official BSA files containing sounds (but not voices). Possibly instructs the game to retain file names in memory.
6 (0x20)² Unknown. Unobserved in official BSA files. In BSA v104, this bit instructs the game to 'retain file name offsets'.
7 (0x40) If this bit is clear, all numbers in the file, including hashes, are little-endian (PC style). A value of 0xABCDEF01 would appear in the file as 01 EF CD AB.

If this bit is set, all numbers are big-endian (Xbox360 style). Thus, the value above would appear in the file as AB CD EF 01.

8 (0x80)² Unknown, but observed being checked for in Oblivion.exe, related to the bInvalidateOlderFiles and bCheckRuntimeCollisions INI settings in Oblivion.ini. Also somehow related to bit 3. In BSA v104, this bit tells the game to 'retain strings during startup'.
9 (0x100)¹ Unknown. This setting has a different meaning for BSA v104.
10 (0x200)¹ Unknown. This setting has a different meaning for BSA v104.
11 (0x400)¹ Unknown.
¹ This bit is set in all official BSA files.
² This bit has no effect on the file structure. Probably just instructions for the game.
uint32 - (FolderCount) Count of all folders in archive.
uint32 - (TotalFileCount) Count of all files in archive.
uint32 - Total length of all folder names, including \0's but not including the prefixed length byte.
uint32 - (TotalFileNameLength) Total length of all file names, including \0's.
uint32 - Content type flags:
Bit Description
1 (0x1) Meshes
2 (0x2) Textures
3 (0x4) Menus
4 (0x8) Sounds
5 (0x10) Voices
6 (0x20) Shaders
7 (0x40) Trees
8 (0x80) Fonts
9 (0x100) Miscellaneous
struct[FolderCount]
(16 bytes per entry)
Folder records
uint64 - Hash of the folder name (eg: menus\chargen).
uint32 - (FolderFileCount) Number of files in this folder.
uint32 - Offset to name and file records for this folder. (Seems to include Total File Name Length)
struct[FolderCount] Folder name and files
bzstring - Name of the folder. (Only present if bit 1 of archive flags is set.)
struct[FolderFileCount] - File records in the given folder.
uint64 - Hash of the file name (eg: race_sex_menu.xml).
uint32 - (FileSize) Size of the file data. Note that the top two bits have special meaning and are not actually part of the size.
If bit 30 is set in the size, the default compression is inverted for this file (i.e., if the default is compressed, this file is not compressed, and vice versa).
Bit 31 is used internally to determine if an archive has been checked yet.
uint32 - Offset to raw file data for this folder. Note that an "offset" is offset from file byte zero (start), NOT from this location.
bzstring[TotalFileCount] File name block. (Only present if bit 2 of the archive flags is set.)

A list of lower case file names, one after another, each ending in a \0. They are ordered in the same order as those generated with the file folder block contents in the BSA archive. These are all the files contained in the archive, such as "cuirass.nif" and "cuirass.dds", etc (no paths, just the root names).

struct Raw file data as either a compressed file block if bit 2 of the archive flags is set, or an uncompressed file block if the bit is clear.
Compressed File Block
bstring Full path and name of the file (only present if bit 9 of the archive flags is set).
uint32 Size of uncompressed data.
uint8[FileSize] File data that has been compressed with zlib.
Uncompressed File Block
bstring Full path and name of the file (only present if bit 9 of the archive flags is set).
uint8[FileSize] File data.