Expand description
Building blocks for reading game files: checked byte reading, the hashes game files key their names by, vertex
layouts and attribute decoding, an ordered parallel map, sRGB and texture-sampling arithmetic, and (behind the
compress feature) the compression codecs games store their data in.
The readers and decoders work on borrowed bytes and return a value or an error rather than panicking on malformed
input; the library modules do no file, environment or process access (the one exception, loading a native Oodle
library the caller names, is in compress::oodle). Each module states its conventions (byte order, normalization,
rounding) in its own documentation, because file formats differ on exactly those points.
bytes: bounds-checkedViewandCursorreaders. The byte order is stated on every multi-byte read, and a refused read reports the absolute offset it was at.hash: CRC-32, Adler-32 (from any start value), Jenkins one-at-a-time (case-folded and exact), MD5 with its block function exposed, and SDBM. Inputs are never normalized.vertex: DXGI vertex element formats, layouts with explicit or appended offsets, stream decoding, packed positions and tangents, and triangle-strip and index-buffer helpers.parallel: an ordered, panic-safe parallel map over independent items, with the thread count passed in.scan(Unix and Windows): many stored entries of a few large files read in the files’ own order, in large (on Windows unbuffered) reads on a stated number of threads, each entry handed to the caller on the thread that read it: the whole-archive pass. The one module that reads files, by the paths its caller names.color: the sRGB transfer curve inf64andf32and its byte forms.sampling: texture sampling as GPUs define it: address modes, point, bilinear and trilinear filtering, level of detail, 2D and 3D.compress(featurecompress): oneDecompressor/Compressorinterface over LZ4, deflate, zlib, zstd, LZMA, Brotli, LZO1X, LZO2A and Oodle, and a frame-by-frame LZX decoder. Every decode takes the exact expected output size and refuses anything else.sqlite(featuresqlite): the tables of an SQLite 3 file image read whole, a table’s columns and every row’s typed values, refusing what it does not read (a write-ahead log, aWITHOUT ROWIDtable, a damaged b-tree).
§Example
Read a small made-up record, then see what a truncated copy of it reports:
use primase_foundations::bytes::{Cursor, Endian, Field};
use primase_foundations::hash::crc32;
// "DATA", a little-endian count of 2-byte entries, then the entries
let file = [b'D', b'A', b'T', b'A', 2, 0, 0, 0, 0x34, 0x12, 0x78, 0x56];
let mut cursor = Cursor::new(&file);
assert_eq!(cursor.take(4)?, b"DATA");
let count = cursor.count(Endian::Little, 2)?; // refused unless that many entries fit
let mut entries = Vec::new();
for _ in 0..count {
entries.push(cursor.u16(Endian::Little)?);
}
assert_eq!(entries, [0x1234, 0x5678]);
assert_eq!(crc32(b"123456789"), 0xcbf4_3926);
// cut short, the read is refused with the field and the offset
let mut cut = Cursor::new(&file[..6]);
cut.take(4)?;
let refusal = cut.count(Endian::Little, 2).field("entry count").unwrap_err();
assert_eq!(refusal.to_string(), "entry count at 0x4: 4 bytes run past the end of 6");Modules§
- bytes
- Bounds-checked reading of fixed-size numbers and byte spans from a borrowed slice. Every read either returns the
value or a
BoundsError(or, once a name is attached withField::field, aFieldError) that says where the read was and how far it ran past the data; nothing here panics on short input. - color
- The IEC sRGB transfer curve both ways, in f64 and in f32 (one definition, evaluated at the precision the caller asks for), and the byte forms: a stored sRGB byte to linear light from a 256-entry table, and linear light to the nearest sRGB byte from a table of the curve’s rounding thresholds (the curve’s own byte for every input).
- hash
- The hashes game files key names and checksums by: CRC-32, Adler-32 from any start value, Jenkins one-at-a-time (with and without case folding), MD5 (including its block function, for formats that pad differently) and SDBM. The byte functions never normalize their input: no trimming, no path-separator or case changes beyond what a function’s own name says.
- parallel
- Independent items worked on a stated number of threads (
Threads), with the serial result. - sampling
- Sampling a decoded texture: each policy the caller’s, stated. Bilinear filtering between texel centres (a texel
icovering[i, i + 1),uvscaled by the level’s size, minus a half), each axis’s address mode (a border reads the colour the caller states,Addressing), the colour’s transfer before filtering, at a level the caller picks. Two precisions, each a fixed order of operations: f64 (Levels::bilinear) and f32 over texels decoded once (Decoded::bilinear). The texel a coordinate falls in (Levels::point,Decoded::point). A level of detail from a sample’s footprint (footprint_lod), and the two levels around it mixed (Levels::trilinear) or the nearest one taken (Levels::nearest_level). - scan
- Many stored entries of a few large files, read in the files’ own order: the whole-archive pass of a census, an index build or an extraction.
- vertex
- Decoding vertex data: DXGI element formats, layouts, vertex streams, quantized and packed attributes, and the triangle-strip and index-buffer helpers a mesh converter needs.
Constants§
- SOURCES
- This crate’s source files as
(name, bytes), for a caller that keys a disk cache by the code that computed its values: hashing them retires cached entries when any of them changes. A test keeps the list equal to thesrcfolder.