git_internal/internal/zlib/stream/
inflate.rs1use 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
8pub struct ReadBoxed<R> {
14 pub inner: R,
16 pub decompressor: Box<Decompress>,
18 count_hash: bool,
20 pub hash: CoreWrapper<sha1::Sha1Core>,
21}
22impl<R> ReadBoxed<R>
23where
24 R: BufRead,
25{
26 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 if self.count_hash {
59 self.hash.update(&into[..o]);
60 }
61 Ok(o)
62 }
63}
64
65fn 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 Ok(Status::StreamEnd) => return Ok(total_written),
91 Ok(Status::Ok | Status::BufError) if eof || dst.is_empty() => return Ok(total_written),
93 Ok(Status::Ok | Status::BufError) if consumed != 0 || written != 0 => continue,
95 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}