1use std::io::Write;
2use std::io;
34use deflate_state::DeflateState;
5use encoder_state::EncoderState;
6use lzvalue::LZValue;
7use lz77::{lz77_compress_block, LZ77Status};
8use huffman_lengths::{gen_huffman_lengths, write_huffman_lengths, BlockType};
9use bitstream::LsbWriter;
10use stored_block::{compress_block_stored, write_stored_header, MAX_STORED_BLOCK_LENGTH};
1112const LARGEST_OUTPUT_BUF_SIZE: usize = 1024 * 32;
1314/// Flush mode to use when compressing input received in multiple steps.
15///
16/// (The more obscure ZLIB flush modes are not implemented.)
17#[derive(Eq, PartialEq, Debug, Copy, Clone)]
18pub enum Flush {
19// Simply wait for more input when we are out of input data to process.
20None,
21// Send a "sync block", corresponding to Z_SYNC_FLUSH in zlib. This finishes compressing and
22 // outputting all pending data, and then outputs an empty stored block.
23 // (That is, the block header indicating a stored block followed by `0000FFFF`).
24Sync,
25 _Partial,
26 _Block,
27 _Full,
28// Finish compressing and output all remaining input.
29Finish,
30}
3132/// Write all the lz77 encoded data in the buffer using the specified `EncoderState`, and finish
33/// with the end of block code.
34pub fn flush_to_bitstream(buffer: &[LZValue], state: &mut EncoderState) {
35for &b in buffer {
36 state.write_lzvalue(b.value());
37 }
38 state.write_end_of_block()
39}
4041/// Compress the input data using only fixed huffman codes.
42///
43/// Currently only used in tests.
44#[cfg(test)]
45pub fn compress_data_fixed(input: &[u8]) -> Vec<u8> {
46use lz77::lz77_compress;
4748let mut state = EncoderState::fixed(Vec::new());
49let compressed = lz77_compress(input).unwrap();
5051// We currently don't split blocks here(this function is just used for tests anyhow)
52state.write_start_of_block(true, true);
53 flush_to_bitstream(&compressed, &mut state);
5455 state.flush();
56 state.reset(Vec::new())
57}
5859fn write_stored_block(input: &[u8], mut writer: &mut LsbWriter, final_block: bool) {
6061// If the input is not zero, we write stored blocks for the input data.
62if !input.is_empty() {
63let mut i = input.chunks(MAX_STORED_BLOCK_LENGTH).peekable();
6465while let Some(chunk) = i.next() {
66let last_chunk = i.peek().is_none();
67// Write the block header
68write_stored_header(writer, final_block && last_chunk);
6970// Write the actual data.
71compress_block_stored(chunk, &mut writer).expect("Write error");
7273 }
74 } else {
75// If the input length is zero, we output an empty block. This is used for syncing.
76write_stored_header(writer, final_block);
77 compress_block_stored(&[], &mut writer).expect("Write error");
78 }
79}
8081/// Inner compression function used by both the writers and the simple compression functions.
82pub fn compress_data_dynamic_n<W: Write>(
83 input: &[u8],
84 deflate_state: &mut DeflateState<W>,
85 flush: Flush,
86) -> io::Result<usize> {
87let mut bytes_written = 0;
8889let mut slice = input;
9091loop {
92let output_buf_len = deflate_state.output_buf().len();
93let output_buf_pos = deflate_state.output_buf_pos;
94// If the output buffer has too much data in it already, flush it before doing anything
95 // else.
96if output_buf_len > LARGEST_OUTPUT_BUF_SIZE {
97let written = deflate_state
98 .inner
99 .as_mut()
100 .expect("Missing writer!")
101 .write(&deflate_state.encoder_state.inner_vec()[output_buf_pos..])?;
102103if written < output_buf_len.checked_sub(output_buf_pos).unwrap() {
104// Only some of the data was flushed, so keep track of where we were.
105deflate_state.output_buf_pos += written;
106 } else {
107// If we flushed all of the output, reset the output buffer.
108deflate_state.output_buf_pos = 0;
109 deflate_state.output_buf().clear();
110 }
111112if bytes_written == 0 {
113// If the buffer was already full when the function was called, this has to be
114 // returned rather than Ok(0) to indicate that we didn't write anything, but are
115 // not done yet.
116return Err(io::Error::new(
117 io::ErrorKind::Interrupted,
118"Internal buffer full.",
119 ));
120 } else {
121return Ok(bytes_written);
122 }
123 }
124125if deflate_state.lz77_state.is_last_block() {
126// The last block has already been written, so we don't ave anything to compress.
127break;
128 }
129130let (written, status, position) = lz77_compress_block(
131 slice,
132&mut deflate_state.lz77_state,
133&mut deflate_state.input_buffer,
134&mut deflate_state.lz77_writer,
135 flush,
136 );
137138// Bytes written in this call
139bytes_written += written;
140// Total bytes written since the compression process started
141 // TODO: Should we realistically have to worry about overflowing here?
142deflate_state.bytes_written += written as u64;
143144if status == LZ77Status::NeedInput {
145// If we've consumed all the data input so far, and we're not
146 // finishing or syncing or ending the block here, simply return
147 // the number of bytes consumed so far.
148return Ok(bytes_written);
149 }
150151// Increment start of input data
152slice = &slice[written..];
153154// We need to check if this is the last block as the header will then be
155 // slightly different to indicate this.
156let last_block = deflate_state.lz77_state.is_last_block();
157158let current_block_input_bytes = deflate_state.lz77_state.current_block_input_bytes();
159160if cfg!(debug_assertions) {
161 deflate_state
162 .bytes_written_control
163 .add(current_block_input_bytes);
164 }
165166let partial_bits = deflate_state.encoder_state.writer.pending_bits();
167168let res = {
169let (l_freqs, d_freqs) = deflate_state.lz77_writer.get_frequencies();
170let (l_lengths, d_lengths) =
171 deflate_state.encoder_state.huffman_table.get_lengths_mut();
172173 gen_huffman_lengths(
174 l_freqs,
175 d_freqs,
176 current_block_input_bytes,
177 partial_bits,
178 l_lengths,
179 d_lengths,
180&mut deflate_state.length_buffers,
181 )
182 };
183184// Check if we've actually managed to compress the input, and output stored blocks
185 // if not.
186match res {
187 BlockType::Dynamic(header) => {
188// Write the block header.
189deflate_state
190 .encoder_state
191 .write_start_of_block(false, last_block);
192193// Output the lengths of the huffman codes used in this block.
194write_huffman_lengths(
195&header,
196&deflate_state.encoder_state.huffman_table,
197&mut deflate_state.length_buffers.length_buf,
198&mut deflate_state.encoder_state.writer,
199 );
200201// Uupdate the huffman codes that will be used to encode the
202 // lz77-compressed data.
203deflate_state
204 .encoder_state
205 .huffman_table
206 .update_from_lengths();
207208209// Write the huffman compressed data and the end of block marker.
210flush_to_bitstream(
211 deflate_state.lz77_writer.get_buffer(),
212&mut deflate_state.encoder_state,
213 );
214 }
215 BlockType::Fixed => {
216// Write the block header for fixed code blocks.
217deflate_state
218 .encoder_state
219 .write_start_of_block(true, last_block);
220221// Use the pre-defined static huffman codes.
222deflate_state.encoder_state.set_huffman_to_fixed();
223224// Write the compressed data and the end of block marker.
225flush_to_bitstream(
226 deflate_state.lz77_writer.get_buffer(),
227&mut deflate_state.encoder_state,
228 );
229 }
230 BlockType::Stored => {
231// If compression fails, output a stored block instead.
232233let start_pos = position.saturating_sub(current_block_input_bytes as usize);
234235assert!(
236 position >= current_block_input_bytes as usize,
237"Error! Trying to output a stored block with forgotten data!\
238 if you encounter this error, please file an issue!"
239);
240241 write_stored_block(
242&deflate_state.input_buffer.get_buffer()[start_pos..position],
243&mut deflate_state.encoder_state.writer,
244 flush == Flush::Finish && last_block,
245 );
246 }
247 };
248249// Clear the current lz77 data in the writer for the next call.
250deflate_state.lz77_writer.clear();
251// We are done with the block, so we reset the number of bytes taken
252 // for the next one.
253deflate_state.lz77_state.reset_input_bytes();
254255// We are done for now.
256if status == LZ77Status::Finished {
257// This flush mode means that there should be an empty stored block at the end.
258if flush == Flush::Sync {
259 write_stored_block(&[], &mut deflate_state.encoder_state.writer, false);
260 } else if !deflate_state.lz77_state.is_last_block() {
261// Make sure a block with the last block header has been output.
262 // Not sure this can actually happen, but we make sure to finish properly
263 // if it somehow does.
264 // An empty fixed block is the shortest.
265let es = &mut deflate_state.encoder_state;
266 es.set_huffman_to_fixed();
267 es.write_start_of_block(true, true);
268 es.write_end_of_block();
269 }
270break;
271 }
272 }
273274// If we reach this point, the remaining data in the buffers is to be flushed.
275deflate_state.encoder_state.flush();
276// Make sure we've output everything, and return the number of bytes written if everything
277 // went well.
278let output_buf_pos = deflate_state.output_buf_pos;
279let written_to_writer = deflate_state
280 .inner
281 .as_mut()
282 .expect("Missing writer!")
283 .write(&deflate_state.encoder_state.inner_vec()[output_buf_pos..])?;
284if written_to_writer <
285 deflate_state
286 .output_buf()
287 .len()
288 .checked_sub(output_buf_pos)
289 .unwrap()
290 {
291 deflate_state.output_buf_pos += written_to_writer;
292 } else {
293// If we sucessfully wrote all the data, we can clear the output buffer.
294deflate_state.output_buf_pos = 0;
295 deflate_state.output_buf().clear();
296 }
297Ok(bytes_written)
298}
299300#[cfg(test)]
301mod test {
302use super::*;
303use test_utils::{get_test_data, decompress_to_end};
304305#[test]
306/// Test compressing a short string using fixed encoding.
307fn fixed_string_mem() {
308let test_data = String::from(" GNU GENERAL PUBLIC LICENSE").into_bytes();
309let compressed = compress_data_fixed(&test_data);
310311let result = decompress_to_end(&compressed);
312313assert_eq!(test_data, result);
314 }
315316#[test]
317fn fixed_data() {
318let data = vec![190u8; 400];
319let compressed = compress_data_fixed(&data);
320let result = decompress_to_end(&compressed);
321322assert_eq!(data, result);
323 }
324325/// Test deflate example.
326 ///
327 /// Check if the encoder produces the same code as the example given by Mark Adler here:
328 /// https://stackoverflow.com/questions/17398931/deflate-encoding-with-static-huffman-codes/17415203
329#[test]
330fn fixed_example() {
331let test_data = b"Deflate late";
332// let check =
333 // [0x73, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49, 0x55, 0xc8, 0x49, 0x2c, 0x49, 0x5, 0x0];
334let check = [
3350x73,
3360x49,
3370x4d,
3380xcb,
3390x49,
3400x2c,
3410x49,
3420x55,
3430x00,
3440x11,
3450x00,
346 ];
347let compressed = compress_data_fixed(test_data);
348assert_eq!(&compressed, &check);
349let decompressed = decompress_to_end(&compressed);
350assert_eq!(&decompressed, test_data)
351 }
352353#[test]
354/// Test compression from a file.
355fn fixed_string_file() {
356let input = get_test_data();
357358let compressed = compress_data_fixed(&input);
359println!("Fixed codes compressed len: {}", compressed.len());
360let result = decompress_to_end(&compressed);
361362assert_eq!(input.len(), result.len());
363// Not using assert_eq here deliberately to avoid massive amounts of output spam.
364assert!(input == result);
365 }
366}