]> git.proxmox.com Git - rustc.git/blame - vendor/miniz_oxide/src/inflate/mod.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / vendor / miniz_oxide / src / inflate / mod.rs
CommitLineData
f035d41b
XL
1//! This module contains functionality for decompression.
2
1b1a35ee 3use ::core::cmp::min;
3dfed10e 4use ::core::usize;
1b1a35ee
XL
5use crate::alloc::boxed::Box;
6use crate::alloc::vec;
7use crate::alloc::vec::Vec;
f035d41b
XL
8
9pub mod core;
10mod output_buffer;
11pub mod stream;
12use self::core::*;
13
14const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS: i32 = -4;
15const TINFL_STATUS_BAD_PARAM: i32 = -3;
16const TINFL_STATUS_ADLER32_MISMATCH: i32 = -2;
17const TINFL_STATUS_FAILED: i32 = -1;
18const TINFL_STATUS_DONE: i32 = 0;
19const TINFL_STATUS_NEEDS_MORE_INPUT: i32 = 1;
20const TINFL_STATUS_HAS_MORE_OUTPUT: i32 = 2;
21
22/// Return status codes.
23#[repr(i8)]
24#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
25pub 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,
42}
43
44impl TINFLStatus {
45 pub fn from_i32(value: i32) -> Option<TINFLStatus> {
46 use self::TINFLStatus::*;
47 match value {
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),
55 _ => None,
56 }
57 }
58}
59
60/// Decompress the deflate-encoded data in `input` to a vector.
61///
62/// Returns a status and an integer representing where the decompressor failed on failure.
63#[inline]
64pub fn decompress_to_vec(input: &[u8]) -> Result<Vec<u8>, TINFLStatus> {
1b1a35ee 65 decompress_to_vec_inner(input, 0, usize::max_value())
f035d41b
XL
66}
67
68/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector.
69///
70/// Returns a status and an integer representing where the decompressor failed on failure.
71#[inline]
72pub fn decompress_to_vec_zlib(input: &[u8]) -> Result<Vec<u8>, TINFLStatus> {
1b1a35ee
XL
73 decompress_to_vec_inner(
74 input,
75 inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER,
76 usize::max_value(),
77 )
f035d41b
XL
78}
79
1b1a35ee
XL
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.
83///
84/// Returns a status and an integer representing where the decompressor failed on failure.
85#[inline]
86pub fn decompress_to_vec_with_limit(input: &[u8], max_size: usize) -> Result<Vec<u8>, TINFLStatus> {
87 decompress_to_vec_inner(input, 0, max_size)
88}
89
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.
93///
94/// Returns a status and an integer representing where the decompressor failed on failure.
95#[inline]
96pub fn decompress_to_vec_zlib_with_limit(
97 input: &[u8],
98 max_size: usize,
99) -> Result<Vec<u8>, TINFLStatus> {
100 decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size)
101}
102
103fn decompress_to_vec_inner(
104 input: &[u8],
105 flags: u32,
106 max_output_size: usize,
107) -> Result<Vec<u8>, TINFLStatus> {
f035d41b 108 let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1b1a35ee 109 let mut ret: Vec<u8> = vec![0; min(input.len().saturating_mul(2), max_output_size)];
f035d41b
XL
110
111 let mut decomp = Box::<DecompressorOxide>::default();
112
113 let mut in_pos = 0;
114 let mut out_pos = 0;
115 loop {
3dfed10e
XL
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);
f035d41b
XL
120 in_pos += in_consumed;
121 out_pos += out_consumed;
122
123 match status {
124 TINFLStatus::Done => {
125 ret.truncate(out_pos);
126 return Ok(ret);
127 }
128
129 TINFLStatus::HasMoreOutput => {
1b1a35ee
XL
130 // We need more space, so check if we can resize the buffer and do it.
131 let new_len = ret
132 .len()
133 .checked_add(out_pos)
134 .ok_or(TINFLStatus::HasMoreOutput)?;
135 if new_len > max_output_size {
136 return Err(TINFLStatus::HasMoreOutput);
137 };
138 ret.resize(new_len, 0);
f035d41b
XL
139 }
140
141 _ => return Err(status),
142 }
143 }
144}
145
146#[cfg(test)]
147mod test {
1b1a35ee
XL
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,
152 ];
f035d41b
XL
153
154 #[test]
155 fn decompress_vec() {
f035d41b
XL
156 let res = decompress_to_vec_zlib(&encoded[..]).unwrap();
157 assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]);
158 }
1b1a35ee
XL
159
160 #[test]
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!"[..]);
164 }
165
166 #[test]
167 fn fail_to_decompress_with_limit() {
168 let res = decompress_to_vec_zlib_with_limit(&encoded[..], 8);
169 match res {
170 Err(TINFLStatus::HasMoreOutput) => (), // expected result
171 _ => panic!("Decompression output size limit was not enforced"),
172 }
173 }
f035d41b 174}