// ByteReader:定长字节流上的顺序/随机读取。
//
// ISO 9660 的数值字段大多是「both-endian」(小端 4 字节 + 大端 4 字节各一份),
// 因此这里同时提供单端与双端读取,供上层按结构体字段选择。
///|
pub struct ByteReader {
data : Bytes
mut pos : Int32
}
///|
pub fn ByteReader::new(data : Bytes) -> ByteReader {
{ data, pos: 0, }
}
///|
pub fn ByteReader::position(self : ByteReader) -> Int32 {
self.pos
}
///|
pub fn ByteReader::remaining(self : ByteReader) -> Int32 {
self.data.length() - self.pos
}
///|
pub fn ByteReader::seek(self : ByteReader, pos : Int32) -> Unit raise IsoError {
if pos < 0 || pos > self.data.length() {
raise Truncated
}
self.pos = pos
}
///|
pub fn ByteReader::skip(self : ByteReader, n : Int32) -> Unit raise IsoError {
self.seek(self.pos + n)
}
///|
pub fn ByteReader::read_u8(self : ByteReader) -> UInt32 raise IsoError {
if self.remaining() < 1 {
raise Truncated
}
let v = self.data[self.pos].to_uint()
self.pos += 1
v
}
///|
pub fn ByteReader::read_u16_le(self : ByteReader) -> Int32 raise IsoError {
let a = self.read_u8().reinterpret_as_int()
let b = self.read_u8().reinterpret_as_int()
a | (b << 8)
}
///|
pub fn ByteReader::read_u16_be(self : ByteReader) -> Int32 raise IsoError {
let a = self.read_u8().reinterpret_as_int()
let b = self.read_u8().reinterpret_as_int()
(a << 8) | b
}
///|
pub fn ByteReader::read_u32_le(self : ByteReader) -> Int32 raise IsoError {
let a = self.read_u8().reinterpret_as_int()
let b = self.read_u8().reinterpret_as_int()
let c = self.read_u8().reinterpret_as_int()
let d = self.read_u8().reinterpret_as_int()
a | (b << 8) | (c << 16) | (d << 24)
}
///|
pub fn ByteReader::read_u32_be(self : ByteReader) -> Int32 raise IsoError {
let a = self.read_u8().reinterpret_as_int()
let b = self.read_u8().reinterpret_as_int()
let c = self.read_u8().reinterpret_as_int()
let d = self.read_u8().reinterpret_as_int()
(a << 24) | (b << 16) | (c << 8) | d
}
///|
/// ISO 9660 的 both-endian 4 字节整数:前 4 字节小端,后 4 字节大端。
/// 两份必须一致,否则映像结构不可信。
pub fn ByteReader::read_u32_both(self : ByteReader) -> Int32 raise IsoError {
let le = self.read_u32_le()
let be = self.read_u32_be()
if le != be {
raise BadBothEndian
}
le
}
///|
pub fn ByteReader::read_u16_both(self : ByteReader) -> Int32 raise IsoError {
let le = self.read_u16_le()
let be = self.read_u16_be()
if le != be {
raise BadBothEndian
}
le
}
///|
pub fn ByteReader::read_bytes(
self : ByteReader,
n : Int32,
) -> Bytes raise IsoError {
if n < 0 || self.remaining() < n {
raise Truncated
}
let out = FixedArray::make(n, b'\x00')
for i = 0; i < n; i = i + 1 {
out[i] = self.data[self.pos + i]
}
self.pos += n
Bytes::from_array(out[:])
}
///|
/// 读取定长 ASCII 字段:遇 NUL 截断,尾部空格忽略。
pub fn ByteReader::read_ascii(
self : ByteReader,
n : Int32,
) -> String raise IsoError {
let raw = self.read_bytes(n)
let mut out = ""
for i = 0; i < n; i = i + 1 {
let b = raw[i].to_uint().reinterpret_as_int()
if b == 0 {
break
}
out = out + Int32::unsafe_to_char(b).to_string()
}
out.trim_end().to_owned()
}
///|
/// 把逻辑块号换算成字节偏移。用 64 位中间量:32 位乘法会回绕,
/// 回绕后仍可能落进映像范围,从而"读出错误数据"而不是报错。
pub fn block_offset(
block : Int32,
block_size : Int32,
limit : Int32,
) -> Int32 raise IsoError {
if block < 0 || block_size <= 0 {
raise Truncated
}
let off = block.to_int64() * block_size.to_int64()
if off < 0 || off + block_size.to_int64() > limit.to_int64() {
raise Truncated
}
off.to_int()
}
///|
/// 校验 [block*block_size, block*block_size+size) 落在映像内,返回字节偏移。
pub fn extent_offset(
block : Int32,
size : Int32,
block_size : Int32,
limit : Int32,
) -> Int32 raise IsoError {
if block < 0 || size < 0 || block_size <= 0 {
raise Truncated
}
let off = block.to_int64() * block_size.to_int64()
let end = off + size.to_int64()
if off < 0 || end > limit.to_int64() {
raise Truncated
}
off.to_int()
}