use crate::error::{Error, Result};
use std::cmp::Ordering;
use std::ops::AddAssign;
#[derive(Clone, Copy, Debug, PartialEq)]
struct Bits(u8);
impl From<u8> for Bits {
fn from(bits: u8) -> Self {
Bits(bits.min(Self::MAX.0))
}
}
impl From<Bits> for u8 {
fn from(bits: Bits) -> Self {
bits.0
}
}
impl AddAssign<u8> for Bits {
fn add_assign(&mut self, rhs: u8) {
self.0 = (self.0 + rhs).min(Self::MAX.0)
}
}
impl Bits {
const MAX: Self = Bits(12);
fn entries(self) -> u16 {
1 << (self.0 as u16)
}
fn mask(self) -> u32 {
(1 << (self.0 as u32)) - 1
}
}
type Code = u16;
#[derive(Clone, Copy, Debug)]
struct CNode {
next: Option<Code>,
left: Option<Code>,
right: Option<Code>,
data: u8,
}
pub struct Compressor {
table: Vec<CNode>,
min_code_bits: u8,
code_bits: Bits,
code: u32,
n_bits: u8,
}
#[derive(Clone, Copy, Debug)]
struct DNode {
parent: Option<Code>,
data: u8,
}
#[derive(Debug)]
pub struct Decompressor {
table: Vec<DNode>,
min_code_bits: u8,
code_bits: Bits,
prefix: Option<Code>,
code: u32,
n_bits: u8,
}
impl CNode {
fn new(next: Option<Code>, data: u8) -> Self {
CNode {
next,
left: None,
right: None,
data,
}
}
fn link(&self, ordering: Ordering) -> Option<Code> {
match ordering {
Ordering::Less => self.left,
Ordering::Equal => self.next,
Ordering::Greater => self.right,
}
}
fn set_link(&mut self, ordering: Ordering, code: Code) {
match ordering {
Ordering::Less => self.left = Some(code),
Ordering::Equal => self.next = Some(code),
Ordering::Greater => self.right = Some(code),
}
}
}
impl Compressor {
pub fn new(min_code_bits: u8) -> Self {
let table = Vec::with_capacity(Bits::MAX.entries().into());
let initial_code_bits = min_code_bits + 1;
let code_bits = Bits::from(initial_code_bits);
let mut com = Compressor {
table,
min_code_bits,
code_bits,
code: 0,
n_bits: 0,
};
com.reset_table();
com
}
fn clear_code(&self) -> Code {
1 << self.min_code_bits
}
fn end_code(&self) -> Code {
self.clear_code() + 1
}
fn next_code(&self) -> Code {
self.table.len() as Code
}
fn reset_table(&mut self) {
self.table.clear();
for data in 0..self.clear_code() {
self.push_node(None, data as u8);
}
self.push_node(None, 0); self.push_node(None, 0); }
fn push_node(&mut self, next: Option<Code>, data: u8) {
self.table.push(CNode::new(next, data))
}
fn node_mut(&mut self, code: Code) -> &mut CNode {
&mut self.table[code as usize]
}
fn pack(&mut self, code: Code, buffer: &mut Vec<u8>) {
self.code |= (code as u32) << self.n_bits;
self.n_bits += u8::from(self.code_bits);
while self.n_bits >= 8 {
buffer.push(self.code as u8);
self.code >>= 8;
self.n_bits -= 8;
}
}
pub fn compress(&mut self, bytes: &[u8], buffer: &mut Vec<u8>) {
self.pack(self.clear_code(), buffer);
let mut code = None;
for data in bytes {
let prefix = self.search_insert(code, *data);
if prefix.is_some() {
code = prefix;
continue;
}
if let Some(code) = code {
self.pack(code, buffer);
}
let next_code = self.next_code();
if next_code > self.code_bits.entries() {
if next_code <= Bits::MAX.entries() {
self.code_bits += 1;
} else {
self.pack(self.clear_code(), buffer);
self.reset_table();
let initial_code_bits = self.min_code_bits + 1;
self.code_bits = Bits::from(initial_code_bits);
}
}
code = Some(*data as Code);
}
if let Some(code) = code {
self.pack(code, buffer);
}
self.pack(self.end_code(), buffer);
}
fn search_insert(&mut self, code: Option<Code>, data: u8) -> Option<Code> {
match code {
Some(code) => self.insert_node(code, data),
None => Some(data as Code),
}
}
fn insert_node(&mut self, code: Code, data: u8) -> Option<Code> {
let next_code = self.next_code();
let mut node = self.node_mut(code);
let mut ordering = Ordering::Equal;
while let Some(code) = node.link(ordering) {
node = self.node_mut(code);
ordering = data.cmp(&node.data);
if ordering == Ordering::Equal {
return Some(code);
}
}
node.set_link(ordering, next_code);
self.push_node(None, data);
None
}
}
impl Decompressor {
pub fn new(min_code_bits: u8) -> Self {
let table = Vec::with_capacity(Bits::MAX.entries().into());
let initial_code_bits = min_code_bits + 1;
let code_bits = Bits::from(initial_code_bits);
let mut dec = Decompressor {
table,
min_code_bits,
code_bits,
prefix: None,
code: 0,
n_bits: 0,
};
dec.reset_table();
dec
}
fn clear_code(&self) -> Code {
1 << self.min_code_bits
}
fn end_code(&self) -> Code {
self.clear_code() + 1
}
fn next_code(&self) -> Code {
self.table.len() as Code
}
fn reset_table(&mut self) {
self.table.clear();
for data in 0..self.clear_code() {
self.push_node(None, data as u8);
}
self.push_node(None, 0); self.push_node(None, 0); }
fn push_node(&mut self, parent: Option<Code>, data: u8) {
self.table.push(DNode { parent, data });
}
fn lookup(&self, code: Code) -> u8 {
let mut node = self.table[code as usize];
while let Some(code) = node.parent {
node = self.table[code as usize];
}
node.data
}
fn unpack(&mut self, buffer: &[u8]) -> (Option<Code>, usize) {
let mut n_consumed = 0;
let code_bits = u8::from(self.code_bits);
for data in buffer {
if self.n_bits >= code_bits {
break;
}
self.code |= (*data as u32) << self.n_bits;
self.n_bits += 8;
n_consumed += 1;
}
if self.n_bits >= code_bits {
let code = (self.code & self.code_bits.mask()) as Code;
self.code >>= code_bits;
self.n_bits -= code_bits;
(Some(code), n_consumed)
} else {
(None, n_consumed)
}
}
pub fn decompress(
&mut self,
bytes: &[u8],
buffer: &mut Vec<u8>,
) -> Result<()> {
let mut bytes = bytes;
while let (Some(code), n_consumed) = self.unpack(bytes) {
self.decompress_code(code, buffer)?;
bytes = &bytes[n_consumed..];
}
Ok(())
}
fn decompress_code(
&mut self,
code: Code,
buffer: &mut Vec<u8>,
) -> Result<()> {
if code == self.clear_code() {
self.reset_table();
let initial_code_bits = self.min_code_bits + 1;
self.code_bits = Bits::from(initial_code_bits);
self.prefix = None;
} else if code == self.end_code() {
self.prefix = None;
} else {
self.decompress_data(code, buffer)?;
self.prefix = Some(code);
}
Ok(())
}
fn decompress_data(
&mut self,
code: Code,
buffer: &mut Vec<u8>,
) -> Result<()> {
let next_code = self.next_code();
if code > next_code {
return Err(Error::InvalidLzwData);
}
match self.prefix {
Some(prefix) => {
let data = if code < next_code {
self.lookup(code)
} else {
self.lookup(prefix)
};
self.push_node(Some(prefix), data);
self.decompress_buffer(code, buffer);
}
None => buffer.push(code as u8),
}
if next_code + 1 == self.code_bits.entries() {
self.code_bits += 1;
}
Ok(())
}
fn decompress_buffer(&self, code: Code, buffer: &mut Vec<u8>) {
let start = buffer.len();
let mut node = self.table[code as usize];
buffer.push(node.data);
while let Some(code) = node.parent {
node = self.table[code as usize];
buffer.push(node.data);
}
buffer[start..].reverse();
}
}