Skip to main content

flate2/gz/
read.rs

1use crate::io;
2use crate::io::{Read, Write};
3
4use super::bufread;
5use super::{GzBuilder, GzHeader};
6use crate::bufreader::BufReader;
7use crate::Compression;
8
9/// A gzip streaming encoder
10///
11/// This structure implements a [`Read`] interface. When read from, it reads
12/// uncompressed data from the underlying [`Read`] and provides the compressed data.
13///
14/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
15///
16/// # Examples
17///
18/// ```
19/// use std::io::prelude::*;
20/// use std::io;
21/// use flate2::Compression;
22/// use flate2::read::GzEncoder;
23///
24/// // Return a vector containing the GZ compressed version of hello world
25///
26/// fn gzencode_hello_world() -> io::Result<Vec<u8>> {
27///     let mut ret_vec = Vec::new();
28///     let bytestring = b"hello world";
29///     let mut gz = GzEncoder::new(&bytestring[..], Compression::fast());
30///     gz.read_to_end(&mut ret_vec)?;
31///     Ok(ret_vec)
32/// }
33/// ```
34#[derive(Debug)]
35pub struct GzEncoder<R> {
36    inner: bufread::GzEncoder<BufReader<R>>,
37}
38
39pub fn gz_encoder<R: Read>(inner: bufread::GzEncoder<BufReader<R>>) -> GzEncoder<R> {
40    GzEncoder { inner }
41}
42
43impl<R: Read> GzEncoder<R> {
44    /// Creates a new encoder which will use the given compression level.
45    ///
46    /// The encoder is not configured specially for the emitted header. For
47    /// header configuration, see the `GzBuilder` type.
48    ///
49    /// The data read from the stream `r` will be compressed and available
50    /// through the returned reader.
51    pub fn new(r: R, level: Compression) -> GzEncoder<R> {
52        GzBuilder::new().read(r, level)
53    }
54}
55
56impl<R> GzEncoder<R> {
57    /// Acquires a reference to the underlying reader.
58    pub fn get_ref(&self) -> &R {
59        self.inner.get_ref().get_ref()
60    }
61
62    /// Acquires a mutable reference to the underlying reader.
63    ///
64    /// The underlying reader may be mutated as long as its unread input and
65    /// current position are preserved for subsequent reads by this encoder.
66    ///
67    /// To process a new stream, wait for this encoder to reach EOF and create a
68    /// new encoder; replacing the reader directly does not reset it.
69    pub fn get_mut(&mut self) -> &mut R {
70        self.inner.get_mut().get_mut()
71    }
72
73    /// Returns the underlying stream, consuming this encoder
74    pub fn into_inner(self) -> R {
75        self.inner.into_inner().into_inner()
76    }
77}
78
79impl<R: Read> Read for GzEncoder<R> {
80    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
81        self.inner.read(into)
82    }
83}
84
85impl<R: Read + Write> Write for GzEncoder<R> {
86    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
87        self.get_mut().write(buf)
88    }
89
90    fn flush(&mut self) -> io::Result<()> {
91        self.get_mut().flush()
92    }
93}
94
95/// A decoder for a single member of a [gzip file].
96///
97/// This structure implements a [`Read`] interface. When read from, it reads
98/// compressed data from the underlying [`Read`] and provides the uncompressed data.
99///
100/// After reading a single member of the gzip data this reader will return
101/// Ok(0) even if there are more bytes available in the underlying reader.
102/// `GzDecoder` may have read additional bytes past the end of the gzip data.
103/// If you need the following bytes, wrap the `Reader` in a `std::io::BufReader`
104/// and use `bufread::GzDecoder` instead.
105///
106/// To handle gzip files that may have multiple members, see [`MultiGzDecoder`]
107/// or read more
108/// [in the introduction](../index.html#about-multi-member-gzip-files).
109///
110/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
111///
112/// # Examples
113///
114/// ```
115/// use std::io::prelude::*;
116/// use std::io;
117/// # use flate2::Compression;
118/// # use flate2::write::GzEncoder;
119/// use flate2::read::GzDecoder;
120///
121/// # fn main() {
122/// #    let mut e = GzEncoder::new(Vec::new(), Compression::default());
123/// #    e.write_all(b"Hello World").unwrap();
124/// #    let bytes = e.finish().unwrap();
125/// #    println!("{}", decode_reader(bytes).unwrap());
126/// # }
127/// #
128/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error
129/// // Here &[u8] implements Read
130///
131/// fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
132///    let mut gz = GzDecoder::new(&bytes[..]);
133///    let mut s = String::new();
134///    gz.read_to_string(&mut s)?;
135///    Ok(s)
136/// }
137/// ```
138#[derive(Debug)]
139pub struct GzDecoder<R> {
140    inner: bufread::GzDecoder<BufReader<R>>,
141}
142
143impl<R: Read> GzDecoder<R> {
144    /// Creates a new decoder from the given reader, immediately parsing the
145    /// gzip header.
146    pub fn new(r: R) -> GzDecoder<R> {
147        GzDecoder {
148            inner: bufread::GzDecoder::new(BufReader::new(r)),
149        }
150    }
151}
152
153impl<R> GzDecoder<R> {
154    /// Returns the header associated with this stream, if it was valid.
155    pub fn header(&self) -> Option<&GzHeader> {
156        self.inner.header()
157    }
158
159    /// Acquires a reference to the underlying reader.
160    ///
161    /// Note that the decoder may have read past the end of the gzip data.
162    /// To prevent this use [`bufread::GzDecoder`] instead.
163    pub fn get_ref(&self) -> &R {
164        self.inner.get_ref().get_ref()
165    }
166
167    /// Acquires a mutable reference to the underlying stream.
168    ///
169    /// The underlying reader may be mutated as long as its unread input and
170    /// current position are preserved for subsequent reads by this decoder.
171    ///
172    /// To process a new stream, wait for this decoder to reach EOF and use
173    /// [`reset`](Self::reset); replacing the reader directly does not reset it.
174    ///
175    /// Note that the decoder may have read past the end of the gzip data.
176    /// To prevent this use [`bufread::GzDecoder`] instead.
177    pub fn get_mut(&mut self) -> &mut R {
178        self.inner.get_mut().get_mut()
179    }
180
181    /// Consumes this decoder, returning the underlying reader.
182    ///
183    /// Note that the decoder may have read past the end of the gzip data.
184    /// Subsequent reads will skip those bytes. To prevent this use
185    /// [`bufread::GzDecoder`] instead.
186    pub fn into_inner(self) -> R {
187        self.inner.into_inner().into_inner()
188    }
189
190    /// Resets the state of this decoder entirely, swapping out the input
191    /// stream for another.
192    ///
193    /// This will reset the internal state of this decoder and replace the
194    /// input stream with the one provided, returning the previous input
195    /// stream. Future data read from this decoder will be the decompressed
196    /// version of `r`'s data.
197    ///
198    /// Note that there may be currently buffered data when this function is
199    /// called, and in that case the buffered data is discarded.
200    pub fn reset(&mut self, r: R) -> R {
201        super::bufread::reset_decoder_data(&mut self.inner);
202        self.inner.get_mut().reset(r)
203    }
204}
205
206impl<R: Read> Read for GzDecoder<R> {
207    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
208        self.inner.read(into)
209    }
210}
211
212impl<R: Read + Write> Write for GzDecoder<R> {
213    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
214        self.get_mut().write(buf)
215    }
216
217    fn flush(&mut self) -> io::Result<()> {
218        self.get_mut().flush()
219    }
220}
221
222/// A gzip streaming decoder that decodes a [gzip file] that may have multiple members.
223///
224/// This structure implements a [`Read`] interface. When read from, it reads
225/// compressed data from the underlying [`Read`] and provides the uncompressed
226/// data.
227///
228/// A gzip file consists of a series of *members* concatenated one after another.
229/// MultiGzDecoder decodes all members of a file and returns Ok(0) once the
230/// underlying reader does.
231///
232/// To handle members separately, see [GzDecoder] or read more
233/// [in the introduction](../index.html#about-multi-member-gzip-files).
234///
235/// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5
236///
237/// # Examples
238///
239/// ```
240/// use std::io::prelude::*;
241/// use std::io;
242/// # use flate2::Compression;
243/// # use flate2::write::GzEncoder;
244/// use flate2::read::MultiGzDecoder;
245///
246/// # fn main() {
247/// #    let mut e = GzEncoder::new(Vec::new(), Compression::default());
248/// #    e.write_all(b"Hello World").unwrap();
249/// #    let bytes = e.finish().unwrap();
250/// #    println!("{}", decode_reader(bytes).unwrap());
251/// # }
252/// #
253/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error
254/// // Here &[u8] implements Read
255///
256/// fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
257///    let mut gz = MultiGzDecoder::new(&bytes[..]);
258///    let mut s = String::new();
259///    gz.read_to_string(&mut s)?;
260///    Ok(s)
261/// }
262/// ```
263#[derive(Debug)]
264pub struct MultiGzDecoder<R> {
265    inner: bufread::MultiGzDecoder<BufReader<R>>,
266}
267
268impl<R: Read> MultiGzDecoder<R> {
269    /// Creates a new decoder from the given reader, immediately parsing the
270    /// (first) gzip header. If the gzip stream contains multiple members all will
271    /// be decoded.
272    pub fn new(r: R) -> MultiGzDecoder<R> {
273        MultiGzDecoder {
274            inner: bufread::MultiGzDecoder::new(BufReader::new(r)),
275        }
276    }
277}
278
279impl<R> MultiGzDecoder<R> {
280    /// Returns the current header associated with this stream, if it's valid.
281    pub fn header(&self) -> Option<&GzHeader> {
282        self.inner.header()
283    }
284
285    /// Acquires a reference to the underlying reader.
286    pub fn get_ref(&self) -> &R {
287        self.inner.get_ref().get_ref()
288    }
289
290    /// Acquires a mutable reference to the underlying stream.
291    ///
292    /// The underlying reader may be mutated as long as its unread input and
293    /// current position are preserved for subsequent reads by this decoder.
294    ///
295    /// To process a new stream, wait for this decoder to reach EOF and create a
296    /// new decoder; replacing the reader directly does not reset it.
297    pub fn get_mut(&mut self) -> &mut R {
298        self.inner.get_mut().get_mut()
299    }
300
301    /// Consumes this decoder, returning the underlying reader.
302    pub fn into_inner(self) -> R {
303        self.inner.into_inner().into_inner()
304    }
305}
306
307impl<R: Read> Read for MultiGzDecoder<R> {
308    fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
309        self.inner.read(into)
310    }
311}
312
313impl<R: Read + Write> Write for MultiGzDecoder<R> {
314    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
315        self.get_mut().write(buf)
316    }
317
318    fn flush(&mut self) -> io::Result<()> {
319        self.get_mut().flush()
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use crate::io::{Cursor, ErrorKind, Read, Result, Write};
326    use alloc::vec::Vec;
327
328    use super::GzDecoder;
329
330    //a cursor turning EOF into blocking errors
331    #[derive(Debug)]
332    pub struct BlockingCursor {
333        pub cursor: Cursor<Vec<u8>>,
334    }
335
336    impl BlockingCursor {
337        pub fn new() -> BlockingCursor {
338            BlockingCursor {
339                cursor: Cursor::new(Vec::new()),
340            }
341        }
342
343        pub fn set_position(&mut self, pos: u64) {
344            self.cursor.set_position(pos)
345        }
346    }
347
348    impl Write for BlockingCursor {
349        fn write(&mut self, buf: &[u8]) -> Result<usize> {
350            self.cursor.write(buf)
351        }
352        fn flush(&mut self) -> Result<()> {
353            self.cursor.flush()
354        }
355    }
356
357    impl Read for BlockingCursor {
358        fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
359            //use the cursor, except it turns eof into blocking error
360            let r = self.cursor.read(buf);
361            match r {
362                Err(ref err) => {
363                    if err.kind() == ErrorKind::UnexpectedEof {
364                        return Err(ErrorKind::WouldBlock.into());
365                    }
366                }
367                Ok(0) => {
368                    //regular EOF turned into blocking error
369                    return Err(ErrorKind::WouldBlock.into());
370                }
371                Ok(_n) => {}
372            }
373            r
374        }
375    }
376
377    #[test]
378    fn blocked_partial_header_read() {
379        // this is a reader which receives data afterwards
380        let mut r = BlockingCursor::new();
381        let data = vec![1, 2, 3];
382
383        match r.write_all(&data) {
384            Ok(()) => {}
385            _ => {
386                panic!("Unexpected result for write_all");
387            }
388        }
389        r.set_position(0);
390
391        // this is unused except for the buffering
392        let mut decoder = GzDecoder::new(r);
393        let mut out = Vec::with_capacity(7);
394        match decoder.read(&mut out) {
395            Err(e) => {
396                assert_eq!(e.kind(), ErrorKind::WouldBlock);
397            }
398            _ => {
399                panic!("Unexpected result for decoder.read");
400            }
401        }
402    }
403
404    fn compress_data(data: &[u8]) -> Vec<u8> {
405        use crate::write::GzEncoder;
406        use crate::Compression;
407
408        let mut e = GzEncoder::new(Vec::new(), Compression::default());
409        e.write_all(data).unwrap();
410        e.finish().unwrap()
411    }
412
413    #[test]
414    fn decode_with_reset() {
415        let data1 = b"Hello World";
416        let data2 = b"Goodbye World";
417
418        let compressed1 = compress_data(data1);
419        let compressed2 = compress_data(data2);
420
421        let mut output = Vec::new();
422        let mut decoder = GzDecoder::new(compressed1.as_slice());
423        decoder.read_to_end(&mut output).unwrap();
424        assert_eq!(output, data1);
425
426        output.clear();
427        decoder.reset(compressed2.as_slice());
428        decoder.read_to_end(&mut output).unwrap();
429        assert_eq!(output, data2);
430    }
431
432    #[test]
433    fn decode_with_reset_after_corruption() {
434        let valid_data = b"Hello World";
435        let valid_compressed = compress_data(valid_data);
436
437        // Create a corrupted payload (valid gzip header but corrupted body)
438        let mut corrupted = valid_compressed.clone();
439        assert!(corrupted.len() > 13);
440        corrupted[12] ^= 0xFF;
441        corrupted[13] ^= 0xFF;
442
443        // Try to decode corrupted data
444        let mut decoder = GzDecoder::new(Cursor::new(corrupted));
445        let mut output = Vec::new();
446        let _ = decoder.read_to_end(&mut output).unwrap_err();
447
448        // Reset with valid payload and decode
449        decoder.reset(Cursor::new(valid_compressed));
450        output.clear();
451        decoder.read_to_end(&mut output).unwrap();
452        assert_eq!(output, valid_data);
453    }
454}