fix(format): read datasets and attributes that use committed datatypes

A dataset created from a committed (named) datatype stores only a shared-
message reference to it. The facade parsed those reference bytes as the
datatype itself, producing `Time { size: 0 }` and unreadable data, and an
attribute using a committed datatype was silently dropped.

- shared_message::parse_shared_ref had the encoding wrong: it skipped six
  reserved bytes for version 2 (only version 1 has them) and had the version 3
  types inverted (1 is the SOHM heap, 2 is "committed, in another object
  header"). Verified against h5py 3.16 / HDF5 2.0, which writes
  `02 02 <address>` under both default and latest libver bounds. Resolution
  now dispatches on which field the reference carries.
- New shared_message::message_data resolves a header message through the
  indirection; the reader, lazy and mmap facades use it for datatype,
  dataspace and filter-pipeline messages.
- AttributeMessage honours the v2/v3 flags (bit 0 datatype shared, bit 1
  dataspace shared) via the new parse_in_file, used everywhere file data is
  available. Parsing a shared attribute without file access is now
  FormatError::UnresolvedSharedMessage instead of a garbage datatype.
- h5py interop test covering both libver settings.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
osobh
2026-09-19 06:31:17 -07:00
co-authored by Claude Fable 5.1
parent 0eca8574f5
commit 81e8294048
7 changed files with 374 additions and 103 deletions
+7
View File
@@ -114,6 +114,9 @@ pub enum FormatError {
InvalidAttributeInfoVersion(u8),
/// Invalid shared message version.
InvalidSharedMessageVersion(u8),
/// A message is marked shared but was parsed without access to the file,
/// so the reference to the real message could not be followed.
UnresolvedSharedMessage,
/// Invalid SOHM table version.
InvalidSohmTableVersion(u8),
/// Invalid SOHM table signature (expected "SMTB").
@@ -307,6 +310,10 @@ impl fmt::Display for FormatError {
FormatError::InvalidSharedMessageVersion(v) => {
write!(f, "invalid shared message version: {v}")
}
FormatError::UnresolvedSharedMessage => write!(
f,
"message is shared but no file data was available to resolve it"
),
FormatError::InvalidSohmTableVersion(v) => {
write!(f, "invalid SOHM table version: {v}")
}