1 use std::io::Write;
2 use std::{io, mem, cmp};
3 
4 use lz77::LZ77State;
5 use output_writer::DynamicWriter;
6 use encoder_state::EncoderState;
7 use input_buffer::InputBuffer;
8 use compression_options::{CompressionOptions, MAX_HASH_CHECKS};
9 use compress::Flush;
10 use length_encode::{LeafVec, EncodedLength};
11 use huffman_table::NUM_LITERALS_AND_LENGTHS;
12 pub use huffman_table::MAX_MATCH;
13 
14 /// A counter used for checking values in debug mode.
15 /// Does nothing when debug assertions are disabled.
16 #[derive(Default)]
17 pub struct DebugCounter {
18     #[cfg(debug_assertions)]
19     count: u64,
20 }
21 
22 impl DebugCounter {
23     #[cfg(debug_assertions)]
get(&self) -> u6424     pub fn get(&self) -> u64 {
25         self.count
26     }
27 
28     #[cfg(not(debug_assertions))]
get(&self) -> u6429     pub fn get(&self) -> u64 {
30         0
31     }
32 
33     #[cfg(debug_assertions)]
reset(&mut self)34     pub fn reset(&mut self) {
35         self.count = 0;
36     }
37 
38     #[cfg(not(debug_assertions))]
reset(&self)39     pub fn reset(&self) {}
40 
41     #[cfg(debug_assertions)]
add(&mut self, val: u64)42     pub fn add(&mut self, val: u64) {
43         self.count += val;
44     }
45 
46     #[cfg(not(debug_assertions))]
add(&self, _: u64)47     pub fn add(&self, _: u64) {}
48 }
49 
50 pub struct LengthBuffers {
51     pub leaf_buf: LeafVec,
52     pub length_buf: Vec<EncodedLength>,
53 }
54 
55 impl LengthBuffers {
56     #[inline]
new() -> LengthBuffers57     fn new() -> LengthBuffers {
58         LengthBuffers {
59             leaf_buf: Vec::with_capacity(NUM_LITERALS_AND_LENGTHS),
60             length_buf: Vec::with_capacity(19),
61         }
62     }
63 }
64 
65 /// A struct containing all the stored state used for the encoder.
66 pub struct DeflateState<W: Write> {
67     /// State of lz77 compression.
68     pub lz77_state: LZ77State,
69     pub input_buffer: InputBuffer,
70     pub compression_options: CompressionOptions,
71     /// State the huffman part of the compression and the output buffer.
72     pub encoder_state: EncoderState,
73     /// The buffer containing the raw output of the lz77-encoding.
74     pub lz77_writer: DynamicWriter,
75     /// Buffers used when generating huffman code lengths.
76     pub length_buffers: LengthBuffers,
77     /// Total number of bytes consumed/written to the input buffer.
78     pub bytes_written: u64,
79     /// Wrapped writer.
80     /// Option is used to allow us to implement `Drop` and `finish()` at the same time for the
81     /// writer structs.
82     pub inner: Option<W>,
83     /// The position in the output buffer where data should be flushed from, to keep track of
84     /// what data has been output in case not all data is output when writing to the wrapped
85     /// writer.
86     pub output_buf_pos: usize,
87     pub flush_mode: Flush,
88     /// Number of bytes written as calculated by sum of block input lengths.
89     /// Used to check that they are correct when `debug_assertions` are enabled.
90     pub bytes_written_control: DebugCounter,
91 }
92 
93 impl<W: Write> DeflateState<W> {
new(compression_options: CompressionOptions, writer: W) -> DeflateState<W>94     pub fn new(compression_options: CompressionOptions, writer: W) -> DeflateState<W> {
95         DeflateState {
96             input_buffer: InputBuffer::empty(),
97             lz77_state: LZ77State::new(
98                 compression_options.max_hash_checks,
99                 cmp::min(compression_options.lazy_if_less_than, MAX_HASH_CHECKS),
100                 compression_options.matching_type,
101             ),
102             encoder_state: EncoderState::new(Vec::with_capacity(1024 * 32)),
103             lz77_writer: DynamicWriter::new(),
104             length_buffers: LengthBuffers::new(),
105             compression_options: compression_options,
106             bytes_written: 0,
107             inner: Some(writer),
108             output_buf_pos: 0,
109             flush_mode: Flush::None,
110             bytes_written_control: DebugCounter::default(),
111         }
112     }
113 
114     #[inline]
output_buf(&mut self) -> &mut Vec<u8>115     pub fn output_buf(&mut self) -> &mut Vec<u8> {
116         self.encoder_state.inner_vec()
117     }
118 
119     /// Resets the status of the decoder, leaving the compression options intact
120     ///
121     /// If flushing the current writer succeeds, it is replaced with the provided one,
122     /// buffers and status (except compression options) is reset and the old writer
123     /// is returned.
124     ///
125     /// If flushing fails, the rest of the writer is not cleared.
reset(&mut self, writer: W) -> io::Result<W>126     pub fn reset(&mut self, writer: W) -> io::Result<W> {
127         self.encoder_state.flush();
128         self.inner
129             .as_mut()
130             .expect("Missing writer!")
131             .write_all(self.encoder_state.inner_vec())?;
132         self.encoder_state.inner_vec().clear();
133         self.input_buffer = InputBuffer::empty();
134         self.lz77_writer.clear();
135         self.lz77_state.reset();
136         self.bytes_written = 0;
137         self.output_buf_pos = 0;
138         self.flush_mode = Flush::None;
139         if cfg!(debug_assertions) {
140             self.bytes_written_control.reset();
141         }
142         mem::replace(&mut self.inner, Some(writer))
143             .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Missing writer"))
144     }
145 }
146