use crate::bitreader::BitReader;
use crate::bwt;
use crate::huffman::HuffmanTree;
use crate::mtf::MtfDecoder;
use std::cell::RefCell;
const MAX_BLOCKSIZE: usize = 900_000;
const MAX_SELECTORS: usize = 18002;
thread_local! {
static TT_POOL: RefCell<Vec<Vec<u32>>> = const { RefCell::new(Vec::new()) };
static OUT_POOL: RefCell<Vec<Vec<u8>>> = const { RefCell::new(Vec::new()) };
}
fn take_tt_buffer(capacity: usize) -> Vec<u32> {
let mut buf = TT_POOL.with(|cell| cell.borrow_mut().pop()).unwrap_or_default();
buf.clear();
if buf.capacity() < capacity {
buf.reserve(capacity - buf.len());
}
buf
}
fn return_tt_buffer(buf: Vec<u32>) {
TT_POOL.with(|cell| cell.borrow_mut().push(buf));
}
fn take_out_buffer() -> Vec<u8> {
OUT_POOL.with(|cell| cell.borrow_mut().pop()).unwrap_or_default()
}
fn return_out_buffer(buf: Vec<u8>) {
OUT_POOL.with(|cell| cell.borrow_mut().push(buf));
}
#[derive(Debug)]
pub struct BlockError(pub &'static str);
impl std::fmt::Display for BlockError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "bzip2 block error: {}", self.0)
}
}
impl std::error::Error for BlockError {}
const fn make_crc_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut i = 0usize;
while i < 256 {
let mut c = (i as u32) << 24;
let mut k = 0;
while k < 8 {
c = if c & 0x8000_0000 != 0 { (c << 1) ^ 0x04C1_1DB7 } else { c << 1 };
k += 1;
}
table[i] = c;
i += 1;
}
table
}
static CRC_TABLE: [u32; 256] = make_crc_table();
pub(crate) fn block_crc(data: &[u8]) -> u32 {
let mut crc: u32 = 0xFFFF_FFFF;
for &b in data {
crc = crc_update(crc, b);
}
!crc
}
#[inline(always)]
fn crc_update(crc: u32, b: u8) -> u32 {
(crc << 8) ^ CRC_TABLE[(((crc >> 24) ^ (b as u32)) & 0xFF) as usize]
}
fn decode_block_common(
reader: &mut BitReader<'_>,
max_blocksize: u32,
) -> Result<(Vec<u32>, u32, u32), BlockError> {
let expected_crc = reader.read_u32(32)
.ok_or(BlockError("block CRC truncated"))?;
let randomised = reader.read_bit()
.ok_or(BlockError("randomised flag truncated"))?;
if randomised {
return Err(BlockError("randomised blocks not supported"));
}
let orig_ptr = reader.read_u32(24)
.ok_or(BlockError("orig_ptr truncated"))? as usize;
let mut used_bytes = [0u8; 256];
let mut n_used: usize = 0;
let mut ranges_present = [false; 16];
for range in &mut ranges_present {
*range = reader.read_bit()
.ok_or(BlockError("symbol range truncated"))?;
}
for (range_idx, &present) in ranges_present.iter().enumerate() {
if !present { continue; }
for sub in 0..16u8 {
if reader.read_bit().ok_or(BlockError("symbol bitmap truncated"))? {
used_bytes[n_used] = range_idx as u8 * 16 + sub;
n_used += 1;
}
}
}
if n_used == 0 {
return Err(BlockError("no symbols in block"));
}
let n_symbols = n_used + 2;
let n_groups = reader.read_u8(3)
.ok_or(BlockError("huffman groups truncated"))?;
if n_groups < 2 || n_groups > 6 {
return Err(BlockError("invalid number of huffman groups"));
}
let n_selectors = reader.read_u16(15)
.ok_or(BlockError("selectors_used truncated"))? as usize;
if n_selectors > MAX_SELECTORS {
return Err(BlockError("too many selectors"));
}
let mut selectors = [0u8; MAX_SELECTORS];
let mut sel_mtf = MtfDecoder::new();
for i in 0..n_selectors {
let mut trees = 0u8;
while reader.read_bit().ok_or(BlockError("selector bit truncated"))? {
trees += 1;
if trees >= n_groups {
return Err(BlockError("selector tree index too large"));
}
}
selectors[i] = sel_mtf.decode(trees);
}
let mut trees = [const { HuffmanTree::empty() }; 6];
let mut n_trees: usize = 0;
for _ in 0..n_groups {
let mut length = reader.read_u8(5)
.ok_or(BlockError("huffman start length truncated"))? as i32;
let mut lengths = [0u8; 258];
for j in 0..n_symbols {
loop {
if length < 1 || length > 20 {
return Err(BlockError("huffman code length out of range"));
}
if !reader.read_bit().ok_or(BlockError("length adjust bit1 truncated"))? {
break;
}
if reader.read_bit().ok_or(BlockError("length adjust bit2 truncated"))? {
length -= 1;
} else {
length += 1;
}
}
lengths[j] = length as u8;
}
trees[n_trees] = HuffmanTree::from_lengths(&lengths[..n_symbols])
.map_err(|_| BlockError("invalid huffman tree"))?;
n_trees += 1;
}
let mut tt: Vec<u32> = take_tt_buffer(max_blocksize as usize);
debug_assert!(tt.capacity() >= max_blocksize as usize);
let tt_ptr = tt.as_mut_ptr();
let mut tt_len: usize = 0; let mut c = [0u32; 256];
let mut byte_symbols = [0u8; 256];
byte_symbols[..n_used].copy_from_slice(&used_bytes[..n_used]);
let mut mtf = MtfDecoder::with_symbols(byte_symbols);
let mut sel_idx: usize = 0;
let mut current_tree = &trees[
selectors[0] as usize
];
let mut repeat: u32 = 0;
let mut repeat_power: u32 = 0;
let eob_symbol = (n_symbols - 1) as u16;
'outer: loop {
for _ in 0..50 {
let sym = current_tree.decode(reader)
.ok_or(BlockError("huffman bitstream truncated"))?;
if sym < 2 {
if repeat == 0 {
repeat_power = 1;
}
repeat += repeat_power << sym;
repeat_power <<= 1;
if repeat as usize > MAX_BLOCKSIZE {
return Err(BlockError("repeat count too large"));
}
continue;
}
if repeat > 0 {
let b = mtf.first();
if tt_len + repeat as usize > max_blocksize as usize {
return Err(BlockError("data exceeds block size"));
}
let val = u32::from(b);
unsafe {
let mut p = tt_ptr.add(tt_len);
for _ in 0..repeat {
p.write(val);
p = p.add(1);
}
}
tt_len += repeat as usize;
c[b as usize] += repeat;
repeat = 0;
}
if sym == eob_symbol {
break 'outer;
}
let b = mtf.decode((sym - 1) as u8);
if tt_len >= max_blocksize as usize {
return Err(BlockError("data exceeds block size"));
}
unsafe { tt_ptr.add(tt_len).write(u32::from(b)); }
tt_len += 1;
c[b as usize] += 1;
}
sel_idx += 1;
if sel_idx >= n_selectors {
return Err(BlockError("ran out of selectors"));
}
let sel = selectors[sel_idx] as usize;
if sel >= n_trees {
return Err(BlockError("selector out of range"));
}
current_tree = &trees[sel];
}
unsafe { tt.set_len(tt_len); }
if orig_ptr >= tt_len {
return Err(BlockError("orig_ptr out of bounds"));
}
let t_pos = bwt::inverse_bwt(&mut tt, orig_ptr, c)
.ok_or(BlockError("inverse-BWT: inconsistent byte counts (corrupt or mis-decoded block)"))?;
Ok((tt, t_pos, expected_crc))
}
fn rle2_decode_append(tt: &[u32], mut t_pos: u32, out: &mut Vec<u8>) -> u32 {
let n = tt.len();
let start = out.len();
out.reserve(n + n / 4 + 1);
let mut out_len: usize = start;
let tt_ptr = tt.as_ptr();
let mut base = out.as_mut_ptr();
let mut cap = out.capacity();
let mut crc: u32 = 0xFFFF_FFFF;
let mut last_byte: u16 = 0x100;
let mut byte_repeats: u8 = 0;
for _ in 0..n {
let entry = unsafe { *tt_ptr.add(t_pos as usize) };
let b = entry as u8;
t_pos = entry >> 8;
if byte_repeats == 3 {
let count = b as usize;
if out_len + count + n > cap {
unsafe { out.set_len(out_len); }
out.reserve(count + n + 1);
base = out.as_mut_ptr();
cap = out.capacity();
}
let ch = last_byte as u8;
unsafe {
std::ptr::write_bytes(base.add(out_len), ch, count);
}
let mut i = 0;
while i < count {
crc = crc_update(crc, ch);
i += 1;
}
out_len += count;
byte_repeats = 0;
last_byte = 0x100; continue;
}
if last_byte == b as u16 {
byte_repeats += 1;
} else {
byte_repeats = 0;
}
last_byte = b as u16;
crc = crc_update(crc, b);
unsafe { *base.add(out_len) = b; }
out_len += 1;
}
unsafe { out.set_len(out_len); }
!crc
}
fn rle2_decode_alloc(tt: &[u32], t_pos: u32) -> (Vec<u8>, u32) {
let mut output = Vec::new();
let crc = rle2_decode_append(tt, t_pos, &mut output);
(output, crc)
}
pub(crate) struct BlockCore {
tt: Vec<u32>,
t_pos: u32,
crc: u32,
}
pub(crate) fn decode_block_core(
reader: &mut BitReader<'_>,
max_blocksize: u32,
) -> Result<BlockCore, BlockError> {
let (tt, t_pos, crc) = decode_block_common(reader, max_blocksize)?;
Ok(BlockCore { tt, t_pos, crc })
}
struct Chain {
tt_ptr: *const u32,
t_pos: u32,
remaining: u32,
pending: u32,
out: Vec<u8>,
out_len: usize,
base: *mut u8,
cap: usize,
last_byte: u16,
byte_repeats: u8,
n: usize,
order: u32,
crc: u32,
crc_acc: u32,
tt: Vec<u32>,
}
#[inline(always)]
fn chain_process(c: &mut Chain, entry: u32) {
let b = entry as u8;
if c.byte_repeats == 3 {
let count = b as usize;
if c.out_len + count + c.n > c.cap {
unsafe { c.out.set_len(c.out_len); }
c.out.reserve(count + c.n + 1);
c.base = c.out.as_mut_ptr();
c.cap = c.out.capacity();
}
let ch = c.last_byte as u8;
unsafe {
std::ptr::write_bytes(c.base.add(c.out_len), ch, count);
}
let mut crc = c.crc_acc;
let mut i = 0;
while i < count {
crc = crc_update(crc, ch);
i += 1;
}
c.crc_acc = crc;
c.out_len += count;
c.byte_repeats = 0;
c.last_byte = 0x100;
return;
}
if c.last_byte == b as u16 {
c.byte_repeats += 1;
} else {
c.byte_repeats = 0;
}
c.last_byte = b as u16;
c.crc_acc = crc_update(c.crc_acc, b);
unsafe { *c.base.add(c.out_len) = b; }
c.out_len += 1;
}
#[inline]
fn lockstep(active: &mut [Chain], steps: u32) {
for _ in 0..steps {
for c in active.iter_mut() {
let e = unsafe { *c.tt_ptr.add(c.t_pos as usize) };
c.t_pos = e >> 8;
c.pending = e;
}
for c in active.iter_mut() {
let e = c.pending;
chain_process(c, e);
}
}
for c in active.iter_mut() {
c.remaining -= steps;
}
}
fn chase_all(chains: &mut [Chain]) {
chains.sort_by_key(|c| c.remaining);
let k = chains.len();
let mut done = 0usize;
while done < k {
if chains[done].remaining == 0 {
done += 1;
continue;
}
let step = chains[done].remaining;
lockstep(&mut chains[done..k], step);
while done < k && chains[done].remaining == 0 {
done += 1;
}
}
}
pub(crate) fn decode_blocks_interleaved(
cores: &mut Vec<BlockCore>,
output: &mut Vec<u8>,
block_crcs: &mut Vec<u32>,
) -> Result<(), BlockError> {
let m = cores.len();
let mut chains: Vec<Chain> = Vec::with_capacity(m);
for (i, core) in cores.drain(..).enumerate() {
let tt = core.tt;
let n = tt.len();
let tt_ptr = tt.as_ptr();
let mut out = take_out_buffer();
out.clear();
out.reserve(n + n / 4 + 1);
let base = out.as_mut_ptr();
let cap = out.capacity();
chains.push(Chain {
tt_ptr,
t_pos: core.t_pos,
remaining: n as u32,
pending: 0,
out,
out_len: 0,
base,
cap,
last_byte: 0x100,
byte_repeats: 0,
n,
order: i as u32,
crc: core.crc,
crc_acc: 0xFFFF_FFFF,
tt,
});
}
chase_all(&mut chains);
chains.sort_by_key(|c| c.order);
for c in chains.iter_mut() {
unsafe { c.out.set_len(c.out_len); }
}
let mut err: Option<BlockError> = None;
for c in chains.into_iter() {
if err.is_none() {
if !c.crc_acc != c.crc {
err = Some(BlockError("block CRC mismatch"));
} else {
output.extend_from_slice(&c.out);
block_crcs.push(c.crc);
}
}
return_tt_buffer(c.tt);
return_out_buffer(c.out);
}
match err {
Some(e) => Err(e),
None => Ok(()),
}
}
pub fn decode_block(reader: &mut BitReader<'_>, max_blocksize: u32) -> Result<Vec<u8>, BlockError> {
let (tt, t_pos, expected_crc) = decode_block_common(reader, max_blocksize)?;
let (output, crc) = rle2_decode_alloc(&tt, t_pos);
return_tt_buffer(tt);
if crc != expected_crc {
return Err(BlockError("block CRC mismatch"));
}
Ok(output)
}
pub fn decode_block_into(reader: &mut BitReader<'_>, max_blocksize: u32, out: &mut Vec<u8>) -> Result<(usize, u32), BlockError> {
let (tt, t_pos, expected_crc) = decode_block_common(reader, max_blocksize)?;
let start = out.len();
let crc = rle2_decode_append(&tt, t_pos, out);
return_tt_buffer(tt);
let written = out.len() - start;
if crc != expected_crc {
out.truncate(start);
return Err(BlockError("block CRC mismatch"));
}
Ok((written, expected_crc))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decode_known_block() {
let compressed = include_bytes!("../test_data/hello.bz2");
let expected = b"Hello, World!\n";
assert_eq!(&compressed[..3], b"BZh");
let level = compressed[3] - b'0';
let max_blocksize = 100_000 * level as u32;
let mut reader = BitReader::from_bit_offset(compressed, 4 * 8);
let magic = reader.read_u64(48).unwrap();
assert_eq!(magic, crate::BLOCK_MAGIC, "expected block magic");
let output = decode_block(&mut reader, max_blocksize).unwrap();
assert_eq!(&output, expected);
}
}