Overview
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
File Structure
Name | Type/Size | Info |
---|---|---|
Header | Header | See specification of Header below. |
folderRecords | Folder Record[folderCount] | See specification of Folder Record below. |
fileRecordBlocks | File Record blocks[...] | See specification of File Record blocks below. |
fileNameBlock | File Name block | A list of filenames. Each filename ends in \0. See specification of File Name block below. |
files | data or specification of Compressed File block | Raw file data. If the file is compressed the file data will have the specification of Compressed File block. |
Header
Name | Type/Size | Info | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fileId | char[4] | Constant: "BSA\x00" | ||||||||||||||||||||||||
version | ulong | Currently 103 (0x67). | ||||||||||||||||||||||||
offset | ulong | Offset of beginning of folder records. All headers are the same size, therefore this value is 36 (0x24) | ||||||||||||||||||||||||
archiveFlags | ulong | List of archive flags:
¹ This bit is set in all official BSA files. |
||||||||||||||||||||||||
folderCount | ulong | Count of all folders in archive. | ||||||||||||||||||||||||
fileCount | ulong | Count of all files in archive. | ||||||||||||||||||||||||
totalFolderNameLength | ulong | Total length of all folder names, including \0's but not including the prefixed length byte. | ||||||||||||||||||||||||
totalFileNameLength | ulong | Total length of all file names, including \0's. | ||||||||||||||||||||||||
fileFlags | ulong | List of flags:
|
Folder Record
Name | Type/Size | Info |
---|---|---|
nameHash | hash | Hash of the folder name (eg: menus\chargen). Must be all lower case, and use backslash as directory delimiter(s). |
count | ulong | Amount of files in this folder. |
offset | ulong | /*Offset to file records for this folder. (Seems to include totalFileNameLength)*/
Offset to name of this folder + totalFileNameLength. |
File Record blocks
If Bit 1 of archive flags is set:
Name | Type/Size | Info |
---|---|---|
name | bzstring | Name of the folder. |
fileRecords | variable (File Record) | Many records in the amount of files specified in the associated folder record. |
If Bit 1 of archive flags is not set:
Name | Type/Size | Info |
---|---|---|
fileRecords | variable (File Record) | Many records in the amount of files specified in the associated folder record. |
File Record
Name | Type/Size | Info |
---|---|---|
nameHash | hash | Hash of the file name (eg: race_sex_menu.xml). Must be all lower case. |
size | ulong | Size of the file data.
If the (1<<30) bit is set in the size:
If the file is compressed the file data will have the specification of Compressed File block. In addition, the size of compressed data is considered to be the ulong "original size" plus the compressed data size (4 + compressed size). |
offset | ulong | Offset to raw file data for this folder. Note that an "offset" is offset from file byte zero
(start), NOT from this location. |
File Name block
If archive flag 0x2 is not set, this block is omitted. A block 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).
Compressed File block
If Bit 9 of archiveFlags is not set:
Name | Type/Size | Info |
---|---|---|
originalSize | ulong | Size of uncompressed data. |
data | ubyte[compressedSize] | File data that has been compressed with zlib. |
If Bit 9 of archiveFlags is set:
Name | Type/Size | Info |
---|---|---|
name | bstring | Full path and name of the file |
originalSize | ulong | Size of uncompressed data. |
data | ubyte[compressedSize] | File data that has been compressed with zlib. |
Uncompressed File block
If Bit 9 of archiveFlags is not set:
Name | Type/Size | Info |
---|---|---|
data | ubyte[fileSize] | File data. |
If Bit 9 of archiveFlags is set:
Name | Type/Size | Info |
---|---|---|
name | bstring | Full path and name of the file |
data | ubyte[fileSize] | File data. |
Files and Dirs order
Inside bsa, folders and files in folders must be sorted by hash values. Sort all folders, then all files within the folders, keeping the folders contiguous. The 64 bit unsigned integer of hash value is used for sorting.
Encoding Numbers in the BSA
If Bit 7 of archive flags is not set, numbers are encoded low byte to high byte. A ulong of 0xABCDEF01 would have 0x01 in the first file byte, 0xEF in the second file byte, 0xCD in the third file byte, and 0xAB in the fourth and last file byte. This is true of the 64 bit (8 byte) hash value as well. If Bit 7 is set, then all numbers and 8 byte hash values are reverse order (big-endian).