X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-core%2Fsrc%2Fcompr%2Fdeflate.rs;h=b1266619b87d5b05228dfd21d1d61904e195bef8;hp=7d6fae5eafd5174bedfd5c3d96e93ad85cc35bd8;hb=bc23de6bedc2e151caea241b073a65d30f62c134;hpb=f8cdb949e5b15fca5b563d9f3ac06083234f0e86 diff --git a/nihav-core/src/compr/deflate.rs b/nihav-core/src/compr/deflate.rs index 7d6fae5..b126661 100644 --- a/nihav-core/src/compr/deflate.rs +++ b/nihav-core/src/compr/deflate.rs @@ -71,6 +71,7 @@ //! # } //! ``` +use crate::options::NAOptionDefinitionType; use crate::io::byteio::*; use crate::io::bitreader::*; use crate::io::codebook::*; @@ -174,7 +175,7 @@ impl<'a> CurrentSource<'a> { 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 { @@ -355,6 +356,14 @@ impl Inflate { 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 { @@ -375,8 +384,15 @@ impl Inflate { ///! ///! [`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 { + 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 { + 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 { if src.is_empty() || dst.is_empty() { return Err(DecompressError::InvalidArgument); } @@ -386,10 +402,25 @@ impl Inflate { 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); } @@ -417,7 +448,7 @@ impl Inflate { }, 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); } @@ -734,11 +765,18 @@ impl Inflate { } } } + ///! 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 { 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) + inflate.decompress_data(src, dst, false) } } @@ -1624,7 +1662,7 @@ impl LZParse for OptimalParser { } 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()); @@ -1692,6 +1730,48 @@ pub enum DeflateMode { 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 { + 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, @@ -1710,17 +1790,17 @@ pub struct Deflate { sum1: u32, sum2: u32, zlib_mode: bool, - parser: Box, + parser: Box, } 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), - DeflateMode::Fast => (Mode::Fixed, Box::new(GreedyParser{}) as Box), - DeflateMode::Better => (Mode::Dynamic, Box::new(LazyParser{}) as Box), - DeflateMode::Best => (Mode::Dynamic, Box::new(OptimalParser::new()) as Box), + DeflateMode::NoCompr => (Mode::Copy, Box::new(NoParser{}) as Box), + DeflateMode::Fast => (Mode::Fixed, Box::new(GreedyParser{}) as Box), + DeflateMode::Better => (Mode::Dynamic, Box::new(LazyParser{}) as Box), + DeflateMode::Best => (Mode::Dynamic, Box::new(OptimalParser::new()) as Box), }; Self { mode, parser, @@ -1785,6 +1865,20 @@ impl Deflate { 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() { @@ -1811,7 +1905,7 @@ impl Deflate { 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); @@ -1822,7 +1916,7 @@ impl Deflate { 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);