compression_codecs/gzip/
decoder.rs1use super::header::{self, Header};
2use crate::{DecodeV2, FlateDecoder};
3use compression_core::util::{PartialBuffer, WriteBuffer};
4use flate2::Crc;
5use std::io::{Error, ErrorKind, Result};
6
7#[derive(Debug)]
8enum State {
9 Header(header::Parser),
10 Decoding,
11 Footer(PartialBuffer<Vec<u8>>),
12 Done,
13}
14
15#[derive(Debug)]
16pub struct GzipDecoder {
17 inner: FlateDecoder,
18 crc: Crc,
19 state: State,
20 header: Header,
21}
22
23fn check_footer(crc: &Crc, input: &[u8]) -> Result<()> {
24 if input.len() < 8 {
25 return Err(Error::new(
26 ErrorKind::InvalidData,
27 "Invalid gzip footer length",
28 ));
29 }
30
31 let crc_sum = crc.sum().to_le_bytes();
32 let bytes_read = crc.amount().to_le_bytes();
33
34 if crc_sum != input[0..4] {
35 return Err(Error::new(
36 ErrorKind::InvalidData,
37 "CRC computed does not match",
38 ));
39 }
40
41 if bytes_read != input[4..8] {
42 return Err(Error::new(
43 ErrorKind::InvalidData,
44 "amount of bytes read does not match",
45 ));
46 }
47
48 Ok(())
49}
50
51impl Default for GzipDecoder {
52 fn default() -> Self {
53 Self {
54 inner: FlateDecoder::new(false),
55 crc: Crc::new(),
56 state: State::Header(header::Parser::default()),
57 header: Header::default(),
58 }
59 }
60}
61
62impl GzipDecoder {
63 pub fn new() -> Self {
64 Self::default()
65 }
66
67 fn process(
68 &mut self,
69 input: &mut PartialBuffer<&[u8]>,
70 output: &mut WriteBuffer<'_>,
71 inner: impl Fn(&mut Self, &mut PartialBuffer<&[u8]>, &mut WriteBuffer<'_>) -> Result<bool>,
72 ) -> Result<bool> {
73 loop {
74 match &mut self.state {
75 State::Header(parser) => {
76 if let Some(header) = parser.input(input)? {
77 self.header = header;
78 self.state = State::Decoding;
79 }
80 }
81
82 State::Decoding => {
83 let prior = output.written_len();
84
85 let res = inner(self, input, output);
86
87 if output.written_len() > prior {
88 self.crc.update(&output.written()[prior..]);
90 }
91
92 let done = res?;
93
94 if done {
95 self.state = State::Footer(vec![0; 8].into())
96 }
97 }
98
99 State::Footer(footer) => {
100 footer.copy_unwritten_from(input);
101
102 if footer.unwritten().is_empty() {
103 check_footer(&self.crc, footer.written())?;
104 self.state = State::Done
105 }
106 }
107
108 State::Done => {}
109 };
110
111 if let State::Done = self.state {
112 return Ok(true);
113 }
114
115 if input.unwritten().is_empty() || output.has_no_spare_space() {
116 return Ok(false);
117 }
118 }
119 }
120}
121
122impl DecodeV2 for GzipDecoder {
123 fn reinit(&mut self) -> Result<()> {
124 self.inner.reinit()?;
125 self.crc = Crc::new();
126 self.state = State::Header(header::Parser::default());
127 self.header = Header::default();
128 Ok(())
129 }
130
131 fn decode(
132 &mut self,
133 input: &mut PartialBuffer<&[u8]>,
134 output: &mut WriteBuffer<'_>,
135 ) -> Result<bool> {
136 self.process(input, output, |this, input, output| {
137 this.inner.decode(input, output)
138 })
139 }
140
141 fn flush(&mut self, output: &mut WriteBuffer<'_>) -> Result<bool> {
142 loop {
143 match self.state {
144 State::Header(_) | State::Footer(_) | State::Done => return Ok(true),
145
146 State::Decoding => {
147 let prior = output.written_len();
148 let done = self.inner.flush(output)?;
149 self.crc.update(&output.written()[prior..]);
150 if done {
151 return Ok(true);
152 }
153 }
154 };
155
156 if output.has_no_spare_space() {
157 return Ok(false);
158 }
159 }
160 }
161
162 fn finish(&mut self, _output: &mut WriteBuffer<'_>) -> Result<bool> {
163 if let State::Done = self.state {
165 Ok(true)
166 } else {
167 Err(Error::from(ErrorKind::UnexpectedEof))
168 }
169 }
170}