///|
/// A parsed HDF5 local heap.
priv struct LocalHeap {
bytes : Bytes
data_address : Int32
data_size : Int32
}
///|
fn parse_local_heap(
bytes : Bytes,
address : UInt64,
offset_size : Int32,
length_size : Int32,
base_address : UInt64,
) -> LocalHeap raise Hdf5Error {
let absolute = address_to_offset(address, base_address)
let reader = Reader::at(bytes, absolute)
let signature = reader.read_bytes(4)
guard signature == b"HEAP" else {
raise InvalidField("expected HEAP signature")
}
let version = reader.read_u8().to_int()
guard version == 0 else {
raise InvalidField("unsupported local heap version")
}
reader.skip(3)
let stored_size = reader.read_uint_le(length_size)
guard stored_size <= 0x7FFFFFFFUL else {
raise InvalidField("local heap size is too large")
}
let data_size = stored_size.to_int()
let _offset_to_free_list = reader.read_uint_le(length_size)
let data_address = address_to_offset(
reader.read_uint_le(offset_size),
base_address,
)
Reader::new(bytes).sub(data_address, data_size) |> ignore
{ bytes, data_address, data_size, }
}
///|
/// Reads a null-terminated UTF-8 string from the local heap data segment.
fn LocalHeap::get_string(
self : LocalHeap,
offset : UInt64,
) -> String raise Hdf5Error {
guard self.data_address >= 0 &&
self.data_address <= self.bytes.length() &&
self.data_size >= 0 &&
self.data_size <= self.bytes.length() - self.data_address else {
raise InvalidField("local heap data segment outside input")
}
guard offset < self.data_size.to_uint64() else {
raise InvalidField("local heap string offset outside data segment")
}
let start = self.data_address + offset.to_int()
let end = self.data_address + self.data_size
let mut cursor = start
while cursor < end && self.bytes.unsafe_get(cursor) != b'\x00' {
cursor = cursor + 1
}
guard cursor < end else {
raise InvalidField("unterminated local heap string")
}
let view = self.bytes.get_view(start~, end=cursor).unwrap()
@utf8.decode(view) catch {
_ => raise InvalidField("invalid UTF-8 string in local heap")
}
}