///|
pub(all) enum Endian {
Little
Big
} derive(Eq)
///|
pub extend Endian with Eq::{equal, not_equal}
///|
pub extend Endian with Show::{output, to_string}
///|
pub impl Show for Endian with fn output(self, logger) {
logger.write_string(if self == Little { "little" } else { "big" })
}
///|
priv struct Reader {
bytes : Bytes
endian : Endian
}
///|
/// All binary reads check bounds before accessing bytes.
fn Reader::bits(
self : Reader,
offset : Int,
width : Int,
) -> UInt64 raise NiftiError {
require(
offset >= 0 &&
width >= 1 &&
width <= 8 &&
offset <= self.bytes.length() - width,
"truncated",
offset~,
)
let mut result = 0UL
for j in 0.. Int raise NiftiError {
let n = self.bits(offset, 2).to_int()
if n >= 32768 {
n - 65536
} else {
n
}
}
///|
fn Reader::i32(self : Reader, offset : Int) -> Int raise NiftiError {
self.bits(offset, 4).to_uint().reinterpret_as_int()
}
///|
fn Reader::f32(self : Reader, offset : Int) -> Double raise NiftiError {
Float::reinterpret_from_uint(self.bits(offset, 4).to_uint()).to_double()
}
///|
fn Reader::f64(self : Reader, offset : Int) -> Double raise NiftiError {
self.bits(offset, 8).reinterpret_as_double()
}
///|
fn put_bits(
out : FixedArray[Byte],
endian : Endian,
offset : Int,
width : Int,
value : UInt64,
) -> Unit {
for j in 0..> shift) & 255UL).to_byte()
}
}
///|
fn put_i16(
out : FixedArray[Byte],
e : Endian,
offset : Int,
value : Int,
) -> Unit {
put_bits(out, e, offset, 2, value.to_uint64())
}
///|
fn put_f32(
out : FixedArray[Byte],
e : Endian,
offset : Int,
value : Double,
) -> Unit raise NiftiError {
let f = Float::from_double(value)
require(finite(value) && !f.is_inf(), "header_float_overflow", offset~)
put_bits(out, e, offset, 4, f.reinterpret_as_uint().to_uint64())
}
///|
fn copy_bytes(bytes : Bytes, start : Int, count : Int) -> Bytes {
Bytes::makei(count, i => bytes[start + i])
}
///|
fn checked_product(a : Int, b : Int, limit : Int) -> Int raise NiftiError {
require(a > 0 && b > 0 && a <= limit / b, "size_limit")
a * b
}