1 //! This module contains functionality for compression.
11 /// How much processing the compressor should do to compress the data.
12 /// `NoCompression` and `Bestspeed` have special meanings, the other levels determine the number
13 /// of checks for matches in the hash chains and whether to use lazy or greedy parsing.
15 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
16 pub enum CompressionLevel
{
17 /// Don't do any compression, only output uncompressed blocks.
19 /// Fast compression. Uses a special compression routine that is optimized for speed.
21 /// Slow/high compression. Do a lot of checks to try to find good matches.
23 /// Even more checks, can be very slow.
25 /// Default compromise between speed and compression.
27 /// Use the default compression level.
28 DefaultCompression
= -1,
31 // Missing safe rust analogue (this and mem-to-mem are quite similar)
34 d: Option<&mut CompressorOxide>,
35 in_buf: *const c_void,
36 in_size: Option<&mut usize>,
38 out_size: Option<&mut usize>,
43 in_size.map(|size| *size = 0);
44 out_size.map(|size| *size = 0);
45 (TDEFLStatus::BadParam, 0, 0)
48 let callback_res = CallbackOxide::new(
49 compressor.callback_func.clone(),
56 if let Ok(mut callback) = callback_res {
57 let res = compress(compressor, &mut callback, flush);
58 callback.update_size(Some(res.1), Some(res.2));
61 (TDEFLStatus::BadParam, 0, 0)
68 // Missing safe rust analogue
71 d: Option<&mut CompressorOxide>,
72 put_buf_func: PutBufFuncPtr,
73 put_buf_user: *mut c_void,
77 *d = CompressorOxide::new(
78 put_buf_func.map(|func|
79 CallbackFunc { put_buf_func: func, put_buf_user: put_buf_user }
89 // Missing safe rust analogue (though maybe best served by flate2 front-end instead)
91 fn tdefl_compress_mem_to_output(
94 put_buf_func: PutBufFuncPtr,
95 put_buf_user: *mut c_void,
99 // Missing safe Rust analogue
101 fn tdefl_compress_mem_to_mem(
102 out_buf: *mut c_void,
104 src_buf: *const c_void,
109 /// Compress the input data to a vector, using the specified compression level (0-10).
110 pub fn compress_to_vec(input
: &[u8], level
: u8) -> Vec
<u8> {
111 compress_to_vec_inner(input
, level
, 0, 0)
114 /// Compress the input data to a vector, using the specified compression level (0-10), and with a
116 pub fn compress_to_vec_zlib(input
: &[u8], level
: u8) -> Vec
<u8> {
117 compress_to_vec_inner(input
, level
, 1, 0)
120 /// Simple function to compress data to a vec.
121 fn compress_to_vec_inner(input
: &[u8], level
: u8, window_bits
: i32, strategy
: i32) -> Vec
<u8> {
122 // The comp flags function sets the zlib flag if the window_bits parameter is > 0.
123 let flags
= create_comp_flags_from_zip_params(level
.into(), window_bits
, strategy
);
124 let mut compressor
= CompressorOxide
::new(flags
);
125 let mut output
= vec
![0; ::core
::cmp
::max(input
.len() / 2, 2)];
130 let (status
, bytes_in
, bytes_out
) = compress(
133 &mut output
[out_pos
..],
137 out_pos
+= bytes_out
;
141 TDEFLStatus
::Done
=> {
142 output
.truncate(out_pos
);
145 TDEFLStatus
::Okay
=> {
146 // We need more space, so resize the vector.
147 if output
.len().saturating_sub(out_pos
) < 30 {
148 output
.resize(output
.len() * 2, 0)
151 // Not supposed to happen unless there is a bug.
152 _
=> panic
!("Bug! Unexpectedly failed to compress!"),
161 use super::{compress_to_vec, compress_to_vec_inner, CompressionStrategy}
;
162 use crate::inflate
::decompress_to_vec
;
165 /// Test deflate example.
167 /// Check if the encoder produces the same code as the example given by Mark Adler here:
168 /// https://stackoverflow.com/questions/17398931/deflate-encoding-with-static-huffman-codes/17415203
170 fn compress_small() {
171 let test_data
= b
"Deflate late";
173 0x73, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49, 0x55, 0x00, 0x11, 0x00,
176 let res
= compress_to_vec(test_data
, 1);
177 assert_eq
!(&check
[..], res
.as_slice());
179 let res
= compress_to_vec(test_data
, 9);
180 assert_eq
!(&check
[..], res
.as_slice());
184 fn compress_huff_only() {
185 let test_data
= b
"Deflate late";
187 let res
= compress_to_vec_inner(test_data
, 1, 0, CompressionStrategy
::HuffmanOnly
as i32);
188 let d
= decompress_to_vec(res
.as_slice()).expect("Failed to decompress!");
189 assert_eq
!(test_data
, d
.as_slice());
192 /// Test that a raw block compresses fine.
195 let text
= b
"Hello, zlib!";
197 let len
= text
.len();
199 let mut encoded
= vec
![
206 encoded
.extend_from_slice(&text
[..]);
210 let res
= compress_to_vec(text
, 0);
211 assert_eq
!(encoded
, res
.as_slice());
216 let test_data
= [10, 10, 10, 10, 10, 55];
217 let c
= compress_to_vec(&test_data
, 9);
219 let d
= decompress_to_vec(c
.as_slice()).expect("Failed to decompress!");
220 assert_eq
!(&test_data
, d
.as_slice());
221 // Check that a static block is used here, rather than a raw block
222 // , so the data is actually compressed.
223 // (The optimal compressed length would be 5, but neither miniz nor zlib manages that either
224 // as neither checks matches against the byte at index 0.)
225 assert
!(c
.len() <= 6);