#![cfg_attr(docsrs, doc(cfg(feature = "zip_shrink")))]
extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::Error;
use crate::traits::{Algorithm, RawDecoder, RawEncoder, RawProgress};
#[derive(Debug, Clone, Copy, Default)]
pub struct ZipShrink;
impl Algorithm for ZipShrink {
const NAME: &'static str = "zip-shrink";
type Encoder = Encoder;
type Decoder = Decoder;
type EncoderConfig = ();
type DecoderConfig = ();
fn encoder_with(_: ()) -> Encoder {
Encoder::new()
}
fn decoder_with(_: ()) -> Decoder {
Decoder::new()
}
}
const HSIZE: usize = 1 << 13;
const BOGUS: u16 = 256;
const INIT_BITS: u8 = 9;
const MAX_BITS: u8 = 13;
const FREE: u16 = 0xFFFF;
const LITERAL: u16 = 0xFFFE;
#[derive(Debug, Default)]
pub struct Encoder;
impl Encoder {
pub const fn new() -> Self {
Self
}
}
impl RawEncoder for Encoder {
fn raw_encode(&mut self, _input: &[u8], _output: &mut [u8]) -> Result<RawProgress, Error> {
Err(Error::Unsupported)
}
fn raw_finish(&mut self, _output: &mut [u8]) -> Result<RawProgress, Error> {
Err(Error::Unsupported)
}
fn raw_reset(&mut self) {}
}
#[derive(Debug)]
pub struct Decoder {
header_pos: u8,
target_len: u64,
bit_acc: u32,
bit_count: u8,
in_buf: Vec<u8>,
in_pos: usize,
n_bits: u8,
parent: Vec<u16>,
value: Vec<u8>,
last_free: u16,
old_code: u16,
final_char: u8,
emit_buf: Vec<u8>,
emit_head: usize,
out_pos: u64,
stack: Vec<u8>,
has_child: Vec<bool>,
completed: bool,
pending_control: bool,
}
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
impl Decoder {
pub fn new() -> Self {
let mut parent = vec![FREE; HSIZE];
let mut value = vec![0u8; HSIZE];
for c in 0..256u16 {
parent[c as usize] = LITERAL;
value[c as usize] = c as u8;
}
parent[BOGUS as usize] = LITERAL;
Self {
header_pos: 0,
target_len: 0,
bit_acc: 0,
bit_count: 0,
in_buf: Vec::new(),
in_pos: 0,
n_bits: INIT_BITS,
parent,
value,
last_free: BOGUS,
old_code: u16::MAX,
final_char: 0,
emit_buf: Vec::new(),
emit_head: 0,
out_pos: 0,
stack: Vec::with_capacity(HSIZE),
has_child: vec![false; HSIZE],
completed: false,
pending_control: false,
}
}
fn compact_in_buf(&mut self) {
if self.in_pos >= 4096 && self.in_pos == self.in_buf.len() {
self.in_buf.clear();
self.in_pos = 0;
} else if self.in_pos >= 64 * 1024 {
self.in_buf.drain(0..self.in_pos);
self.in_pos = 0;
}
}
fn try_read_code(&mut self) -> Option<u16> {
let need = self.n_bits as u32;
while self.bit_count < need as u8 {
if self.in_pos >= self.in_buf.len() {
return None;
}
self.bit_acc |= (self.in_buf[self.in_pos] as u32) << self.bit_count;
self.bit_count += 8;
self.in_pos += 1;
}
let mask = (1u32 << need) - 1;
let code = (self.bit_acc & mask) as u16;
self.bit_acc >>= need;
self.bit_count -= need as u8;
Some(code)
}
fn emit_string(&mut self, code: u16) -> Result<u8, Error> {
self.stack.clear();
let mut c = code;
if self.parent[c as usize] == FREE {
self.stack.push(self.final_char);
c = self.old_code;
if c == u16::MAX {
return Err(Error::Corrupt);
}
}
let mut hops = 0usize;
loop {
let p = self.parent[c as usize];
if p == LITERAL {
self.stack.push(self.value[c as usize]);
break;
}
if p == FREE {
self.stack.push(self.final_char);
c = self.old_code;
if c == u16::MAX {
return Err(Error::Corrupt);
}
} else {
self.stack.push(self.value[c as usize]);
c = p;
}
hops += 1;
if hops > HSIZE {
return Err(Error::Corrupt);
}
}
let first = *self.stack.last().ok_or(Error::Corrupt)?;
while let Some(b) = self.stack.pop() {
self.emit_buf.push(b);
}
Ok(first)
}
fn partial_clear(&mut self) {
for m in self.has_child.iter_mut() {
*m = false;
}
let last = self.last_free as usize;
for code in (BOGUS as usize + 1)..=last {
let par = self.parent[code];
if par == FREE || par == LITERAL {
continue;
}
if par > BOGUS {
self.has_child[par as usize] = true;
}
}
for code in (BOGUS as usize + 1)..=last {
if !self.has_child[code] {
self.parent[code] = FREE;
}
}
self.last_free = BOGUS;
}
fn next_free_slot(&mut self) -> Option<u16> {
let mut s = self.last_free as usize + 1;
while s < HSIZE && self.parent[s] != FREE {
s += 1;
}
if s >= HSIZE { None } else { Some(s as u16) }
}
fn drain_emit(&mut self, out: &mut [u8]) -> usize {
let available = self.emit_buf.len() - self.emit_head;
let n = available.min(out.len());
out[..n].copy_from_slice(&self.emit_buf[self.emit_head..self.emit_head + n]);
self.emit_head += n;
if self.emit_head == self.emit_buf.len() {
self.emit_buf.clear();
self.emit_head = 0;
}
n
}
fn pump(&mut self) -> Result<(), Error> {
loop {
if self.completed {
return Ok(());
}
if self.emit_buf.len() - self.emit_head > 16 * 1024 {
return Ok(());
}
let saved_acc = self.bit_acc;
let saved_cnt = self.bit_count;
let saved_pos = self.in_pos;
let code = match self.try_read_code() {
Some(c) => c,
None => {
self.bit_acc = saved_acc;
self.bit_count = saved_cnt;
self.in_pos = saved_pos;
return Ok(());
}
};
if self.pending_control {
self.pending_control = false;
match code {
1 => {
if self.n_bits >= MAX_BITS {
return Err(Error::Corrupt);
}
self.n_bits += 1;
}
2 => {
self.partial_clear();
}
_ => return Err(Error::Corrupt),
}
continue;
}
if code == BOGUS {
self.pending_control = true;
continue;
}
if (code as usize) >= HSIZE {
return Err(Error::Corrupt);
}
if self.old_code == u16::MAX {
if code >= BOGUS {
return Err(Error::Corrupt);
}
self.final_char = code as u8;
self.emit_buf.push(self.final_char);
self.old_code = code;
continue;
}
let new_final = self.emit_string(code)?;
let new_code = self.next_free_slot();
if let Some(nc) = new_code {
self.parent[nc as usize] = self.old_code;
self.value[nc as usize] = new_final;
self.last_free = nc;
} else {
return Err(Error::Corrupt);
}
self.final_char = new_final;
self.old_code = code;
}
}
}
impl RawDecoder for Decoder {
fn raw_decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<RawProgress, Error> {
let mut consumed = 0usize;
let mut written = 0usize;
while self.header_pos < 4 && consumed < input.len() {
let b = input[consumed];
consumed += 1;
self.target_len |= (b as u64) << (8 * self.header_pos as u64);
self.header_pos += 1;
}
if self.header_pos < 4 {
return Ok(RawProgress {
consumed,
written,
done: false,
});
}
if self.target_len == 0 {
self.completed = true;
}
self.in_buf.extend_from_slice(&input[consumed..]);
consumed = input.len();
self.pump()?;
let remaining_target = self.target_len.saturating_sub(self.out_pos);
let cap = output.len().min(remaining_target as usize);
if cap > 0 && self.emit_head < self.emit_buf.len() {
let n = self.drain_emit(&mut output[..cap]);
written += n;
self.out_pos += n as u64;
if self.out_pos >= self.target_len {
self.completed = true;
}
}
self.compact_in_buf();
Ok(RawProgress {
consumed,
written,
done: self.completed,
})
}
fn raw_finish(&mut self, output: &mut [u8]) -> Result<RawProgress, Error> {
let mut written = 0usize;
if self.header_pos < 4 {
if self.header_pos == 0 && self.in_buf.is_empty() && self.emit_buf.is_empty() {
return Err(Error::UnexpectedEnd);
}
return Err(Error::UnexpectedEnd);
}
if !self.completed {
self.pump()?;
}
let remaining_target = self.target_len.saturating_sub(self.out_pos);
let cap = output.len().min(remaining_target as usize);
if cap > 0 && self.emit_head < self.emit_buf.len() {
let n = self.drain_emit(&mut output[..cap]);
written += n;
self.out_pos += n as u64;
}
if self.out_pos >= self.target_len {
self.completed = true;
return Ok(RawProgress {
consumed: 0,
written,
done: true,
});
}
if self.emit_head >= self.emit_buf.len() {
return Err(Error::UnexpectedEnd);
}
Ok(RawProgress {
consumed: 0,
written,
done: false,
})
}
fn raw_reset(&mut self) {
self.header_pos = 0;
self.target_len = 0;
self.bit_acc = 0;
self.bit_count = 0;
self.in_buf.clear();
self.in_pos = 0;
self.n_bits = INIT_BITS;
for c in 0..HSIZE {
self.parent[c] = FREE;
self.value[c] = 0;
}
for c in 0..256u16 {
self.parent[c as usize] = LITERAL;
self.value[c as usize] = c as u8;
}
self.parent[BOGUS as usize] = LITERAL;
self.last_free = BOGUS;
self.old_code = u16::MAX;
self.final_char = 0;
self.emit_buf.clear();
self.emit_head = 0;
self.out_pos = 0;
self.stack.clear();
for m in self.has_child.iter_mut() {
*m = false;
}
self.completed = false;
self.pending_control = false;
}
}