core: support DeflateMode option setting
[nihav.git] / nihav-core / src / compr / deflate.rs
index 13d9ad53c2270082d8295666d6beed53992702a5..91207891a83a83b760485101db125f3ee98d78e0 100644 (file)
@@ -71,6 +71,7 @@
 //! # }
 //! ```
 
+use crate::options::NAOptionDefinitionType;
 use crate::io::byteio::*;
 use crate::io::bitreader::*;
 use crate::io::codebook::*;
@@ -375,8 +376,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<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);
         }
@@ -386,6 +394,9 @@ 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;
@@ -399,6 +410,9 @@ impl Inflate {
             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);
                     }
@@ -743,6 +757,14 @@ 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<usize> {
         let mut inflate = Self::new();
@@ -1700,6 +1722,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,
@@ -1718,17 +1782,17 @@ pub struct Deflate {
     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,