libflate/non_blocking/gzip.rs
1//! The encoder and decoder of the GZIP format.
2//!
3//! The GZIP format is defined in [RFC-1952](https://tools.ietf.org/html/rfc1952).
4//!
5//! # Examples
6//! ```
7//! use no_std_io2::io::{Read, Write};
8//! use libflate::gzip::Encoder;
9//! use libflate::non_blocking::gzip::Decoder;
10//!
11//! // Encoding
12//! let mut encoder = Encoder::new(Vec::new()).unwrap();
13//! encoder.write_all(&b"Hello World!".as_ref()).unwrap();
14//! let encoded_data = encoder.finish().into_result().unwrap();
15//!
16//! // Decoding
17//! let mut decoder = Decoder::new(&encoded_data[..]);
18//! let mut decoded_data = Vec::new();
19//! decoder.read_to_end(&mut decoded_data).unwrap();
20//!
21//! assert_eq!(decoded_data, b"Hello World!");
22//! ```
23use crate::checksum;
24use crate::gzip::{Header, Trailer};
25use crate::non_blocking::deflate;
26use no_std_io2::io::{self, Read};
27
28/// GZIP decoder which supports non-blocking I/O.
29#[derive(Debug)]
30pub struct Decoder<R> {
31 header: Option<Header>,
32 reader: deflate::Decoder<R>,
33 crc32: checksum::Crc32,
34 eos: bool,
35}
36impl<R: Read> Decoder<R> {
37 /// Makes a new decoder instance.
38 ///
39 /// `inner` is to be decoded GZIP stream.
40 ///
41 /// # Examples
42 /// ```
43 /// use no_std_io2::io::Read;
44 /// use libflate::non_blocking::gzip::Decoder;
45 ///
46 /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
47 /// 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
48 /// 163, 28, 41, 28, 12, 0, 0, 0];
49 ///
50 /// let mut decoder = Decoder::new(&encoded_data[..]);
51 /// let mut buf = Vec::new();
52 /// decoder.read_to_end(&mut buf).unwrap();
53 ///
54 /// assert_eq!(buf, b"Hello World!");
55 /// ```
56 pub fn new(inner: R) -> Self {
57 Decoder {
58 header: None,
59 reader: deflate::Decoder::new(inner),
60 crc32: checksum::Crc32::new(),
61 eos: false,
62 }
63 }
64
65 /// Returns the header of the GZIP stream.
66 ///
67 /// # Examples
68 /// ```
69 /// use libflate::gzip::Os;
70 /// use libflate::non_blocking::gzip::Decoder;
71 ///
72 /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
73 /// 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
74 /// 163, 28, 41, 28, 12, 0, 0, 0];
75 ///
76 /// let mut decoder = Decoder::new(&encoded_data[..]);
77 /// assert_eq!(decoder.header().unwrap().os(), Os::Unix);
78 /// ```
79 pub fn header(&mut self) -> io::Result<&Header> {
80 if let Some(ref header) = self.header {
81 Ok(header)
82 } else {
83 let header = self
84 .reader
85 .bit_reader_mut()
86 .transaction(|r| Header::read_from(r.as_inner_mut()))?;
87 self.header = Some(header);
88 self.header()
89 }
90 }
91
92 /// Returns the immutable reference to the inner stream.
93 pub fn as_inner_ref(&self) -> &R {
94 self.reader.as_inner_ref()
95 }
96
97 /// Returns the mutable reference to the inner stream.
98 pub fn as_inner_mut(&mut self) -> &mut R {
99 self.reader.as_inner_mut()
100 }
101
102 /// Unwraps this `Decoder`, returning the underlying reader.
103 ///
104 /// # Examples
105 /// ```
106 /// use no_std_io2::io::Cursor;
107 /// use libflate::non_blocking::gzip::Decoder;
108 ///
109 /// let encoded_data = [31, 139, 8, 0, 123, 0, 0, 0, 0, 3, 1, 12, 0, 243, 255,
110 /// 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33,
111 /// 163, 28, 41, 28, 12, 0, 0, 0];
112 ///
113 /// let decoder = Decoder::new(Cursor::new(&encoded_data[..]));
114 /// assert_eq!(decoder.into_inner().into_inner(), &encoded_data[..]);
115 /// ```
116 pub fn into_inner(self) -> R {
117 self.reader.into_inner()
118 }
119}
120impl<R: Read> Read for Decoder<R> {
121 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
122 if self.header.is_none() {
123 self.header()?;
124 }
125 if self.eos {
126 Ok(0)
127 } else {
128 let read_size = self.reader.read(buf)?;
129 if read_size == 0 {
130 let trailer = self
131 .reader
132 .bit_reader_mut()
133 .transaction(|r| Trailer::read_from(r.as_inner_mut()))?;
134 self.eos = true;
135 // checksum verification is skipped during fuzzing
136 // so that random data from fuzzer can reach actually interesting code
137 // Compilation flag 'fuzzing' is automatically set by all 3 Rust fuzzers.
138 if cfg!(not(fuzzing)) && trailer.crc32() != self.crc32.value() {
139 Err(invalid_data_error!(
140 "CRC32 mismatched: value={}, expected={}",
141 self.crc32.value(),
142 trailer.crc32()
143 ))
144 } else {
145 Ok(0)
146 }
147 } else {
148 self.crc32.update(&buf[..read_size]);
149 Ok(read_size)
150 }
151 }
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use crate::gzip::Encoder;
159 use crate::util::{WouldBlockReader, nb_read_to_end};
160 use alloc::vec::Vec;
161 use no_std_io2::io::Write;
162
163 fn decode_all(buf: &[u8]) -> io::Result<Vec<u8>> {
164 let decoder = Decoder::new(WouldBlockReader::new(buf));
165 nb_read_to_end(decoder)
166 }
167
168 #[test]
169 fn encode_works() {
170 let plain = b"Hello World! Hello GZIP!!";
171 let mut encoder = Encoder::new(Vec::new()).unwrap();
172 encoder.write_all(plain.as_ref()).unwrap();
173 let encoded = encoder.finish().into_result().unwrap();
174 assert_eq!(decode_all(&encoded).unwrap(), plain);
175 }
176
177 #[test]
178 fn decode_works_noncompressed_block_offset_sync() {
179 let encoded = include_bytes!("../../data/noncompressed_block_offset_sync/offset.gz");
180 let decoded = include_bytes!("../../data/noncompressed_block_offset_sync/offset");
181 // decode_all(encoded).unwrap();
182 assert_eq!(decode_all(encoded).unwrap(), decoded.to_vec());
183 }
184}