Skip to main content

hdf5_reader/
reference.rs

1//! HDF5 object reference resolution.
2//!
3//! Object references in HDF5 are `offset_size`-byte addresses pointing to
4//! object headers. This module provides utilities for reading and resolving
5//! these references.
6
7use crate::error::{Error, Result};
8use crate::io::Cursor;
9
10/// Read a single object reference (an address) from raw bytes.
11///
12/// Returns the file address of the referenced object header.
13pub fn resolve_object_reference(ref_bytes: &[u8], offset_size: u8) -> Result<u64> {
14    if ref_bytes.len() < offset_size as usize {
15        return Err(Error::InvalidData(format!(
16            "object reference too short: need {} bytes, have {}",
17            offset_size,
18            ref_bytes.len()
19        )));
20    }
21    let mut cursor = Cursor::new(ref_bytes);
22    cursor.read_offset(offset_size)
23}
24
25/// Read an array of object references from raw bytes.
26///
27/// Each reference is `offset_size` bytes. Returns a vector of file addresses.
28pub fn read_object_references(raw_data: &[u8], offset_size: u8) -> Result<Vec<u64>> {
29    let ref_size = offset_size as usize;
30    if ref_size == 0 {
31        return Ok(Vec::new());
32    }
33    let count = raw_data.len() / ref_size;
34    let mut refs = Vec::with_capacity(count);
35    let mut cursor = Cursor::new(raw_data);
36    for _ in 0..count {
37        let addr = cursor.read_offset(offset_size)?;
38        refs.push(addr);
39    }
40    Ok(refs)
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_resolve_object_reference_8byte() {
49        let addr: u64 = 0x1234_5678_9ABC_DEF0;
50        let bytes = addr.to_le_bytes();
51        let result = resolve_object_reference(&bytes, 8).unwrap();
52        assert_eq!(result, addr);
53    }
54
55    #[test]
56    fn test_resolve_object_reference_4byte() {
57        let addr: u32 = 0x1234_5678;
58        let bytes = addr.to_le_bytes();
59        let result = resolve_object_reference(&bytes, 4).unwrap();
60        assert_eq!(result, addr as u64);
61    }
62
63    #[test]
64    fn test_read_object_references() {
65        let mut data = Vec::new();
66        data.extend_from_slice(&0x1000u64.to_le_bytes());
67        data.extend_from_slice(&0x2000u64.to_le_bytes());
68        data.extend_from_slice(&0x3000u64.to_le_bytes());
69
70        let refs = read_object_references(&data, 8).unwrap();
71        assert_eq!(refs, vec![0x1000, 0x2000, 0x3000]);
72    }
73
74    #[test]
75    fn test_read_object_references_4byte() {
76        let mut data = Vec::new();
77        data.extend_from_slice(&0xAAAAu32.to_le_bytes());
78        data.extend_from_slice(&0xBBBBu32.to_le_bytes());
79
80        let refs = read_object_references(&data, 4).unwrap();
81        assert_eq!(refs, vec![0xAAAA, 0xBBBB]);
82    }
83
84    #[test]
85    fn test_too_short_reference() {
86        let data = [0x01, 0x02];
87        let err = resolve_object_reference(&data, 8).unwrap_err();
88        assert!(matches!(err, Error::InvalidData(_)));
89    }
90}