ERF (Encapsulated Resource File)
ERFs are the heavy lifters for standard game modules (.mod) and save game architectures (.sav). Unlike BIFs, which rely entirely on an external KEY file to resolve their resource identities, ERFs are completely self-contained entities that carry their own internal file tables, localized descriptions, and asset payloads.
At a Glance
| Property | Value |
|---|---|
| Extension(s) | .erf, .mod, .hak, .sav |
| Magic Signatures | ERF , MOD , HAK , SAV (version V1.0) |
| Type | Self-Contained Archive |
| Rust Reference | View rakata_formats::Erf in Rustdocs |
Data Model Structure
Because ERF files share the exact same structural responsibility as RIM files (acting as self-contained module wrappers), the rakata-extract crate abstracts both ERF and RIM parsing directly behind the unified Capsule struct.
- Capsule Generalization: Standard module extraction relies entirely on calling
rakata_extract::Capsule::read_from_bytes(). This actively probes and dynamically mounts eitherERForRIMboundaries identically in memory, completely hiding the underlying structural container differences from the developer API.
Engine Audits & Decompilation
The following information documents the KOTOR engine’s exact load sequence and field requirements for genuine .erf capsule variants. All behavior was mapped natively from swkotor.exe during clean-room reverse engineering.
Capsule Header Initialization (CExoEncapsulatedFile::LoadHeader)
Mapped from 0x0040e1f0.
| Action | Engine Behavior |
|---|---|
| Signature Check | Explicitly validates the header against exactly matching ERF , MOD , or HAK signatures, paired with the mandatory V1.0 version string. |
| Unchecked Saves | The engine completely lacks a validation branch for .sav files. If a file is loaded as a Save Game (param flag 1), the engine falls through the validation tree and explicitly mandates the file use the MOD magic string natively. An ERF file with SAV magic will physically crash or reject here! |
| Header Truncation | The loader explicitly pulls the entire 160-byte header into scope (CExoFile::Read(..., 0xa0)), but only evaluates offsets 0x00 through 0x1C. Offset 0x18 (Key List) and anything beyond 0x1C is entirely ignored during initialization. |
Tip
The 116-Byte “Dead Zone” The giant block of bytes stretching from physical offsets
0x2Cdown to0xA0inside the 160-byte header is formally loaded into the engine’s active memory stack… and then completely discarded immediately. It is totally inert data containing old Bioware build metadata.