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 std::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. 20 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 #[test] 104 fn test_state() { 105 let data = b"Hello zlib!"; 106 let mut compressed = vec![0; 50]; 107 let mut compressor = Box::<CompressorOxide>::default(); 108 let res = deflate(&mut compressor, data, &mut compressed, MZFlush::Finish); 109 let status = res.status.expect("Failed to compress!"); 110 let decomp = 111 decompress_to_vec_zlib(&compressed).expect("Failed to decompress compressed data"); 112 assert_eq!(status, MZStatus::StreamEnd); 113 assert_eq!(decomp[..], data[..]); 114 assert_eq!(res.bytes_consumed, data.len()); 115 } 116 } 117