git_zero_core/zlib/
gzip.rs1use super::{InflateLimits, InflateStatus, Inflater, WINDOW_SIZE};
3use crate::{Error, Result, pack::crc32};
4
5pub fn decode_gzip(
9 input: &[u8],
10 output: &mut [u8],
11 window: &mut [u8; WINDOW_SIZE],
12 limits: InflateLimits,
13) -> Result<usize> {
14 let header = input.get(..10).ok_or(Error::InvalidZlib)?;
15 if header[..3] != [31, 139, 8] || header[3] & 0xe0 != 0 {
16 return Err(Error::InvalidZlib);
17 }
18 let flags = header[3];
19 let mut offset = 10;
20 if flags & 4 != 0 {
21 let length = input.get(offset..offset + 2).ok_or(Error::InvalidZlib)?;
22 offset += 2 + usize::from(u16::from_le_bytes([length[0], length[1]]));
23 input.get(..offset).ok_or(Error::InvalidZlib)?;
24 }
25 for flag in [8, 16] {
26 if flags & flag != 0 {
27 offset += input
28 .get(offset..)
29 .ok_or(Error::InvalidZlib)?
30 .iter()
31 .position(|&b| b == 0)
32 .ok_or(Error::InvalidZlib)?
33 + 1;
34 }
35 }
36 if flags & 2 != 0 {
37 let checksum = input.get(offset..offset + 2).ok_or(Error::InvalidZlib)?;
38 if u16::from_le_bytes([checksum[0], checksum[1]]) != crc32(&input[..offset]) as u16 {
39 return Err(Error::InvalidZlib);
40 }
41 offset += 2;
42 }
43 let mut decoder = Inflater::new_raw(window, limits);
44 let progress = decoder.update(input.get(offset..).ok_or(Error::InvalidZlib)?, output, true)?;
45 if progress.status != InflateStatus::Finished {
46 return Err(Error::BufferTooSmall);
47 }
48 let trailer = input
49 .get(offset + progress.consumed..)
50 .ok_or(Error::InvalidZlib)?;
51 if trailer.len() != 8
52 || trailer[..4] != crc32(&output[..progress.written]).to_le_bytes()
53 || trailer[4..] != (progress.written as u32).to_le_bytes()
54 {
55 return Err(Error::InvalidZlib);
56 }
57 Ok(progress.written)
58}