//! # }
//! ```
+use crate::options::NAOptionDefinitionType;
use crate::io::byteio::*;
use crate::io::bitreader::*;
use crate::io::codebook::*;
}
Ok(())
}
+ fn skip_bytes(&mut self, nbytes: usize) -> BitReaderResult<()> {
+ self.align();
+ let cached = usize::from(self.br.bits / 8);
+ if nbytes <= cached {
+ self.skip((nbytes as u32) * 8)?;
+ } else {
+ self.skip((cached as u32) * 8)?;
+ self.br.bits = 0;
+ self.br.bitbuf = 0;
+ self.br.pos += nbytes - cached;
+ if self.br.pos > self.src.len() {
+ return Err(BitReaderError::BitstreamEnd);
+ }
+ self.refill();
+ }
+ Ok(())
+ }
fn align(&mut self) {
let b = self.br.bits & 7;
if b != 0 {
- self.skip_cache(8 - (b as u8));
+ self.skip_cache(b);
}
}
fn left(&self) -> isize {
((self.src.len() as isize) - (self.br.pos as isize)) * 8 + (self.br.bits as isize)
}
+ fn tell(&self) -> usize {
+ self.br.pos - usize::from(self.br.bits / 8)
+ }
}
impl<'a, S: Copy> CodebookReader<S> for CurrentSource<'a> {
self.full_pos += len;
Ok(())
}
+ ///! Sets custom history for decoding an update for already decoded data.
+ pub fn set_dict(&mut self, dict: &[u8]) {
+ let len = dict.len().min(self.buf.len());
+ let start = dict.len() - len;
+ self.buf[..len].copy_from_slice(&dict[start..]);
+ self.bpos = len;
+ self.full_pos = len;
+ }
///! Reports whether decoder has finished decoding the input.
pub fn is_finished(&self) -> bool {
- match self.state {
- InflateState::End => true,
- _ => false,
- }
+ matches!(self.state, InflateState::End)
}
///! Reports the current amount of bytes output into the destination buffer after the last run.
pub fn get_current_output_size(&self) -> usize { self.output_idx }
///!
///! [`DecompressError::ShortData`]: ../enum.DecompressError.html#variant.ShortData
///! [`DecompressError::OutputFull`]: ../enum.DecompressError.html#variant.OutputFull
- #[allow(clippy::comparison_chain)]
pub fn decompress_data(&mut self, src: &[u8], dst: &mut [u8], continue_block: bool) -> DecompressResult<usize> {
+ self.decompress_data_internal(src, dst, continue_block, false)
+ }
+ ///! Tries to decompress whole input chunk to the output buffer.
+ pub fn decompress_block(&mut self, src: &[u8], dst: &mut [u8]) -> DecompressResult<usize> {
+ self.decompress_data_internal(src, dst, false, true)
+ }
+ #[allow(clippy::comparison_chain)]
+ fn decompress_data_internal(&mut self, src: &[u8], dst: &mut [u8], continue_block: bool, do_one_block: bool) -> DecompressResult<usize> {
if src.is_empty() || dst.is_empty() {
return Err(DecompressError::InvalidArgument);
}
self.output_idx = 0;
CurrentSource::reinit(src, self.br)
};
+ if do_one_block {
+ self.output_idx = 0;
+ }
+ // check for zlib stream header
+ if let (&InflateState::Start, true) = (&self.state, src.len() > 2) {
+ let cm = src[0] & 0xF;
+ let cinfo = src[0] >> 4;
+ let hdr = (u16::from(src[0]) << 8) | u16::from(src[1]);
+ if cm == 8 && cinfo <= 7 && (hdr % 31) == 0 {
+ csrc.skip(16).unwrap();
+ }
+ }
'main: loop {
match self.state {
InflateState::Start | InflateState::BlockStart => {
if csrc.left() == 0 {
+ if do_one_block {
+ return Ok(self.output_idx);
+ }
self.br = csrc.br;
return Err(DecompressError::ShortData);
}
},
InflateState::StaticBlockInvLen(len) => {
let inv_len = read_bits!(self, csrc, 16);
- if len != !inv_len {
+ if (len ^ inv_len) != 0xFFFF {
self.state = InflateState::End;
return Err(DecompressError::InvalidHeader);
}
let (lit_lengths, dist_lengths) = self.all_lengths.split_at(self.hlit);
let mut lit_codes = [ShortCodebookDesc { code: 0, bits: 0 }; NUM_LITERALS];
- lengths_to_codes(&lit_lengths, &mut lit_codes)?;
+ lengths_to_codes(lit_lengths, &mut lit_codes)?;
let mut cr = ShortCodebookDescReader::new(lit_codes.to_vec());
let ret = Codebook::new(&mut cr, CodebookMode::LSB);
if ret.is_err() { return Err(DecompressError::InvalidHeader); }
}
}
}
+ ///! Resets decoder state.
+ pub fn reset(&mut self) {
+ self.bpos = 0;
+ self.output_idx = 0;
+ self.full_pos = 0;
+ self.state = InflateState::Start;
+ }
+
///! Decompresses input data into output returning the uncompressed data length.
pub fn uncompress(src: &[u8], dst: &mut [u8]) -> DecompressResult<usize> {
- let mut inflate = Self::new();
- let off = if src.len() > 2 && src[0] == 0x78 && (src[1] != 0 && ((src[1] - 1) % 31) == 0) { 2 } else { 0 };
- inflate.decompress_data(&src[off..], dst, false)
+ let mut csrc = CurrentSource::new(src, BitReaderState::default());
+ if src.len() > 2 {
+ let cm = src[0] & 0xF;
+ let cinfo = src[0] >> 4;
+ let hdr = (u16::from(src[0]) << 8) | u16::from(src[1]);
+ if cm == 8 && cinfo <= 7 && (hdr % 31) == 0 {
+ csrc.skip(16).unwrap();
+ }
+ }
+
+ let mut fix_len_cb = None;
+
+ let mut dst_idx = 0;
+ let mut final_block = false;
+ while !final_block {
+ final_block = csrc.read_bool()?;
+
+ let bmode = csrc.read(2)?;
+ match bmode {
+ 0 => {
+ csrc.align();
+ let len = csrc.read(16)? as usize;
+ let inv_len = csrc.read(16)? as usize;
+ if (len ^ inv_len) != 0xFFFF {
+ return Err(DecompressError::InvalidHeader);
+ }
+ let src_pos = csrc.tell();
+ if src_pos + len > src.len() {
+ return Err(DecompressError::ShortData);
+ }
+ if dst_idx + len > dst.len() {
+ return Err(DecompressError::OutputFull);
+ }
+ dst[dst_idx..][..len].copy_from_slice(&src[src_pos..][..len]);
+ dst_idx += len;
+ csrc.skip_bytes(len)?;
+ },
+ 1 => {
+ if fix_len_cb.is_none() {
+ let mut cr = FixedLenCodeReader {};
+ fix_len_cb = Some(Codebook::new(&mut cr, CodebookMode::LSB).unwrap());
+ }
+ if let Some(ref len_cb) = &fix_len_cb {
+ loop {
+ let val = csrc.read_cb(len_cb)?;
+ if val < 256 {
+ if dst_idx >= dst.len() {
+ return Err(DecompressError::OutputFull);
+ }
+ dst[dst_idx] = val as u8;
+ dst_idx += 1;
+ } else if val == 256 {
+ break;
+ } else {
+ let len_idx = (val - 257) as usize;
+ if len_idx >= LENGTH_BASE.len() {
+ return Err(DecompressError::InvalidData);
+ }
+ let len_bits = LENGTH_ADD_BITS[len_idx];
+ let mut length = LENGTH_BASE[len_idx] as usize;
+ if len_bits > 0 {
+ length += csrc.read(len_bits)? as usize;
+ }
+ let dist_idx = reverse_bits(csrc.read(5)?, 5) as usize;
+ if dist_idx >= DIST_BASE.len() {
+ return Err(DecompressError::InvalidData);
+ }
+ let dist_bits = DIST_ADD_BITS[dist_idx];
+ let mut dist = DIST_BASE[dist_idx] as usize;
+ if dist_bits > 0 {
+ dist += csrc.read(dist_bits)? as usize;
+ }
+
+ if dst_idx + length > dst.len() {
+ return Err(DecompressError::OutputFull);
+ }
+ if dist > dst_idx {
+ return Err(DecompressError::InvalidData);
+ }
+ lz_copy(dst, dst_idx, dist, length);
+ dst_idx += length;
+ }
+ }
+ } else {
+ unreachable!();
+ }
+ },
+ 2 => {
+ let hlit = csrc.read(5)? as usize + 257;
+ if hlit >= 287 {
+ return Err(DecompressError::InvalidHeader);
+ }
+ let hdist = csrc.read(5)? as usize + 1;
+ let hclen = csrc.read(4)? as usize + 4;
+ let mut cur_len_idx = 0;
+ let mut len_lengths = [0; 19];
+ let mut all_lengths = [0; NUM_LITERALS + NUM_DISTS];
+
+ for _ in 0..hclen {
+ len_lengths[LEN_RECODE[cur_len_idx]] = csrc.read(3)? as u8;
+ cur_len_idx += 1;
+ }
+ let mut len_codes = [ShortCodebookDesc { code: 0, bits: 0 }; 19];
+ lengths_to_codes(&len_lengths, &mut len_codes)?;
+ let mut cr = ShortCodebookDescReader::new(len_codes.to_vec());
+ let ret = Codebook::new(&mut cr, CodebookMode::LSB);
+ if ret.is_err() {
+ return Err(DecompressError::InvalidHeader);
+ }
+ let dyn_len_cb = ret.unwrap();
+
+ let mut cur_len_idx = 0;
+ while cur_len_idx < hlit + hdist {
+ let val = csrc.read_cb(&dyn_len_cb)?;
+ if val < 16 {
+ all_lengths[cur_len_idx] = val as u8;
+ cur_len_idx += 1;
+ } else {
+ let mode = (val as usize) - 16;
+ if mode > 2 {
+ return Err(DecompressError::InvalidHeader);
+ }
+ let base = REPEAT_BASE[mode] as usize;
+ let bits = REPEAT_BITS[mode];
+ let len = base + (csrc.read(bits)? as usize);
+ if cur_len_idx + len > hlit + hdist {
+ return Err(DecompressError::InvalidHeader);
+ }
+ let rpt = if mode == 0 {
+ if cur_len_idx == 0 {
+ return Err(DecompressError::InvalidHeader);
+ }
+ all_lengths[cur_len_idx - 1]
+ } else {
+ 0
+ };
+ for _ in 0..len {
+ all_lengths[cur_len_idx] = rpt;
+ cur_len_idx += 1;
+ }
+ }
+ }
+ let (lit_lengths, dist_lengths) = all_lengths.split_at(hlit);
+
+ let mut lit_codes = [ShortCodebookDesc { code: 0, bits: 0 }; NUM_LITERALS];
+ lengths_to_codes(lit_lengths, &mut lit_codes)?;
+ let mut cr = ShortCodebookDescReader::new(lit_codes.to_vec());
+ let ret = Codebook::new(&mut cr, CodebookMode::LSB);
+ if ret.is_err() { return Err(DecompressError::InvalidHeader); }
+ let dyn_lit_cb = ret.unwrap();
+
+ let mut dist_codes = [ShortCodebookDesc { code: 0, bits: 0 }; NUM_DISTS];
+ lengths_to_codes(&dist_lengths[..hdist], &mut dist_codes)?;
+ let mut cr = ShortCodebookDescReader::new(dist_codes.to_vec());
+ let ret = Codebook::new(&mut cr, CodebookMode::LSB);
+ if ret.is_err() { return Err(DecompressError::InvalidHeader); }
+ let dyn_dist_cb = ret.unwrap();
+
+ loop {
+ let val = csrc.read_cb(&dyn_lit_cb)?;
+ if val < 256 {
+ if dst_idx >= dst.len() {
+ return Err(DecompressError::OutputFull);
+ }
+ dst[dst_idx] = val as u8;
+ dst_idx += 1;
+ } else if val == 256 {
+ break;
+ } else {
+ let len_idx = (val - 257) as usize;
+ if len_idx >= LENGTH_BASE.len() {
+ return Err(DecompressError::InvalidData);
+ }
+ let len_bits = LENGTH_ADD_BITS[len_idx];
+ let mut length = LENGTH_BASE[len_idx] as usize;
+ if len_bits > 0 {
+ length += csrc.read(len_bits)? as usize;
+ }
+
+ let dist_idx = csrc.read_cb(&dyn_dist_cb)? as usize;
+ if dist_idx >= DIST_BASE.len() {
+ return Err(DecompressError::InvalidData);
+ }
+ let dist_bits = DIST_ADD_BITS[dist_idx];
+ let mut dist = DIST_BASE[dist_idx] as usize;
+ if dist_bits > 0 {
+ dist += csrc.read(dist_bits)? as usize;
+ }
+
+ if dst_idx + length > dst.len() {
+ return Err(DecompressError::OutputFull);
+ }
+ if dist > dst_idx {
+ return Err(DecompressError::InvalidData);
+ }
+ lz_copy(dst, dst_idx, dist, length);
+ dst_idx += length;
+ }
+ }
+ },
+ _ => return Err(DecompressError::InvalidHeader),
+ };
+ }
+ Ok(dst_idx)
}
}
}
dst.reserve(src.len());
- self.trellis.truncate(0);
+ self.trellis.clear();
self.trellis.reserve(src.len() + 1);
for _ in 0..=src.len() {
self.trellis.push(TNode::default());
Best,
}
+impl Default for DeflateMode {
+ fn default() -> Self { DeflateMode::Better }
+}
+
+pub const DEFLATE_MODE_DESCRIPTION: &str = "Deflate compression level.";
+///! Deflate option for no compression.
+pub const DEFLATE_MODE_NONE: &str = "none";
+///! Deflate option for fast compression.
+pub const DEFLATE_MODE_FAST: &str = "fast";
+///! Deflate option for better compression.
+pub const DEFLATE_MODE_BETTER: &str = "better";
+///! Deflate option for best compression.
+pub const DEFLATE_MODE_BEST: &str = "best";
+
+///! All possible option values for deflate compression.
+pub const DEFLATE_OPTION_VALUES: NAOptionDefinitionType = NAOptionDefinitionType::String(Some(&[DEFLATE_MODE_NONE, DEFLATE_MODE_FAST, DEFLATE_MODE_BETTER, DEFLATE_MODE_BEST]));
+
+impl std::str::FromStr for DeflateMode {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ DEFLATE_MODE_NONE => Ok(DeflateMode::NoCompr),
+ DEFLATE_MODE_FAST => Ok(DeflateMode::Fast),
+ DEFLATE_MODE_BETTER => Ok(DeflateMode::Better),
+ DEFLATE_MODE_BEST => Ok(DeflateMode::Best),
+ _ => Err(()),
+ }
+ }
+}
+
+impl ToString for DeflateMode {
+ fn to_string(&self) -> String {
+ match *self {
+ DeflateMode::NoCompr => DEFLATE_MODE_NONE.to_string(),
+ DeflateMode::Fast => DEFLATE_MODE_FAST.to_string(),
+ DeflateMode::Better => DEFLATE_MODE_BETTER.to_string(),
+ DeflateMode::Best => DEFLATE_MODE_BEST.to_string(),
+ }
+ }
+}
+
#[derive(Clone,Copy,Debug,PartialEq)]
enum Mode {
Copy,
sum1: u32,
sum2: u32,
zlib_mode: bool,
- parser: Box<dyn LZParse>,
+ parser: Box<dyn LZParse + Send>,
}
impl Deflate {
///! Creates a new instance of `Deflate`.
pub fn new(mode: DeflateMode) -> Self {
let (mode, parser) = match mode {
- DeflateMode::NoCompr => (Mode::Copy, Box::new(NoParser{}) as Box<dyn LZParse>),
- DeflateMode::Fast => (Mode::Fixed, Box::new(GreedyParser{}) as Box<dyn LZParse>),
- DeflateMode::Better => (Mode::Dynamic, Box::new(LazyParser{}) as Box<dyn LZParse>),
- DeflateMode::Best => (Mode::Dynamic, Box::new(OptimalParser::new()) as Box<dyn LZParse>),
+ DeflateMode::NoCompr => (Mode::Copy, Box::new(NoParser{}) as Box<dyn LZParse + Send>),
+ DeflateMode::Fast => (Mode::Fixed, Box::new(GreedyParser{}) as Box<dyn LZParse + Send>),
+ DeflateMode::Better => (Mode::Dynamic, Box::new(LazyParser{}) as Box<dyn LZParse + Send>),
+ DeflateMode::Best => (Mode::Dynamic, Box::new(OptimalParser::new()) as Box<dyn LZParse + Send>),
};
Self {
mode, parser,
self.write_zlib_footer(wr);
}
}
+ ///! Tells the encoder to compress the data it received and flush it.
+ pub fn compress_flush(&mut self, wr: &mut DeflateWriter) {
+ if self.ssize > 0 {
+ self.do_block(wr, false);
+ }
+ if (wr.bits & 7) != 0 {
+ // write zero-length copy block for byte-alignment
+ wr.write(0, 1);
+ wr.write(0, 2);
+ wr.align();
+ wr.write(0, 16);
+ wr.write(0xFFFF, 16);
+ }
+ }
fn do_block(&mut self, wr: &mut DeflateWriter, final_block: bool) {
const CRC_BASE: u32 = 65521;
for &b in self.srcbuf[..self.ssize].iter() {
Mode::Fixed => {
wr.write(final_block as u16, 1);
wr.write(1, 2);
- self.tokens.truncate(0);
+ self.tokens.clear();
self.parser.parse(&self.srcbuf[..self.ssize], &mut self.tokens);
let mut codes = CodeHuff::new(true);
codes.make_codes(&self.tokens);
Mode::Dynamic => {
wr.write(final_block as u16, 1);
wr.write(2, 2);
- self.tokens.truncate(0);
+ self.tokens.clear();
self.parser.parse(&self.srcbuf[..self.ssize], &mut self.tokens);
let mut codes = CodeHuff::new(false);
codes.make_codes(&self.tokens);