///|
/// Non-owning reader over byte arrays. Values outside 0..255 are masked so
/// generated fixtures and host-provided byte arrays behave consistently.
pub(all) struct ByteReader {
bytes : Array[Int]
offset : Int
} derive(Eq, @debug.Debug)
///|
pub fn ByteReader::new(bytes : Array[Int]) -> ByteReader {
{ bytes, offset: 0 }
}
///|
pub fn ByteReader::at(bytes : Array[Int], offset : Int) -> ByteReader {
{ bytes, offset }
}
///|
pub fn ByteReader::length(self : ByteReader) -> Int {
self.bytes.length()
}
///|
pub fn ByteReader::remaining(self : ByteReader) -> Int {
self.bytes.length() - self.offset
}
///|
pub fn ByteReader::can_read(self : ByteReader, count : Int) -> Bool {
count >= 0 && self.offset >= 0 && self.offset + count <= self.bytes.length()
}
///|
pub fn ByteReader::slice_can_read(
self : ByteReader,
offset : Int,
count : Int,
) -> Bool {
offset >= 0 && count >= 0 && offset + count <= self.bytes.length()
}
///|
pub fn ByteReader::byte_at(self : ByteReader, offset : Int) -> Int {
if self.slice_can_read(offset, 1) {
self.bytes[offset] & 0xff
} else {
0
}
}
///|
pub fn ByteReader::u16_le_at(self : ByteReader, offset : Int) -> Int {
self.byte_at(offset) | (self.byte_at(offset + 1) << 8)
}
///|
pub fn ByteReader::u32_le_at(self : ByteReader, offset : Int) -> Int {
self.byte_at(offset) |
(self.byte_at(offset + 1) << 8) |
(self.byte_at(offset + 2) << 16) |
(self.byte_at(offset + 3) << 24)
}
///|
pub fn ByteReader::fourcc_at(self : ByteReader, offset : Int) -> String {
if !self.slice_can_read(offset, 4) {
""
} else {
String::from_array([
self.byte_at(offset).to_uint16().unsafe_to_char(),
self.byte_at(offset + 1).to_uint16().unsafe_to_char(),
self.byte_at(offset + 2).to_uint16().unsafe_to_char(),
self.byte_at(offset + 3).to_uint16().unsafe_to_char(),
])
}
}
///|
pub fn ByteReader::matches_u16(
self : ByteReader,
offset : Int,
value : Int,
) -> Bool {
self.slice_can_read(offset, 2) && self.u16_le_at(offset) == value
}
///|
pub fn ByteReader::ascii_z_at(
self : ByteReader,
offset : Int,
limit : Int,
) -> String {
if offset < 0 || limit <= 0 || offset >= self.length() {
""
} else {
let end = if offset + limit <= self.length() {
offset + limit
} else {
self.length()
}
for i in offset..= 32 && b <= 126 {
continue acc + String::from_array([b.to_uint16().unsafe_to_char()])
} else {
continue acc
}
} nobreak {
acc
}
}
}
///|
pub fn ByteReader::ascii_fixed_at(
self : ByteReader,
offset : Int,
size : Int,
) -> String {
if size <= 0 || !self.slice_can_read(offset, size) {
""
} else {
for i in 0..= 32 && b <= 126 {
continue acc + String::from_array([b.to_uint16().unsafe_to_char()])
} else {
continue acc
}
} nobreak {
acc
}
}
}
///|
pub fn ByteReader::slice(
self : ByteReader,
offset : Int,
size : Int,
) -> Array[Int] {
if !self.slice_can_read(offset, size) {
[]
} else {
Array::makei(size, i => self.byte_at(offset + i))
}
}