Skip to main content

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}