1//! This module contains functionality for decompression.
23use std::io::Cursor;
4use std::usize;
56pub mod core;
7mod output_buffer;
8pub mod stream;
9use self::core::*;
1011const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS: i32 = -4;
12const TINFL_STATUS_BAD_PARAM: i32 = -3;
13const TINFL_STATUS_ADLER32_MISMATCH: i32 = -2;
14const TINFL_STATUS_FAILED: i32 = -1;
15const TINFL_STATUS_DONE: i32 = 0;
16const TINFL_STATUS_NEEDS_MORE_INPUT: i32 = 1;
17const TINFL_STATUS_HAS_MORE_OUTPUT: i32 = 2;
1819/// Return status codes.
20#[repr(i8)]
21#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22pub enum TINFLStatus {
23/// More input data was expected, but the caller indicated that there was more data, so the
24 /// input stream is likely truncated.
25FailedCannotMakeProgress = TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS as i8,
26/// One or more of the input parameters were invalid.
27BadParam = TINFL_STATUS_BAD_PARAM as i8,
28/// The decompression went fine, but the adler32 checksum did not match the one
29 /// provided in the header.
30Adler32Mismatch = TINFL_STATUS_ADLER32_MISMATCH as i8,
31/// Failed to decompress due to invalid data.
32Failed = TINFL_STATUS_FAILED as i8,
33/// Finished decomression without issues.
34Done = TINFL_STATUS_DONE as i8,
35/// The decompressor needs more input data to continue decompressing.
36NeedsMoreInput = TINFL_STATUS_NEEDS_MORE_INPUT as i8,
37/// There is still pending data that didn't fit in the output buffer.
38HasMoreOutput = TINFL_STATUS_HAS_MORE_OUTPUT as i8,
39}
4041impl TINFLStatus {
42pub fn from_i32(value: i32) -> Option<TINFLStatus> {
43use self::TINFLStatus::*;
44match value {
45 TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS => Some(FailedCannotMakeProgress),
46 TINFL_STATUS_BAD_PARAM => Some(BadParam),
47 TINFL_STATUS_ADLER32_MISMATCH => Some(Adler32Mismatch),
48 TINFL_STATUS_FAILED => Some(Failed),
49 TINFL_STATUS_DONE => Some(Done),
50 TINFL_STATUS_NEEDS_MORE_INPUT => Some(NeedsMoreInput),
51 TINFL_STATUS_HAS_MORE_OUTPUT => Some(HasMoreOutput),
52_ => None,
53 }
54 }
55}
5657/// Decompress the deflate-encoded data in `input` to a vector.
58///
59/// Returns a status and an integer representing where the decompressor failed on failure.
60#[inline]
61pub fn decompress_to_vec(input: &[u8]) -> Result<Vec<u8>, TINFLStatus> {
62 decompress_to_vec_inner(input, 0)
63}
6465/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
66///
67/// Returns a status and an integer representing where the decompressor failed on failure.
68#[inline]
69pub fn decompress_to_vec_zlib(input: &[u8]) -> Result<Vec<u8>, TINFLStatus> {
70 decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER)
71}
7273fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result<Vec<u8>, TINFLStatus> {
74let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
75let mut ret: Vec<u8> = vec![0; input.len() * 2];
7677let mut decomp = Box::<DecompressorOxide>::default();
7879let mut in_pos = 0;
80let mut out_pos = 0;
81loop {
82let (status, in_consumed, out_consumed) = {
83// Wrap the whole output slice so we know we have enough of the
84 // decompressed data for matches.
85let mut c = Cursor::new(ret.as_mut_slice());
86 c.set_position(out_pos as u64);
87 decompress(&mut decomp, &input[in_pos..], &mut c, flags)
88 };
89 in_pos += in_consumed;
90 out_pos += out_consumed;
9192match status {
93 TINFLStatus::Done => {
94 ret.truncate(out_pos);
95return Ok(ret);
96 }
9798 TINFLStatus::HasMoreOutput => {
99// We need more space so resize the buffer.
100ret.resize(ret.len() + out_pos, 0);
101 }
102103_ => return Err(status),
104 }
105 }
106}
107108#[cfg(test)]
109mod test {
110use super::decompress_to_vec_zlib;
111112#[test]
113fn decompress_vec() {
114let encoded = [
115120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
116 ];
117let res = decompress_to_vec_zlib(&encoded[..]).unwrap();
118assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
119 }
120}