extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::Error;
use crate::traits::{RawEncoder, RawProgress};
use super::bits::BitWriter;
use super::bwt::bwt_forward;
use super::crc::Crc32;
use super::huffman::{MAX_CODE_LEN, build_canonical_codes, build_canonical_lengths};
use super::mtf::mtf_forward_reduced;
use super::rle::{rle1_forward, rle2_forward};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EncoderConfig {
pub level: u8,
}
impl Default for EncoderConfig {
fn default() -> Self {
Self { level: 6 }
}
}
const BLOCK_MAGIC: u64 = 0x3141_5926_5359; const STREAM_END_MAGIC: u64 = 0x1772_4538_5090;
const MAX_SELECTORS: usize = 18002;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Phase {
Accepting,
Flushed,
Done,
}
pub struct Encoder {
config: EncoderConfig,
pending: Vec<u8>,
out: Vec<u8>,
out_idx: usize,
header_written: bool,
combined_crc: u32,
bw: Option<BitWriter>,
phase: Phase,
}
impl Encoder {
pub fn new() -> Self {
Self::with_config(EncoderConfig::default())
}
pub fn with_config(mut config: EncoderConfig) -> Self {
config.level = config.level.clamp(1, 9);
Self {
config,
pending: Vec::new(),
out: Vec::new(),
out_idx: 0,
header_written: false,
combined_crc: 0,
bw: None,
phase: Phase::Accepting,
}
}
fn block_input_cap(&self) -> usize {
(self.config.level as usize) * 100_000 - 19
}
fn ensure_header(&mut self) {
if self.header_written {
return;
}
self.out.push(b'B');
self.out.push(b'Z');
self.out.push(b'h');
self.out.push(b'0' + self.config.level);
self.bw = Some(BitWriter::new());
self.header_written = true;
}
fn encode_block(&mut self) {
let block: Vec<u8> = core::mem::take(&mut self.pending);
debug_assert!(!block.is_empty());
let mut crc = Crc32::new();
crc.update(&block);
let block_crc = crc.value();
self.combined_crc = self.combined_crc.rotate_left(1) ^ block_crc;
let rle1 = rle1_forward(&block);
let (l_column, origin) = bwt_forward(&rle1);
let mut present = [false; 256];
for &b in &l_column {
present[b as usize] = true;
}
let alphabet: Vec<u8> = (0..=255u8).filter(|&b| present[b as usize]).collect();
let num_used = alphabet.len();
let mtf = mtf_forward_reduced(&l_column, &alphabet);
drop(l_column);
let mut symbols = rle2_forward(&mtf, num_used);
let eob_symbol: u16 = (num_used as u16) + 1;
symbols.push(eob_symbol);
drop(mtf);
let alpha_size = num_used + 2; let num_tables = pick_num_tables(symbols.len());
let num_selectors_total = symbols.len().div_ceil(50);
debug_assert!(num_selectors_total >= 1);
debug_assert!(num_selectors_total <= MAX_SELECTORS);
let mut freqs = vec![0u32; alpha_size];
for &s in &symbols {
freqs[s as usize] += 1;
}
let table_lengths = build_canonical_lengths(&freqs, MAX_CODE_LEN);
let tables: Vec<Vec<u8>> = (0..num_tables).map(|_| table_lengths.clone()).collect();
let selectors: Vec<u8> = vec![0u8; num_selectors_total];
let codes: Vec<Vec<u32>> = tables
.iter()
.map(|lens| build_canonical_codes(lens))
.collect();
let bw = self.bw.as_mut().expect("header must be written first");
bw.write_bits_48(BLOCK_MAGIC);
bw.write_bits(32, block_crc);
bw.write_bit(0);
bw.write_bits(24, origin);
let mut stripe_used = [false; 16];
for &b in &alphabet {
stripe_used[(b >> 4) as usize] = true;
}
let mut stripe_top: u16 = 0;
for (i, &u) in stripe_used.iter().enumerate() {
if u {
stripe_top |= 1 << (15 - i);
}
}
bw.write_bits(16, stripe_top as u32);
for (stripe, &used) in stripe_used.iter().enumerate() {
if !used {
continue;
}
let mut mask: u16 = 0;
for byte in 0..16 {
let candidate = (stripe << 4) | byte;
if present[candidate] {
mask |= 1 << (15 - byte);
}
}
bw.write_bits(16, mask as u32);
}
bw.write_bits(3, num_tables as u32);
bw.write_bits(15, num_selectors_total as u32);
let mut mtf_list: Vec<u8> = (0..num_tables as u8).collect();
for &sel in &selectors {
let mut pos = 0;
while mtf_list[pos] != sel {
pos += 1;
}
for _ in 0..pos {
bw.write_bit(1);
}
bw.write_bit(0);
if pos > 0 {
let v = mtf_list.remove(pos);
mtf_list.insert(0, v);
}
}
for table in &tables {
let mut cur = table[0] as i32;
bw.write_bits(5, cur as u32);
for &l in table.iter() {
let target = l as i32;
while cur != target {
if target > cur {
bw.write_bit(1);
bw.write_bit(0);
cur += 1;
} else {
bw.write_bit(1);
bw.write_bit(1);
cur -= 1;
}
}
bw.write_bit(0);
}
}
let mut group_idx = 0usize;
let mut i = 0usize;
while i < symbols.len() {
let end = (i + 50).min(symbols.len());
let sel = selectors[group_idx] as usize;
let lens = &tables[sel];
let cds = &codes[sel];
for &s in &symbols[i..end] {
let len = lens[s as usize] as u32;
let code = cds[s as usize];
bw.write_bits(len, code);
}
group_idx += 1;
i = end;
}
drop(tables);
drop(codes);
drop(selectors);
}
fn drain_out(&mut self, output: &mut [u8], written: &mut usize) {
let avail = self.out.len() - self.out_idx;
let space = output.len() - *written;
let n = avail.min(space);
if n > 0 {
output[*written..*written + n]
.copy_from_slice(&self.out[self.out_idx..self.out_idx + n]);
self.out_idx += n;
*written += n;
}
if self.out_idx == self.out.len() {
self.out.clear();
self.out_idx = 0;
}
}
fn flush_full_bytes(&mut self) {
if let Some(ref mut bw) = self.bw {
let taken = core::mem::replace(bw, BitWriter::new());
let (bytes, cur, nbits) = bw_internals(taken);
self.out.extend_from_slice(&bytes);
*bw = bw_rehydrate(cur, nbits);
}
}
fn write_footer(&mut self) {
let bw = self.bw.as_mut().expect("header must be written first");
bw.write_bits_48(STREAM_END_MAGIC);
bw.write_bits(32, self.combined_crc);
bw.align_to_byte();
let taken = core::mem::replace(bw, BitWriter::new());
let (bytes, _, _) = bw_internals(taken);
self.out.extend_from_slice(&bytes);
self.bw = None;
}
}
fn bw_internals(bw: BitWriter) -> (Vec<u8>, u8, u8) {
bw.internals_for_encoder()
}
fn bw_rehydrate(cur: u8, nbits: u8) -> BitWriter {
BitWriter::rehydrate(cur, nbits)
}
fn pick_num_tables(n_symbols: usize) -> usize {
if n_symbols < 200 {
2
} else if n_symbols < 600 {
3
} else if n_symbols < 1200 {
4
} else if n_symbols < 2400 {
5
} else {
6
}
}
impl Default for Encoder {
fn default() -> Self {
Self::new()
}
}
impl RawEncoder for Encoder {
fn raw_encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error> {
if matches!(self.phase, Phase::Done | Phase::Flushed) {
return Ok(RawProgress {
consumed: 0,
written: 0,
done: false,
});
}
self.ensure_header();
let cap = self.block_input_cap();
let mut consumed = 0usize;
let mut written = 0usize;
self.drain_out(output, &mut written);
if written == output.len() && !self.out.is_empty() {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
while consumed < input.len() {
let space = cap - self.pending.len();
let take = space.min(input.len() - consumed);
self.pending
.extend_from_slice(&input[consumed..consumed + take]);
consumed += take;
if self.pending.len() == cap {
self.encode_block();
self.flush_full_bytes();
self.drain_out(output, &mut written);
if written == output.len() && !self.out.is_empty() {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
}
}
Ok(RawProgress {
consumed,
written,
done: false,
})
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
let mut written = 0usize;
self.ensure_header();
self.drain_out(output, &mut written);
if !self.out.is_empty() {
return Ok(RawProgress {
consumed: 0,
written,
done: false,
});
}
if matches!(self.phase, Phase::Accepting) {
if !self.pending.is_empty() {
self.encode_block();
self.flush_full_bytes();
}
self.write_footer();
self.phase = Phase::Flushed;
self.drain_out(output, &mut written);
if !self.out.is_empty() {
return Ok(RawProgress {
consumed: 0,
written,
done: false,
});
}
}
if matches!(self.phase, Phase::Flushed) {
self.drain_out(output, &mut written);
if self.out.is_empty() {
self.phase = Phase::Done;
}
}
Ok(RawProgress {
consumed: 0,
written,
done: matches!(self.phase, Phase::Done),
})
}
fn raw_reset(&mut self) {
self.pending.clear();
self.out.clear();
self.out_idx = 0;
self.header_written = false;
self.combined_crc = 0;
self.bw = None;
self.phase = Phase::Accepting;
}
}