Skip to main content

nwnrs_erf/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = "# nwnrs-erf\n\n`nwnrs-erf` reads and writes the ERF-family archive formats used by\nNeverwinter Nights, including `ERF`, `MOD`, `HAK`, and `NWM`.\n\n## Scope\n\n- parse typed ERF archives and their resource tables\n- expose archive contents as an [`Erf`] value\n- implement `nwnrs-resman` container behavior for archive-backed resolution\n- write typed archive data back to disk\n\nThe principal entry points are [`read_erf`], [`read_erf_from_file`],\n[`read_erf_shared`], and [`write_erf`].\n\n## Public Surface\n\n- `Erf`\n- `ErfVersion`\n- `ErfWriteOptions`\n- `ErfError`\n- `ErfResult`\n- `read_erf`\n- `read_erf_from_file`\n- `read_erf_shared`\n- `write_erf`\n- `write_erf_archive`\n- `write_erf_with_options`\n\n## Core Model\n\n`Erf` preserves:\n\n- outer archive type and version\n- archive filename\n- build year and day\n- top-level `str_ref`\n- localized strings\n- ordered entries\n- optional enhanced-edition `oid`\n- preserved padding between key and resource lists\n\nThe same typed value also implements `ResContainer`.\n\n## Binary Layout\n\nHeader size: `160` bytes.\n\nKnown outer file types:\n\n- `ERF `\n- `MOD `\n- `HAK `\n- `NWM `\n\nKnown versions:\n\n- `V1`\n- `E1`\n\nHeader shape:\n\n```text\nfile_type                [4]\nfile_version             [4]\nloc_str_count            i32\nloc_string_size          i32\nentry_count              i32\noffset_to_loc_str        i32\noffset_to_key_list       i32\noffset_to_resource_list  i32\nbuild_year               i32\nbuild_day                i32\nstr_ref                  i32\nreserved or OID area     remaining header bytes\n```\n\nArchive body:\n\n```text\n+----------------------+\n| 160-byte header      |\n+----------------------+\n| localized strings    |\n+----------------------+\n| key list             |\n+----------------------+\n| resource list        |\n+----------------------+\n| resource data area   |\n+----------------------+\n```\n\nEntry-table sizes differ by version:\n\n- key entry\n  - `V1`: 24 bytes\n  - `E1`: 44 bytes\n- resource entry\n  - `V1`: 8 bytes\n  - `E1`: 16 bytes\n\n`E1` adds optional compression metadata and archive OID support.\n\n## Invariants\n\n- resource references and archive membership are represented explicitly\n- archive semantics are preserved independently of the container filename\n- the same typed archive value can be inspected structurally and used as a\n  `ResContainer`\n- stored entry order and resource-list padding are preserved on write\n- `E1` per-entry compression metadata is physical-storage metadata, not content\n  semantics\n\n## See also\n\n- [`nwnrs-resman`](https://docs.rs/nwnrs-resman), which layers multiple\n  containers in precedence order\n- [`nwnrs-key`](https://docs.rs/nwnrs-key), which models the KEY/BIF storage\n  family\n\n## Why This Crate Exists\n\n`ERF` is both:\n\n- a physical archive format\n- a logical resource container\n\nThis crate models both sides explicitly without conflating them with global\nlookup policy, which belongs in `nwnrs-resman`.\n"include_str!("../README.md")]
3
4mod io;
5mod types;
6
7pub use io::*;
8pub use types::*;
9
10/// Common imports for consumers of this crate.
11pub mod prelude {
12    pub use crate::{
13        Erf, ErfError, ErfResult, ErfVersion, ErfWriteOptions, read_erf, read_erf_from_file,
14        read_erf_shared, write_erf, write_erf_archive, write_erf_with_options,
15    };
16}