1 //! Extra streaming compression functionality.
2 //!
3 //! As of now this is mainly inteded for use to build a higher-level wrapper.
4 //!
5 //! There is no DeflateState as the needed state is contained in the compressor struct itself.
6 use core::convert::{AsMut, AsRef};
7 
8 use crate::deflate::core::{compress, CompressorOxide, TDEFLFlush, TDEFLStatus};
9 use crate::{MZError, MZFlush, MZStatus, StreamResult};
10 
11 /// Try to compress from input to output with the given Compressor
12 ///
13 /// # Errors
14 ///
15 /// Returns `MZError::Buf` If the size of the `output` slice is empty or no progress was made due to
16 /// lack of expected input data or called after the compression was finished without
17 /// MZFlush::Finish.
18 ///
19 /// Returns `MZError::Param` if the compressor parameters are set wrong.
deflate( compressor: &mut CompressorOxide, input: &[u8], output: &mut [u8], flush: MZFlush, ) -> StreamResult20 pub fn deflate(
21     compressor: &mut CompressorOxide,
22     input: &[u8],
23     output: &mut [u8],
24     flush: MZFlush,
25 ) -> StreamResult {
26     if output.is_empty() {
27         return StreamResult::error(MZError::Buf);
28     }
29 
30     if compressor.prev_return_status() == TDEFLStatus::Done {
31         return if flush == MZFlush::Finish {
32             StreamResult {
33                 bytes_written: 0,
34                 bytes_consumed: 0,
35                 status: Ok(MZStatus::StreamEnd),
36             }
37         } else {
38             StreamResult::error(MZError::Buf)
39         };
40     }
41 
42     let mut bytes_written = 0;
43     let mut bytes_consumed = 0;
44 
45     let mut next_in = input.as_ref();
46     let mut next_out = output.as_mut();
47 
48     let status = loop {
49         let in_bytes;
50         let out_bytes;
51         let defl_status = {
52             let res = compress(compressor, next_in, next_out, TDEFLFlush::from(flush));
53             in_bytes = res.1;
54             out_bytes = res.2;
55             res.0
56         };
57 
58         next_in = &next_in[in_bytes..];
59         next_out = &mut next_out[out_bytes..];
60         bytes_consumed += in_bytes;
61         bytes_written += out_bytes;
62 
63         // Check if we are done, or compression failed.
64         match defl_status {
65             TDEFLStatus::BadParam => break Err(MZError::Param),
66             // Don't think this can happen as we're not using a custom callback.
67             TDEFLStatus::PutBufFailed => break Err(MZError::Stream),
68             TDEFLStatus::Done => break Ok(MZStatus::StreamEnd),
69             _ => (),
70         };
71 
72         // All the output space was used, so wait for more.
73         if next_out.is_empty() {
74             break Ok(MZStatus::Ok);
75         }
76 
77         if next_in.is_empty() && (flush != MZFlush::Finish) {
78             let total_changed = bytes_written > 0 || bytes_consumed > 0;
79 
80             break if (flush != MZFlush::None) || total_changed {
81                 // We wrote or consumed something, and/or did a flush (sync/partial etc.).
82                 Ok(MZStatus::Ok)
83             } else {
84                 // No more input data, not flushing, and nothing was consumed or written,
85                 // so couldn't make any progress.
86                 Err(MZError::Buf)
87             };
88         }
89     };
90     StreamResult {
91         bytes_consumed,
92         bytes_written,
93         status,
94     }
95 }
96 
97 #[cfg(test)]
98 mod test {
99     use super::deflate;
100     use crate::deflate::CompressorOxide;
101     use crate::inflate::decompress_to_vec_zlib;
102     use crate::{MZFlush, MZStatus};
103     use std::prelude::v1::*;
104     use std::vec;
105 
106     #[test]
test_state()107     fn test_state() {
108         let data = b"Hello zlib!";
109         let mut compressed = vec![0; 50];
110         let mut compressor = Box::<CompressorOxide>::default();
111         let res = deflate(&mut compressor, data, &mut compressed, MZFlush::Finish);
112         let status = res.status.expect("Failed to compress!");
113         let decomp =
114             decompress_to_vec_zlib(&compressed).expect("Failed to decompress compressed data");
115         assert_eq!(status, MZStatus::StreamEnd);
116         assert_eq!(decomp[..], data[..]);
117         assert_eq!(res.bytes_consumed, data.len());
118     }
119 }
120