pub mod bits;
pub mod block;
pub mod bwt;
pub mod crc;
pub mod mtf;
pub mod parallel;
mod read;
pub mod rle;
pub mod stream;
#[cfg(feature = "python")]
mod python;
pub use parallel::StreamDecoder;
pub use read::{scan, BlockSpan, BzReader, Scan};
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Kernels {
pub avx2: bool,
pub clmul: bool,
}
impl Kernels {
pub const fn scalar() -> Self {
Kernels {
avx2: false,
clmul: false,
}
}
pub fn detect() -> Self {
#[cfg(target_arch = "x86_64")]
{
Kernels {
avx2: std::is_x86_feature_detected!("avx2")
&& std::is_x86_feature_detected!("bmi1"),
clmul: std::is_x86_feature_detected!("pclmulqdq")
&& std::is_x86_feature_detected!("sse4.1")
&& std::is_x86_feature_detected!("ssse3"),
}
}
#[cfg(not(target_arch = "x86_64"))]
{
Kernels::scalar()
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ErrorKind {
Empty,
NotBz2,
BadBlockMagic,
Randomised,
BadOrigPtr,
NoSymbols,
BadGroups,
BadSelectors,
BadSelector,
BadCodeLength,
BadHuffmanCode,
SelectorOverrun,
RunTooLong,
BlockTooLong,
RunUnfinished,
BlockCrc {
stored: u32,
computed: u32,
},
StreamCrc {
stored: u32,
computed: u32,
},
Truncated,
TrailingData,
BlockTooLarge,
RangeOvershoot,
Cancelled,
Io(std::io::ErrorKind, String),
Internal(String),
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ErrorKind::Empty => write!(f, "no input: not a bzip2 file"),
ErrorKind::NotBz2 => write!(f, "not a bzip2 file (no BZh1-9 stream header)"),
ErrorKind::BadBlockMagic => write!(f, "bad block header magic"),
ErrorKind::Randomised => write!(
f,
"a randomised block (written only by bzip2 0.9.0 and earlier): not supported by this decoder"
),
ErrorKind::BadOrigPtr => write!(f, "the block's primary index is out of range"),
ErrorKind::NoSymbols => write!(f, "the block uses no symbols"),
ErrorKind::BadGroups => write!(f, "the block's number of Huffman tables is not 2-6"),
ErrorKind::BadSelectors => write!(f, "the block has no selectors"),
ErrorKind::BadSelector => write!(f, "a selector names no Huffman table"),
ErrorKind::BadCodeLength => write!(f, "a Huffman code length is not 1-20"),
ErrorKind::BadHuffmanCode => write!(f, "a Huffman code is not in its table"),
ErrorKind::SelectorOverrun => write!(f, "the block's symbols outrun its selectors"),
ErrorKind::RunTooLong => write!(f, "a RUNA/RUNB run is too long"),
ErrorKind::BlockTooLong => write!(f, "the block is longer than its stream's level allows"),
ErrorKind::RunUnfinished => write!(f, "the block ends inside an RLE1 run (4 equal bytes, no count)"),
ErrorKind::BlockCrc { stored, computed } => {
write!(f, "block CRC mismatch (stored {stored:#010x}, computed {computed:#010x})")
}
ErrorKind::StreamCrc { stored, computed } => {
write!(f, "stream CRC mismatch (stored {stored:#010x}, computed {computed:#010x})")
}
ErrorKind::Truncated => write!(f, "unexpected end of input (truncated)"),
ErrorKind::TrailingData => write!(f, "trailing data after the last bzip2 stream"),
ErrorKind::BlockTooLarge => write!(f, "a block's compressed form is over 64 MiB"),
ErrorKind::RangeOvershoot => write!(f, "the last block runs past the range's end"),
ErrorKind::Cancelled => write!(f, "cancelled"),
ErrorKind::Io(_, m) => write!(f, "reading the input: {m}"),
ErrorKind::Internal(m) => write!(f, "internal error: {m}"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub block: Option<u64>,
pub bit: Option<u64>,
}
impl Error {
pub fn new(kind: ErrorKind) -> Self {
Error {
kind,
block: None,
bit: None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "bz2 data error: {}", self.kind)?;
match (self.block, self.bit) {
(Some(b), Some(at)) => write!(f, " (block {b}, at bit {at} = byte {})", at / 8),
(None, Some(at)) => write!(f, " (at bit {at} = byte {})", at / 8),
(Some(b), None) => write!(f, " (block {b})"),
_ => Ok(()),
}
}
}
impl std::error::Error for Error {}
impl From<Error> for std::io::Error {
fn from(e: Error) -> Self {
let kind = match &e.kind {
ErrorKind::Io(k, _) => *k,
ErrorKind::Cancelled => std::io::ErrorKind::Interrupted,
_ => std::io::ErrorKind::InvalidData,
};
std::io::Error::new(kind, e)
}
}
pub struct Scratch<I: bwt::InverseBwt = bwt::Segmented> {
ll: Vec<u8>,
counts: [u32; 256],
inverse: I,
rle: Vec<u8>,
}
impl<I: bwt::InverseBwt> Default for Scratch<I> {
fn default() -> Self {
Scratch {
ll: Vec::new(),
counts: [0; 256],
inverse: I::default(),
rle: Vec::new(),
}
}
}
pub fn decode_block<I: bwt::InverseBwt>(
b: &block::Symbols,
k: Kernels,
s: &mut Scratch<I>,
out: &mut Vec<u8>,
) -> Result<u32, ErrorKind> {
let n = mtf::mtf(b, &mut s.ll, &mut s.counts, k)?;
if b.orig_ptr as usize >= n {
return Err(ErrorKind::BadOrigPtr);
}
s.inverse.invert(&s.ll, &s.counts, b.orig_ptr, &mut s.rle);
let start = out.len();
if let Err(kind) = rle::unrle(&s.rle, out, k) {
out.truncate(start);
return Err(kind);
}
let computed = crc::crc32(&out[start..], k);
if computed != b.crc {
out.truncate(start);
return Err(ErrorKind::BlockCrc {
stored: b.crc,
computed,
});
}
Ok(computed)
}
pub fn decode(data: &[u8]) -> Result<Vec<u8>, Error> {
decode_with::<bwt::Segmented>(data, Kernels::detect())
}
pub fn decode_parallel(data: &[u8], threads: usize) -> Result<Vec<u8>, Error> {
let dec = StreamDecoder::new(threads, 2 * threads.max(1), Kernels::detect());
let mut out = Vec::with_capacity(data.len().saturating_mul(4));
std::thread::scope(|s| {
s.spawn(|| {
for c in data.chunks(4 << 20) {
if dec.write(c.to_vec()).is_err() {
return;
}
}
dec.close();
});
let mut buf = vec![0u8; 4 << 20];
let res = loop {
match dec.read(&mut buf) {
Ok(0) => break Ok(()),
Ok(n) => out.extend_from_slice(&buf[..n]),
Err(e) => break Err(e),
}
};
dec.cancel();
res
})?;
Ok(out)
}
pub fn decode_with<I: bwt::InverseBwt>(data: &[u8], k: Kernels) -> Result<Vec<u8>, Error> {
let mut sc = stream::Scanner::new(stream::SliceSource(data));
let mut out = Vec::new();
let mut s = Scratch::<I>::default();
let mut syms = Vec::new();
loop {
match sc.next(syms)? {
stream::Event::Block {
index,
bit,
symbols,
..
} => {
decode_block(&symbols, k, &mut s, &mut out).map_err(|kind| Error {
kind,
block: Some(index),
bit: Some(bit),
})?;
syms = symbols.syms;
}
stream::Event::Done => return Ok(out),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Range {
pub blocks: Vec<(u64, u64, u32)>,
pub end: u64,
pub stream_end: bool,
pub stored_combined: u32,
}
pub fn decode_blocks(
data: &[u8],
start_bit: u64,
end_bit: u64,
level: u32,
k: Kernels,
out: &mut Vec<u8>,
) -> Result<Range, Error> {
let mut s = Scratch::<bwt::Segmented>::default();
let mut syms = Vec::new();
let mut range = Range {
end: start_bit,
..Range::default()
};
let mut bit = start_bit;
while bit < end_bit {
let index = range.blocks.len() as u64;
let at = |kind| Error {
kind,
block: Some(index),
bit: Some(bit),
};
let mut br = bits::Bits::at(data, bit);
let item = block::read_item(&mut br, level, syms);
if br.overran() {
return Err(at(ErrorKind::Truncated));
}
let next = br.bit_pos();
match item.map_err(|(kind, _)| at(kind))? {
block::Item::End(crc) => {
range.stream_end = true;
range.stored_combined = crc;
range.end = next;
return Ok(range);
}
block::Item::Block(b) => {
if next > end_bit {
return Err(at(ErrorKind::RangeOvershoot));
}
let crc = decode_block(&b, k, &mut s, out).map_err(at)?;
range.blocks.push((bit, next, crc));
syms = b.syms;
}
}
bit = next;
range.end = bit;
}
Ok(range)
}
pub fn combine(crcs: impl IntoIterator<Item = u32>) -> u32 {
crcs.into_iter().fold(0, |c, b| c.rotate_left(1) ^ b)
}