#[cfg(feature = "std")]
pub(crate) mod encoder;
pub(crate) mod tables;
use crate::error::BzzError;
use tables::{LPS_NEXT, MPS_NEXT, PROB, THRESHOLD};
pub(crate) struct ZpDecoder<'a> {
pub(crate) a: u16,
pub(crate) c: u16,
pub(crate) fence: u16,
pub(crate) bit_buf: u32,
pub(crate) bit_count: i32,
pub(crate) data: &'a [u8],
pub(crate) pos: usize,
}
impl<'a> ZpDecoder<'a> {
pub(crate) fn new(data: &'a [u8]) -> Result<Self, BzzError> {
if data.len() < 2 {
return Err(BzzError::TooShort);
}
let mut dec = ZpDecoder {
a: 0,
c: 0,
fence: 0,
bit_buf: 0,
bit_count: 0,
data,
pos: 0,
};
let high = dec.read_byte() as u16;
let low = dec.read_byte() as u16;
dec.c = (high << 8) | low;
dec.refill_buffer();
dec.fence = dec.c.min(0x7fff);
Ok(dec)
}
#[inline(always)]
fn read_byte(&mut self) -> u8 {
if self.pos < self.data.len() {
let b = self.data[self.pos];
self.pos += 1;
b
} else {
0xff
}
}
#[inline(always)]
fn refill_buffer(&mut self) {
while self.bit_count <= 24 {
let byte = self.read_byte();
self.bit_buf = (self.bit_buf << 8) | (byte as u32);
self.bit_count += 8;
}
}
#[inline(always)]
pub(crate) fn decode_bit(&mut self, ctx: &mut u8) -> bool {
let state = *ctx as usize;
let mps_bit = state & 1; let z = self.a as u32 + PROB[state] as u32;
if z <= self.fence as u32 {
self.a = z as u16;
return mps_bit != 0;
}
let boundary = 0x6000u32 + ((self.a as u32 + z) >> 2);
let z_clamped = z.min(boundary);
if z_clamped > self.c as u32 {
let lps_bit = 1 - mps_bit;
let complement = 0x10000u32 - z_clamped;
self.a = self.a.wrapping_add(complement as u16);
self.c = self.c.wrapping_add(complement as u16);
*ctx = LPS_NEXT[state];
self.renormalize();
lps_bit != 0
} else {
if self.a >= THRESHOLD[state] {
*ctx = MPS_NEXT[state];
}
self.bit_count -= 1;
self.a = (z_clamped << 1) as u16;
self.c = ((self.c as u32) << 1 | ((self.bit_buf >> self.bit_count as u32) & 1)) as u16;
if self.bit_count < 16 {
self.refill_buffer();
}
self.fence = self.c.min(0x7fff);
mps_bit != 0
}
}
pub(crate) fn is_exhausted(&self) -> bool {
self.pos >= self.data.len()
}
#[inline(always)]
pub(crate) fn decode_passthrough(&mut self) -> bool {
let z = 0x8000u16.wrapping_add(self.a >> 1);
self.passthrough_with_threshold(z)
}
#[inline(always)]
pub(crate) fn decode_passthrough_iw44(&mut self) -> bool {
let z = (0x8000u32 + (3u32 * self.a as u32) / 8) as u16;
self.passthrough_with_threshold(z)
}
#[inline(always)]
fn passthrough_with_threshold(&mut self, z: u16) -> bool {
if z > self.c {
let complement = 0x10000u32 - z as u32;
self.a = self.a.wrapping_add(complement as u16);
self.c = self.c.wrapping_add(complement as u16);
self.renormalize();
true
} else {
self.bit_count -= 1;
self.a = z.wrapping_mul(2);
self.c = ((self.c as u32) << 1 | ((self.bit_buf >> self.bit_count as u32) & 1)) as u16;
if self.bit_count < 16 {
self.refill_buffer();
}
self.fence = self.c.min(0x7fff);
false
}
}
#[inline(always)]
fn renormalize(&mut self) {
let shift = self.a.leading_ones();
self.bit_count -= shift as i32;
self.a = ((self.a as u32) << shift) as u16;
let mask = (1u32 << shift) - 1;
self.c =
((self.c as u32) << shift | ((self.bit_buf >> self.bit_count as u32) & mask)) as u16;
if self.bit_count < 16 {
self.refill_buffer();
}
self.fence = self.c.min(0x7fff);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::BzzError;
#[test]
fn zp_decoder_rejects_empty_input() {
assert!(matches!(ZpDecoder::new(&[]), Err(BzzError::TooShort)));
}
#[test]
fn zp_decoder_rejects_one_byte_input() {
assert!(matches!(ZpDecoder::new(&[0x00]), Err(BzzError::TooShort)));
}
#[test]
fn zp_decoder_accepts_two_byte_input() {
assert!(ZpDecoder::new(&[0x00, 0x00]).is_ok());
assert!(ZpDecoder::new(&[0xff, 0xff]).is_ok());
}
#[test]
fn zp_tables_spot_check() {
assert_eq!(PROB[0], 0x8000);
assert_eq!(PROB[250], 0x481a);
assert_eq!(MPS_NEXT[0], 84);
assert_eq!(LPS_NEXT[0], 145);
assert_eq!(THRESHOLD[83], 0);
assert_eq!(THRESHOLD[250], 0);
}
}