use super::decode::{self, Resume, Status};
use super::tables::Tables;
use super::wrapper::{body_start, trailer_len, Check, HeaderParser};
use super::Error;
use crate::Format;
pub(super) const WINDOW: usize = 32 * 1024;
const CARRY_LEN: usize = 1024;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Stage {
Header,
Body,
Trailer,
Done,
}
enum Step {
Continue,
NeedInput,
Full,
Done,
}
pub(super) struct Run {
pub(super) consumed: usize,
pub(super) start: usize,
pub(super) done: bool,
pub(super) full: bool,
}
#[derive(PartialEq, Eq)]
enum Stop {
Done,
NeedInput,
Full,
}
#[derive(Clone)]
pub(super) struct Core<const WRITE: bool> {
format: Format,
tables: Tables,
stage: Stage,
resume: Resume,
fresh: bool,
pos: usize,
carry: [u8; CARRY_LEN],
carry_len: usize,
header: HeaderParser,
trailer: [u8; 8],
trailer_len: usize,
check: Check,
total_in: u64,
total_out: u64,
}
impl<const WRITE: bool> Core<WRITE> {
const fn new(format: Format) -> Self {
Core {
format,
tables: Tables::new(),
stage: Stage::Header,
resume: Resume::START,
fresh: true,
pos: 0,
carry: [0; CARRY_LEN],
carry_len: 0,
header: HeaderParser::new(),
trailer: [0; 8],
trailer_len: 0,
check: Self::new_check(format),
total_in: 0,
total_out: 0,
}
}
const fn new_check(format: Format) -> Check {
if WRITE {
Check::new(format)
} else {
Check::len_only(format)
}
}
fn restart(&mut self) {
self.stage = Stage::Header;
self.resume = Resume::START;
self.fresh = true;
self.pos = 0;
self.carry_len = 0;
self.header = HeaderParser::new();
self.trailer_len = 0;
self.check = Self::new_check(self.format);
self.total_in = 0;
self.total_out = 0;
}
#[cfg_attr(not(feature = "std"), allow(dead_code))]
pub(super) fn pos(&self) -> usize {
self.pos
}
pub(super) fn run(&mut self, input: &[u8], buf: &mut [u8], end: bool) -> Result<Run, Error> {
if self.stage == Stage::Done {
self.restart();
}
let start = self.pos;
let mut ip = 0;
let r = self.steps(input, &mut ip, buf, end);
self.total_in += ip as u64;
match r {
Ok(stop) => {
let done = stop == Stop::Done;
if done {
self.stage = Stage::Done;
}
Ok(Run {
consumed: ip,
start,
done,
full: stop == Stop::Full,
})
}
Err(e) => {
self.stage = Stage::Done;
Err(e)
}
}
}
fn can_run_whole(&self) -> bool {
self.stage == Stage::Done || (self.stage == Stage::Header && self.total_in == 0)
}
#[inline(never)]
fn run_whole(&mut self, input: &[u8], buf: &mut [u8]) -> Result<Run, Error> {
let r = self.whole(input, buf);
if r.is_err() {
self.stage = Stage::Done;
}
r
}
#[inline(always)]
fn whole(&mut self, input: &[u8], buf: &mut [u8]) -> Result<Run, Error> {
let format = self.format;
let start = body_start(format, input)?;
let out_len = if WRITE { buf.len() } else { usize::MAX / 2 };
let r = decode::run::<false, WRITE>(
&mut self.tables,
&input[start..],
buf,
out_len,
None,
false,
)?;
let (written, used) = match &r {
Status::Done(consumed, written) => (*written, start + consumed),
Status::Full(r) => (r.out_pos(), start + r.in_pos()),
};
let mut check = Self::new_check(format);
if format != Format::Deflate {
if WRITE {
check.update(&buf[..written]);
} else {
check.count(written);
}
}
if let Status::Full(r) = r {
return Ok(self.carry_on(r, check, used, written));
}
let consumed = check.verify_at(input, used)?;
self.stage = Stage::Done;
self.pos = written;
self.total_in = consumed as u64;
self.total_out = written as u64;
Ok(Run {
consumed,
start: 0,
done: true,
full: false,
})
}
#[cold]
#[inline(never)]
fn carry_on(&mut self, r: Resume, check: Check, used: usize, written: usize) -> Run {
self.restart();
self.stage = Stage::Body;
self.fresh = false;
self.resume = r;
self.check = check;
self.pos = written;
self.total_in = used as u64;
self.total_out = written as u64;
Run {
consumed: used,
start: 0,
done: false,
full: WRITE,
}
}
fn steps(
&mut self,
input: &[u8],
ip: &mut usize,
buf: &mut [u8],
end: bool,
) -> Result<Stop, Error> {
loop {
match self.stage {
Stage::Header => {
if !self.header.parse(self.format, input, ip)? {
return need_input(end);
}
self.stage = Stage::Body;
}
Stage::Body => match self.body(input, ip, buf, end)? {
Step::Continue => {}
Step::NeedInput => return need_input(end),
Step::Full => return Ok(Stop::Full),
Step::Done => self.stage = Stage::Trailer,
},
Stage::Trailer => {
let complete = self.collect_trailer(input, ip);
self.check.verify(&self.trailer[..self.trailer_len])?;
if !complete {
return need_input(end);
}
return Ok(Stop::Done);
}
Stage::Done => return Ok(Stop::Done),
}
}
}
fn body(
&mut self,
input: &[u8],
ip: &mut usize,
buf: &mut [u8],
end: bool,
) -> Result<Step, Error> {
if !WRITE {
self.pos = self.pos.min(WINDOW);
}
let out_len = if WRITE { buf.len() } else { usize::MAX / 2 };
let fresh = core::mem::replace(&mut self.fresh, false);
if self.carry_len == 0 {
let rest = &input[*ip..];
let r = if fresh && end {
decode::run::<false, WRITE>(&mut self.tables, rest, buf, out_len, None, false)?
} else {
self.resume.set_in_pos(0);
self.resume.set_out_pos(self.pos);
let resume = &self.resume;
decode::run::<true, WRITE>(
&mut self.tables,
rest,
buf,
out_len,
Some(resume),
!end,
)?
};
return Ok(match r {
Status::Done(consumed, written) => {
self.output(buf, written);
*ip += consumed;
Step::Done
}
Status::Full(r) => {
self.output(buf, r.out_pos());
let pos = r.in_pos();
self.resume = r;
if self.resume.needs_input() {
let keep = &rest[pos..];
if keep.len() > CARRY_LEN {
return Err(Error::BadData);
}
self.carry[..keep.len()].copy_from_slice(keep);
self.carry_len = keep.len();
*ip = input.len();
Step::NeedInput
} else {
*ip += pos;
Self::full()
}
}
});
}
let old = self.carry_len;
let rest = &input[*ip..];
let take = rest.len().min(CARRY_LEN - old);
self.carry[old..old + take].copy_from_slice(&rest[..take]);
self.carry_len = old + take;
let more = !end || take < rest.len();
self.resume.set_in_pos(0);
self.resume.set_out_pos(self.pos);
let r = decode::run::<true, WRITE>(
&mut self.tables,
&self.carry[..self.carry_len],
buf,
out_len,
Some(&self.resume),
more,
)?;
Ok(match r {
Status::Done(consumed, written) => {
self.output(buf, written);
self.unload_carry(consumed, old, ip);
Step::Done
}
Status::Full(mut r) => {
self.output(buf, r.out_pos());
let pos = r.in_pos();
if r.needs_input() && pos < old {
self.drain_carry(pos);
*ip += take;
r.set_in_pos(0);
self.resume = r;
if take == 0 {
if self.carry_len == CARRY_LEN {
return Err(Error::BadData);
}
return Ok(Step::NeedInput);
}
Step::Continue
} else {
let needs_input = r.needs_input();
self.unload_carry(pos, old, ip);
self.resume = r;
if needs_input {
Step::Continue
} else {
Self::full()
}
}
}
})
}
const fn full() -> Step {
if WRITE {
Step::Full
} else {
Step::Continue
}
}
fn output(&mut self, buf: &[u8], new_pos: usize) {
let n = new_pos - self.pos;
if WRITE {
self.check.update(&buf[self.pos..new_pos]);
} else {
self.check.count(n);
}
self.total_out += n as u64;
self.pos = new_pos;
}
fn drain_carry(&mut self, n: usize) {
self.carry.copy_within(n..self.carry_len, 0);
self.carry_len -= n;
}
fn unload_carry(&mut self, pos: usize, old: usize, ip: &mut usize) {
if pos >= old {
*ip += pos - old;
self.carry_len = 0;
} else {
self.carry_len = old;
self.drain_carry(pos);
}
}
fn collect_trailer(&mut self, input: &[u8], ip: &mut usize) -> bool {
let need = trailer_len(self.format);
let from_carry = (need - self.trailer_len).min(self.carry_len);
self.trailer[self.trailer_len..self.trailer_len + from_carry]
.copy_from_slice(&self.carry[..from_carry]);
self.trailer_len += from_carry;
self.drain_carry(from_carry);
let n = (need - self.trailer_len).min(input.len() - *ip);
self.trailer[self.trailer_len..self.trailer_len + n].copy_from_slice(&input[*ip..*ip + n]);
self.trailer_len += n;
*ip += n;
self.trailer_len == need
}
}
fn need_input(end: bool) -> Result<Stop, Error> {
if end {
Err(Error::Truncated)
} else {
Ok(Stop::NeedInput)
}
}
#[derive(Clone)]
pub struct Decoder {
pub(super) core: Core<true>,
}
impl core::fmt::Debug for Decoder {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Decoder")
.field("format", &self.core.format)
.field("total_in", &self.core.total_in)
.field("total_out", &self.core.total_out)
.finish_non_exhaustive()
}
}
#[derive(Debug, PartialEq, Eq)]
#[must_use]
#[non_exhaustive]
pub struct Progress<'b> {
pub consumed: usize,
pub output: &'b [u8],
pub done: bool,
pub full: bool,
}
impl Decoder {
#[must_use]
pub const fn new(format: Format) -> Self {
Decoder {
core: Core::new(format),
}
}
#[must_use]
pub const fn format(&self) -> Format {
self.core.format
}
pub fn reset(&mut self) {
self.core.restart();
}
#[must_use]
pub fn total_in(&self) -> u64 {
self.core.total_in
}
#[must_use]
pub fn total_out(&self) -> u64 {
self.core.total_out
}
pub fn decompress<'b>(
&mut self,
input: &[u8],
buf: &'b mut [u8],
end_of_input: bool,
) -> Result<Progress<'b>, Error> {
let core = &mut self.core;
if end_of_input && core.can_run_whole() {
let r = core.run_whole(input, buf)?;
let buf: &'b [u8] = buf;
return Ok(Progress {
consumed: r.consumed,
output: &buf[..core.pos],
done: r.done,
full: core.stage == Stage::Body && core.pos == buf.len(),
});
}
if core.stage == Stage::Done {
core.restart();
}
if core.pos > buf.len() {
return Err(Error::BufferFull);
}
let r = core.run(input, buf, end_of_input)?;
if r.full && r.consumed == 0 && r.start == core.pos {
return Err(Error::BufferFull);
}
let buf: &'b [u8] = buf;
Ok(Progress {
consumed: r.consumed,
output: &buf[r.start..core.pos],
done: r.done,
full: core.stage == Stage::Body && core.pos == buf.len(),
})
}
pub fn make_room(&mut self, buf: &mut [u8]) -> usize {
let core = &mut self.core;
let pos = core.pos;
if core.stage != Stage::Body || pos <= WINDOW || pos > buf.len() {
return 0;
}
buf.copy_within(pos - WINDOW..pos, 0);
core.pos = WINDOW;
pos - WINDOW
}
}
#[derive(Clone)]
pub struct Scanner {
core: Core<false>,
}
impl core::fmt::Debug for Scanner {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Scanner")
.field("format", &self.core.format)
.field("total_in", &self.core.total_in)
.field("total_out", &self.core.total_out)
.finish_non_exhaustive()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct Lengths {
pub compressed: u64,
pub decompressed: u64,
}
impl Scanner {
#[must_use]
pub const fn new(format: Format) -> Self {
Scanner {
core: Core::new(format),
}
}
#[must_use]
pub const fn format(&self) -> Format {
self.core.format
}
pub fn reset(&mut self) {
self.core.restart();
}
#[must_use]
pub fn total_in(&self) -> u64 {
self.core.total_in
}
#[must_use]
pub fn total_out(&self) -> u64 {
self.core.total_out
}
pub fn scan(&mut self, input: &[u8], end_of_input: bool) -> Result<Option<usize>, Error> {
let r = self.core.run(input, &mut [], end_of_input)?;
debug_assert!(r.done || r.consumed == input.len());
Ok(r.done.then_some(r.consumed))
}
#[cfg(feature = "std")]
pub fn scan_reader<R: std::io::BufRead>(&mut self, mut reader: R) -> std::io::Result<Lengths> {
self.reset();
loop {
let input = reader.fill_buf()?;
let eof = input.is_empty();
let r = self.scan(input, eof);
let consumed = match r? {
Some(n) => {
reader.consume(n);
return Ok(Lengths {
compressed: self.total_in(),
decompressed: self.total_out(),
});
}
None => input.len(),
};
reader.consume(consumed);
}
}
}