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:
@@ -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:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user