Skip to main content

Crate primase_foundations

Crate primase_foundations 

Source
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-checked View and Cursor readers. 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 in f64 and f32 and its byte forms.
  • sampling: texture sampling as GPUs define it: address modes, point, bilinear and trilinear filtering, level of detail, 2D and 3D.
  • compress (feature compress): one Decompressor / Compressor interface 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 (feature sqlite): 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, a WITHOUT ROWID table, 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 with Field::field, a FieldError) 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 i covering [i, i + 1), uv scaled 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 the src folder.