// The literals section of a compressed block (RFC 8878 section 3.1.1.3.1).
///|
/// Makes `literals` hold at least `n` bytes.
fn Decoder::reserve_literals(self : Decoder, n : Int32) -> Unit {
if self.literals.length() < n {
self.literals = FixedArray::make(n, b'\x00')
}
}
///|
/// Decodes the literals section at the start of `block[0:size]` into
/// `literals[0:literals_len]`. Returns where the sequences section starts.
fn Decoder::decode_literals(self : Decoder, size : Int32) -> Int32 raise Stop {
let block = self.block
let b0 = block[0].to_int()
let block_type = b0 & 3
let size_format = (b0 >> 2) & 3
if block_type < 2 {
// Raw or RLE: a 1-, 2- or 3-byte header with the regenerated size.
let (header, regenerated) = match size_format {
0 | 2 => (1, b0 >> 3)
1 => {
if size < 2 {
raise corrupt("a literals header past its block")
}
(2, (b0 >> 4) + (block[1].to_int() << 4))
}
_ => {
if size < 3 {
raise corrupt("a literals header past its block")
}
(3, (b0 >> 4) + (block[1].to_int() << 4) + (block[2].to_int() << 12))
}
}
if regenerated > self.block_max {
raise corrupt("more literals than the block limit")
}
self.reserve_literals(regenerated)
self.literals_len = regenerated
if block_type == 0 {
if header + regenerated > size {
raise corrupt("raw literals past their block")
}
FixedArray::unsafe_blit(self.literals, 0, block, header, regenerated)
return header + regenerated
}
if header + 1 > size {
raise corrupt("RLE literals past their block")
}
self.literals.fill(block[header], start=0, end=regenerated)
return header + 1
}
// Compressed or treeless: both sizes, in 10, 14 or 18 bits each.
let (header, width) = match size_format {
0 | 1 => (3, 10)
2 => (4, 14)
_ => (5, 18)
}
if size < header {
raise corrupt("a literals header past its block")
}
let mut fields : UInt64 = 0
for i = header - 1; i >= 0; i = i - 1 {
fields = (fields << 8) | block[i].to_uint64()
}
let mask = (1UL << width) - 1
let regenerated = ((fields >> 4) & mask).to_int()
let compressed = ((fields >> (4 + width)) & mask).to_int()
if regenerated > self.block_max {
raise corrupt("more literals than the block limit")
}
let end = header + compressed
if end > size {
raise corrupt("compressed literals past their block")
}
let mut streams = header
if block_type == 2 {
streams += self.huffman.read(block, header, end, self.scratch)
self.huffman_valid = true
} else if !self.huffman_valid {
raise corrupt("treeless literals before any Huffman table")
}
self.reserve_literals(regenerated)
self.literals_len = regenerated
self.huffman.decode(
block,
streams,
end,
self.literals,
regenerated,
size_format != 0,
)
end
}