///|
fn Image::data_block(
self : Image,
at : Int,
descriptor : UInt,
limit : Int,
) -> Bytes raise SquashError {
let key = "\{at}:\{descriptor}:\{limit}"
if self.data_cache.get(key) is Some(bytes) {
return bytes
}
guard (descriptor & 0xfe000000U) == 0U else {
raise Invalid(at, "reserved data block bits")
}
let size = (descriptor & 0xffffffU).reinterpret_as_int()
guard size > 0 && size <= self.superblock.block_size else {
raise Invalid(at, "invalid stored data size")
}
guard at >= 96 &&
at <= self.superblock.inode_table &&
size <= self.superblock.inode_table - at else {
raise Invalid(at, "data overlaps inode table")
}
let b = self.range(at, size)
let decoded = if (descriptor & 0x1000000U) != 0U {
b
} else {
(self.decode)(self.superblock.compression, b, limit)
}
guard decoded.length() > 0 && decoded.length() <= limit else {
raise Invalid(at, "invalid decoded data length")
}
if self.data_cache.length() >= 16 {
self.data_cache.clear()
}
self.data_cache[key] = decoded
decoded
}
///|
pub fn Image::read_file(
self : Image,
file : Inode,
max_bytes? : Int = 67108864,
) -> Bytes raise SquashError {
guard file.content is File(start, size, fragment, fragment_offset, blocks) else {
raise Invalid(file.number, "not a regular file")
}
guard max_bytes >= 0 && size <= max_bytes else {
raise Limit("file output exceeds max_bytes")
}
let out : Array[Byte] = []
let mut at = start
for descriptor in blocks {
let expected = Int::min(self.superblock.block_size, size - out.length())
if descriptor == 0U {
for _ in 0..