1use std::io::Cursor;
5use std::{cmp, mem};
6
7use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_LZ_DICT_SIZE};
8use crate::inflate::TINFLStatus;
9use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult};
10
11pub struct InflateState {
14 decomp: DecompressorOxide,
16
17 dict: [u8; TINFL_LZ_DICT_SIZE],
23 dict_ofs: usize,
25 dict_avail: usize,
27
28 first_call: bool,
29 has_flushed: bool,
30
31 data_format: DataFormat,
34 last_status: TINFLStatus,
35}
36
37impl Default for InflateState {
38 fn default() -> Self {
39 InflateState {
40 decomp: DecompressorOxide::default(),
41 dict: [0; TINFL_LZ_DICT_SIZE],
42 dict_ofs: 0,
43 dict_avail: 0,
44 first_call: true,
45 has_flushed: false,
46 data_format: DataFormat::Raw,
47 last_status: TINFLStatus::NeedsMoreInput,
48 }
49 }
50}
51impl InflateState {
52 pub fn new(data_format: DataFormat) -> InflateState {
61 let mut b = InflateState::default();
62 b.data_format = data_format;
63 b
64 }
65
66 pub fn new_boxed(data_format: DataFormat) -> Box<InflateState> {
72 let mut b: Box<InflateState> = Box::default();
73 b.data_format = data_format;
74 b
75 }
76
77 pub fn decompressor(&mut self) -> &mut DecompressorOxide {
79 &mut self.decomp
80 }
81
82 pub fn last_status(&self) -> TINFLStatus {
84 self.last_status
85 }
86
87 pub fn new_boxed_with_window_bits(window_bits: i32) -> Box<InflateState> {
93 let mut b: Box<InflateState> = Box::default();
94 b.data_format = DataFormat::from_window_bits(window_bits);
95 b
96 }
97
98 pub fn reset(&mut self, data_format: DataFormat) {
101 self.decompressor().init();
102 self.dict = [0; TINFL_LZ_DICT_SIZE];
103 self.dict_ofs = 0;
104 self.dict_avail = 0;
105 self.first_call = true;
106 self.has_flushed = false;
107 self.data_format = data_format;
108 self.last_status = TINFLStatus::NeedsMoreInput;
109 }
110}
111
112pub fn inflate(
122 state: &mut InflateState,
123 input: &[u8],
124 output: &mut [u8],
125 flush: MZFlush,
126) -> StreamResult {
127 let mut bytes_consumed = 0;
128 let mut bytes_written = 0;
129 let mut next_in = input;
130 let mut next_out = output;
131
132 if flush == MZFlush::Full {
133 return StreamResult::error(MZError::Stream);
134 }
135
136 let mut decomp_flags = inflate_flags::TINFL_FLAG_COMPUTE_ADLER32;
137 if state.data_format == DataFormat::Zlib {
138 decomp_flags |= inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER;
139 }
140
141 let first_call = state.first_call;
142 state.first_call = false;
143 if (state.last_status as i32) < 0 {
144 return StreamResult::error(MZError::Data);
145 }
146
147 if state.has_flushed && (flush != MZFlush::Finish) {
148 return StreamResult::error(MZError::Stream);
149 }
150 state.has_flushed |= flush == MZFlush::Finish;
151
152 if (flush == MZFlush::Finish) && first_call {
153 decomp_flags |= inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
154
155 let status = decompress(
156 &mut state.decomp,
157 next_in,
158 &mut Cursor::new(next_out),
159 decomp_flags,
160 );
161 let in_bytes = status.1;
162 let out_bytes = status.2;
163 let status = status.0;
164
165 state.last_status = status;
166
167 bytes_consumed += in_bytes;
168 bytes_written += out_bytes;
169
170 let ret_status = {
171 if (status as i32) < 0 {
172 Err(MZError::Data)
173 } else if status != TINFLStatus::Done {
174 state.last_status = TINFLStatus::Failed;
175 Err(MZError::Buf)
176 } else {
177 Ok(MZStatus::StreamEnd)
178 }
179 };
180 return StreamResult {
181 bytes_consumed,
182 bytes_written,
183 status: ret_status,
184 };
185 }
186
187 if flush != MZFlush::Finish {
188 decomp_flags |= inflate_flags::TINFL_FLAG_HAS_MORE_INPUT;
189 }
190
191 if state.dict_avail != 0 {
192 bytes_written += push_dict_out(state, &mut next_out);
193 return StreamResult {
194 bytes_consumed,
195 bytes_written,
196 status: Ok(
197 if (state.last_status == TINFLStatus::Done) && (state.dict_avail == 0) {
198 MZStatus::StreamEnd
199 } else {
200 MZStatus::Ok
201 },
202 ),
203 };
204 }
205
206 let status = inflate_loop(
207 state,
208 &mut next_in,
209 &mut next_out,
210 &mut bytes_consumed,
211 &mut bytes_written,
212 decomp_flags,
213 flush,
214 );
215 StreamResult {
216 bytes_consumed,
217 bytes_written,
218 status,
219 }
220}
221
222fn inflate_loop(
223 state: &mut InflateState,
224 next_in: &mut &[u8],
225 next_out: &mut &mut [u8],
226 total_in: &mut usize,
227 total_out: &mut usize,
228 decomp_flags: u32,
229 flush: MZFlush,
230) -> MZResult {
231 let orig_in_len = next_in.len();
232 loop {
233 let status = {
234 let mut cursor = Cursor::new(&mut state.dict[..]);
235 cursor.set_position(state.dict_ofs as u64);
236 decompress(&mut state.decomp, *next_in, &mut cursor, decomp_flags)
237 };
238
239 let in_bytes = status.1;
240 let out_bytes = status.2;
241 let status = status.0;
242
243 state.last_status = status;
244
245 *next_in = &next_in[in_bytes..];
246 *total_in += in_bytes;
247
248 state.dict_avail = out_bytes;
249 *total_out += push_dict_out(state, next_out);
250
251 if (status as i32) < 0 {
253 return Err(MZError::Data);
254 }
255
256 if (status == TINFLStatus::NeedsMoreInput) && orig_in_len == 0 {
259 return Err(MZError::Buf);
260 }
261
262 if flush == MZFlush::Finish {
263 if status == TINFLStatus::Done {
264 return if state.dict_avail != 0 {
267 Err(MZError::Buf)
268 } else {
269 Ok(MZStatus::StreamEnd)
270 };
271 } else if next_out.is_empty() {
273 return Err(MZError::Buf);
274 }
275 } else {
276 let empty_buf = next_in.is_empty() || next_out.is_empty();
278 if (status == TINFLStatus::Done) || empty_buf || (state.dict_avail != 0) {
279 return if (status == TINFLStatus::Done) && (state.dict_avail == 0) {
280 Ok(MZStatus::StreamEnd)
282 } else {
283 Ok(MZStatus::Ok)
285 };
286 }
287 }
288 }
289}
290
291fn push_dict_out(state: &mut InflateState, next_out: &mut &mut [u8]) -> usize {
292 let n = cmp::min(state.dict_avail as usize, next_out.len());
293 (next_out[..n]).copy_from_slice(&state.dict[state.dict_ofs..state.dict_ofs + n]);
294 *next_out = &mut mem::replace(next_out, &mut [])[n..];
295 state.dict_avail -= n;
296 state.dict_ofs = (state.dict_ofs + (n)) & (TINFL_LZ_DICT_SIZE - 1);
297 n
298}
299
300#[cfg(test)]
301mod test {
302 use super::{inflate, InflateState};
303 use crate::{DataFormat, MZFlush, MZStatus};
304 #[test]
305 fn test_state() {
306 let encoded = [
307 120u8, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4,
308 19,
309 ];
310 let mut out = vec![0; 50];
311 let mut state = InflateState::new_boxed(DataFormat::Zlib);
312 let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish);
313 let status = res.status.expect("Failed to decompress!");
314 assert_eq!(status, MZStatus::StreamEnd);
315 assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
316 assert_eq!(res.bytes_consumed, encoded.len());
317
318 state.reset(DataFormat::Zlib);
319 let status = res.status.expect("Failed to decompress!");
320 assert_eq!(status, MZStatus::StreamEnd);
321 assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]);
322 assert_eq!(res.bytes_consumed, encoded.len());
323 }
324}