format: resolve shared messages over Storage

Every shared-message entry point has an *_in(&dyn Storage, ..) core:
message_data(_with_sohm), resolve_shared_message(_with_sohm),
resolve_sohm_message, load_sohm_table, and the SMTB/SMLI parsers, which
read the signature and then all entries in one bounded read (the list's
open-ended &file_data[pos..] slice is gone). Object headers and the SOHM
fractal heap are read through their Storage parsers; a SOHM B-tree index
still needs the v2 B-tree over a slice, so over a backend without one it
is a clean ContiguousStorageRequired error. New signature::find_signature_in
probes the candidate offsets with 8-byte reads. The &[u8] functions are
wrappers.

New tests: SOHM tables and lists with 4- and 8-byte offsets, at two
offsets, cut at every length and with a bad signature, parse identically
through a read_at-only CountingStorage in at most two reads; the
signature search matches the slice search.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
osobh
2026-09-26 13:02:58 -05:00
co-authored by Claude Opus 5.5
parent ff6d644391
commit ba3f476be6
2 changed files with 264 additions and 29 deletions
+37
View File
@@ -1,6 +1,7 @@
//! HDF5 file signature (magic bytes) detection.
use crate::error::FormatError;
use crate::storage::{Storage, read_exact_at};
/// The 8-byte HDF5 magic signature.
pub const HDF5_SIGNATURE: [u8; 8] = [0x89, b'H', b'D', b'F', b'\r', b'\n', 0x1A, b'\n'];
@@ -39,6 +40,20 @@ pub fn find_signature(data: &[u8]) -> Result<usize, FormatError> {
Err(FormatError::SignatureNotFound)
}
/// [`find_signature`] over any [`Storage`]: one 8-byte read per candidate
/// offset.
pub fn find_signature_in(file: &dyn Storage) -> Result<u64, FormatError> {
let len = file.len();
let mut offset = 0u64;
while offset.checked_add(8).is_some_and(|end| end <= len) {
if *read_exact_at(file, offset, 8)? == HDF5_SIGNATURE {
return Ok(offset);
}
offset = if offset == 0 { 512 } else { offset * 2 };
}
Err(FormatError::SignatureNotFound)
}
/// Split a file into its user block and its HDF5 bytes.
///
/// Returns `(user_block, hdf5)`: `user_block` is everything before the
@@ -132,4 +147,26 @@ mod tests {
data[512..520].copy_from_slice(&HDF5_SIGNATURE);
assert_eq!(find_signature(&data), Ok(0));
}
#[test]
fn find_signature_in_matches_slice_search() {
use crate::storage::CountingStorage;
for (len, at) in [
(0, None),
(7, None),
(8, Some(0)),
(600, Some(512)),
(5000, Some(4096)),
(3000, Some(2048)),
(3000, None),
] {
let mut data = vec![0u8; len];
if let Some(at) = at {
data[at..at + 8].copy_from_slice(&HDF5_SIGNATURE);
}
let want = find_signature(&data).map(|o| o as u64);
let got = find_signature_in(&CountingStorage::new(data));
assert_eq!(got, want, "{len} {at:?}");
}
}
}