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