git_internal/internal/zlib/stream/
inflate.rs

1use std::{io, io::BufRead};
2
3use flate2::{Decompress, FlushDecompress, Status};
4use sha1::{Digest, Sha1, digest::core_api::CoreWrapper};
5
6use crate::internal::object::types::ObjectType;
7
8/// ReadBoxed is to unzip information from a  DEFLATE stream,
9/// which hash [`BufRead`] trait.
10/// For a continuous stream of DEFLATE information, the structure
11/// does not read too many bytes to affect subsequent information
12/// reads
13pub struct ReadBoxed<R> {
14    /// The reader from which bytes should be decompressed.
15    pub inner: R,
16    /// The decompressor doing all the work.
17    pub decompressor: Box<Decompress>,
18    /// the [`count_hash`] decide whether to calculate the hash value in the [`read`] method
19    count_hash: bool,
20    pub hash: CoreWrapper<sha1::Sha1Core>,
21}
22impl<R> ReadBoxed<R>
23where
24    R: BufRead,
25{
26    /// Nen a ReadBoxed for zlib read, the Output ReadBoxed is for the Common Object,
27    /// but not for the Delta Object,if that ,see new_for_delta method below.
28    pub fn new(inner: R, obj_type: ObjectType, size: usize) -> Self {
29        let mut hash = sha1::Sha1::new();
30        hash.update(obj_type.to_bytes());
31        hash.update(b" ");
32        hash.update(size.to_string());
33        hash.update(b"\0");
34        ReadBoxed {
35            inner,
36            hash,
37            count_hash: true,
38            decompressor: Box::new(Decompress::new(true)),
39        }
40    }
41
42    pub fn new_for_delta(inner: R) -> Self {
43        ReadBoxed {
44            inner,
45            hash: Sha1::new(),
46            count_hash: false,
47            decompressor: Box::new(Decompress::new(true)),
48        }
49    }
50}
51impl<R> io::Read for ReadBoxed<R>
52where
53    R: BufRead,
54{
55    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
56        let o = read(&mut self.inner, &mut self.decompressor, into)?;
57        //update the hash value
58        if self.count_hash {
59            self.hash.update(&into[..o]);
60        }
61        Ok(o)
62    }
63}
64
65/// Read bytes from `rd` and decompress them using `state` into a pre-allocated fitting buffer `dst`, returning the amount of bytes written.
66fn read(rd: &mut impl BufRead, state: &mut Decompress, mut dst: &mut [u8]) -> io::Result<usize> {
67    let mut total_written = 0;
68    loop {
69        let (written, consumed, ret, eof);
70        {
71            let input = rd.fill_buf()?;
72            eof = input.is_empty();
73            let before_out = state.total_out();
74            let before_in = state.total_in();
75            let flush = if eof {
76                FlushDecompress::Finish
77            } else {
78                FlushDecompress::None
79            };
80            ret = state.decompress(input, dst, flush);
81            written = (state.total_out() - before_out) as usize;
82            total_written += written;
83            dst = &mut dst[written..];
84            consumed = (state.total_in() - before_in) as usize;
85        }
86        rd.consume(consumed);
87
88        match ret {
89            // The stream has officially ended, nothing more to do here.
90            Ok(Status::StreamEnd) => return Ok(total_written),
91            // Either input our output are depleted even though the stream is not depleted yet.
92            Ok(Status::Ok | Status::BufError) if eof || dst.is_empty() => return Ok(total_written),
93            // Some progress was made in both the input and the output, it must continue to reach the end.
94            Ok(Status::Ok | Status::BufError) if consumed != 0 || written != 0 => continue,
95            // A strange state, where zlib makes no progress but isn't done either. Call it out.
96            Ok(Status::Ok | Status::BufError) => unreachable!("Definitely a bug somewhere"),
97            Err(..) => {
98                return Err(io::Error::new(
99                    io::ErrorKind::InvalidInput,
100                    "corrupt deflate stream",
101                ));
102            }
103        }
104    }
105}