core/compr: allow inflate work with a custom dictionary
[nihav.git] / nihav-core / src / compr / deflate.rs
index 3a3819ef2eb4bea191ed55e7fe985f0c44b1b793..b1266619b87d5b05228dfd21d1d61904e195bef8 100644 (file)
@@ -71,6 +71,7 @@
 //! # }
 //! ```
 
+use crate::options::NAOptionDefinitionType;
 use crate::io::byteio::*;
 use crate::io::bitreader::*;
 use crate::io::codebook::*;
@@ -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 {
@@ -1653,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());
@@ -1721,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<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,
@@ -1814,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() {
@@ -1840,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);
@@ -1851,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);