nwnrs_ssf/lib.rs
1#![forbid(unsafe_code)]
2#![doc = "# nwnrs-ssf\n\nReader and writer for soundset (`SSF`) files.\n\n## Scope\n\n- parse fixed-layout SSF tables into typed slot entries\n- preserve the association between each slot and its sound and string\n references\n- write typed SSF data back to disk\n\n## Public Surface\n\n- `SsfRoot`\n- `SsfEntry`\n- `SsfError`\n- `SsfResult`\n- `read_ssf`\n- `write_ssf`\n\n## Core Model\n\n- `SsfRoot` is an ordered vector of slots\n- `SsfEntry` preserves:\n - `raw_resref`\n - decoded `resref`\n - `strref`\n\nEach slot binds two different namespaces:\n\n- a resource reference for audio\n- a string reference for localized text\n\n## Binary Layout\n\nThe crate models:\n\n- magic: `\"SSF \"`\n- version: `\"V1.0\"`\n- fixed table offset: `40`\n- fixed entry size: `20` bytes\n\nLayout:\n\n```text\n0x00 \"SSF \"\n0x04 \"V1.0\"\n0x08 entry_count u32\n0x0C table_offset u32 == 40\n0x10 padding 24 bytes of zero\n0x28 entry_offsets entry_count * u32\n0x.. entry data entry_count * 20 bytes\n```\n\nEntry payload:\n\n```text\nresref[16]\nstrref u32\n```\n\nConceptually:\n\n```text\n+----------------------+\n| fixed header |\n+----------------------+\n| offset table |\n+----------------------+\n| slot 0 |\n+----------------------+\n| slot 1 |\n+----------------------+\n| ... |\n+----------------------+\n```\n\n## Invariants\n\n- soundset slots remain positional and typed\n- string references and resource references stay distinct fields\n- slot position is semantic; reordering entries changes meaning\n- raw resref bytes are preserved when only `strref` changes and the original\n encoded bytes still match the typed name\n\n## See also\n\n- [`nwnrs-tlk`](https://docs.rs/nwnrs-tlk), which resolves the string\n references stored in SSF slot entries\n- [`nwnrs-localization`](https://docs.rs/nwnrs-localization), which defines\n `StrRef` and the language vocabulary used across TLK and SSF\n\n## Why This Crate Exists\n\n`SSF` is a reminder that small file formats can still justify dedicated typed\nmodels. The key fact is not \"it is 20 bytes per entry.\" The key fact is that it\nis a positional dispatch table whose meaning is destroyed if you flatten it into\n\"some list of audio references.\"\n"include_str!("../README.md")]
3mod io;
4mod types;
5
6pub use io::*;
7pub use types::*;
8
9/// Common imports for consumers of this crate.
10pub mod prelude {
11 pub use crate::{SsfEntry, SsfError, SsfResult, SsfRoot, read_ssf, write_ssf};
12}