1 //! This module contains functionality for decompression.
3 use crate::alloc
::boxed
::Box
;
5 use crate::alloc
::vec
::Vec
;
14 const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS
: i32 = -4;
15 const TINFL_STATUS_BAD_PARAM
: i32 = -3;
16 const TINFL_STATUS_ADLER32_MISMATCH
: i32 = -2;
17 const TINFL_STATUS_FAILED
: i32 = -1;
18 const TINFL_STATUS_DONE
: i32 = 0;
19 const TINFL_STATUS_NEEDS_MORE_INPUT
: i32 = 1;
20 const TINFL_STATUS_HAS_MORE_OUTPUT
: i32 = 2;
22 /// Return status codes.
24 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
25 pub enum TINFLStatus
{
26 /// More input data was expected, but the caller indicated that there was more data, so the
27 /// input stream is likely truncated.
28 FailedCannotMakeProgress
= TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS
as i8,
29 /// One or more of the input parameters were invalid.
30 BadParam
= TINFL_STATUS_BAD_PARAM
as i8,
31 /// The decompression went fine, but the adler32 checksum did not match the one
32 /// provided in the header.
33 Adler32Mismatch
= TINFL_STATUS_ADLER32_MISMATCH
as i8,
34 /// Failed to decompress due to invalid data.
35 Failed
= TINFL_STATUS_FAILED
as i8,
36 /// Finished decomression without issues.
37 Done
= TINFL_STATUS_DONE
as i8,
38 /// The decompressor needs more input data to continue decompressing.
39 NeedsMoreInput
= TINFL_STATUS_NEEDS_MORE_INPUT
as i8,
40 /// There is still pending data that didn't fit in the output buffer.
41 HasMoreOutput
= TINFL_STATUS_HAS_MORE_OUTPUT
as i8,
45 pub fn from_i32(value
: i32) -> Option
<TINFLStatus
> {
46 use self::TINFLStatus
::*;
48 TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS
=> Some(FailedCannotMakeProgress
),
49 TINFL_STATUS_BAD_PARAM
=> Some(BadParam
),
50 TINFL_STATUS_ADLER32_MISMATCH
=> Some(Adler32Mismatch
),
51 TINFL_STATUS_FAILED
=> Some(Failed
),
52 TINFL_STATUS_DONE
=> Some(Done
),
53 TINFL_STATUS_NEEDS_MORE_INPUT
=> Some(NeedsMoreInput
),
54 TINFL_STATUS_HAS_MORE_OUTPUT
=> Some(HasMoreOutput
),
60 /// Decompress the deflate-encoded data in `input` to a vector.
62 /// Returns a status and an integer representing where the decompressor failed on failure.
64 pub fn decompress_to_vec(input
: &[u8]) -> Result
<Vec
<u8>, TINFLStatus
> {
65 decompress_to_vec_inner(input
, 0, usize::max_value())
68 /// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
70 /// Returns a status and an integer representing where the decompressor failed on failure.
72 pub fn decompress_to_vec_zlib(input
: &[u8]) -> Result
<Vec
<u8>, TINFLStatus
> {
73 decompress_to_vec_inner(
75 inflate_flags
::TINFL_FLAG_PARSE_ZLIB_HEADER
,
80 /// Decompress the deflate-encoded data in `input` to a vector.
81 /// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
82 /// `TINFLStatus::HasMoreOutput` error is returned.
84 /// Returns a status and an integer representing where the decompressor failed on failure.
86 pub fn decompress_to_vec_with_limit(input
: &[u8], max_size
: usize) -> Result
<Vec
<u8>, TINFLStatus
> {
87 decompress_to_vec_inner(input
, 0, max_size
)
90 /// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
91 /// The vector is grown to at most `max_size` bytes; if the data does not fit in that size,
92 /// `TINFLStatus::HasMoreOutput` error is returned.
94 /// Returns a status and an integer representing where the decompressor failed on failure.
96 pub fn decompress_to_vec_zlib_with_limit(
99 ) -> Result
<Vec
<u8>, TINFLStatus
> {
100 decompress_to_vec_inner(input
, inflate_flags
::TINFL_FLAG_PARSE_ZLIB_HEADER
, max_size
)
103 fn decompress_to_vec_inner(
106 max_output_size
: usize,
107 ) -> Result
<Vec
<u8>, TINFLStatus
> {
108 let flags
= flags
| inflate_flags
::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF
;
109 let mut ret
: Vec
<u8> = vec
![0; min(input
.len().saturating_mul(2), max_output_size
)];
111 let mut decomp
= Box
::<DecompressorOxide
>::default();
116 // Wrap the whole output slice so we know we have enough of the
117 // decompressed data for matches.
118 let (status
, in_consumed
, out_consumed
) =
119 decompress(&mut decomp
, &input
[in_pos
..], &mut ret
, out_pos
, flags
);
120 in_pos
+= in_consumed
;
121 out_pos
+= out_consumed
;
124 TINFLStatus
::Done
=> {
125 ret
.truncate(out_pos
);
129 TINFLStatus
::HasMoreOutput
=> {
130 // We need more space, so check if we can resize the buffer and do it.
133 .checked_add(out_pos
)
134 .ok_or(TINFLStatus
::HasMoreOutput
)?
;
135 if new_len
> max_output_size
{
136 return Err(TINFLStatus
::HasMoreOutput
);
138 ret
.resize(new_len
, 0);
141 _
=> return Err(status
),
148 use super::TINFLStatus
;
149 use super::{decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit}
;
150 const encoded
: [u8; 20] = [
151 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
155 fn decompress_vec() {
156 let res
= decompress_to_vec_zlib(&encoded
[..]).unwrap();
157 assert_eq
!(res
.as_slice(), &b
"Hello, zlib!"[..]);
161 fn decompress_vec_with_high_limit() {
162 let res
= decompress_to_vec_zlib_with_limit(&encoded
[..], 100_000).unwrap();
163 assert_eq
!(res
.as_slice(), &b
"Hello, zlib!"[..]);
167 fn fail_to_decompress_with_limit() {
168 let res
= decompress_to_vec_zlib_with_limit(&encoded
[..], 8);
170 Err(TINFLStatus
::HasMoreOutput
) => (), // expected result
171 _
=> panic
!("Decompression output size limit was not enforced"),