use std::io; use std::io::prelude::*; use super::bufread; use super::{GzBuilder, GzHeader}; use crate::bufreader::BufReader; use crate::Compression; /// A gzip streaming encoder /// /// This structure implements a [`Read`] interface. When read from, it reads /// uncompressed data from the underlying [`Read`] and provides the compressed data. /// /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html /// /// # Examples /// /// ``` /// use std::io::prelude::*; /// use std::io; /// use flate2::Compression; /// use flate2::read::GzEncoder; /// /// // Return a vector containing the GZ compressed version of hello world /// /// fn gzencode_hello_world() -> io::Result> { /// let mut ret_vec = Vec::new(); /// let bytestring = b"hello world"; /// let mut gz = GzEncoder::new(&bytestring[..], Compression::fast()); /// gz.read_to_end(&mut ret_vec)?; /// Ok(ret_vec) /// } /// ``` #[derive(Debug)] pub struct GzEncoder { inner: bufread::GzEncoder>, } pub fn gz_encoder(inner: bufread::GzEncoder>) -> GzEncoder { GzEncoder { inner } } impl GzEncoder { /// Creates a new encoder which will use the given compression level. /// /// The encoder is not configured specially for the emitted header. For /// header configuration, see the `GzBuilder` type. /// /// The data read from the stream `r` will be compressed and available /// through the returned reader. pub fn new(r: R, level: Compression) -> GzEncoder { GzBuilder::new().read(r, level) } } impl GzEncoder { /// Acquires a reference to the underlying reader. pub fn get_ref(&self) -> &R { self.inner.get_ref().get_ref() } /// Acquires a mutable reference to the underlying reader. /// /// Note that mutation of the reader may result in surprising results if /// this encoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.inner.get_mut().get_mut() } /// Returns the underlying stream, consuming this encoder pub fn into_inner(self) -> R { self.inner.into_inner().into_inner() } } impl Read for GzEncoder { fn read(&mut self, into: &mut [u8]) -> io::Result { self.inner.read(into) } } impl Write for GzEncoder { fn write(&mut self, buf: &[u8]) -> io::Result { self.get_mut().write(buf) } fn flush(&mut self) -> io::Result<()> { self.get_mut().flush() } } /// A decoder for a single member of a [gzip file]. /// /// This structure implements a [`Read`] interface. When read from, it reads /// compressed data from the underlying [`Read`] and provides the uncompressed data. /// /// After reading a single member of the gzip data this reader will return /// Ok(0) even if there are more bytes available in the underlying reader. /// `GzDecoder` may have read additional bytes past the end of the gzip data. /// If you need the following bytes, wrap the `Reader` in a `std::io::BufReader` /// and use `bufread::GzDecoder` instead. /// /// To handle gzip files that may have multiple members, see [`MultiGzDecoder`] /// or read more /// [in the introduction](../index.html#about-multi-member-gzip-files). /// /// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5 /// /// # Examples /// /// ``` /// use std::io::prelude::*; /// use std::io; /// # use flate2::Compression; /// # use flate2::write::GzEncoder; /// use flate2::read::GzDecoder; /// /// # fn main() { /// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); /// # e.write_all(b"Hello World").unwrap(); /// # let bytes = e.finish().unwrap(); /// # println!("{}", decode_reader(bytes).unwrap()); /// # } /// # /// // Uncompresses a Gz Encoded vector of bytes and returns a string or error /// // Here &[u8] implements Read /// /// fn decode_reader(bytes: Vec) -> io::Result { /// let mut gz = GzDecoder::new(&bytes[..]); /// let mut s = String::new(); /// gz.read_to_string(&mut s)?; /// Ok(s) /// } /// ``` #[derive(Debug)] pub struct GzDecoder { inner: bufread::GzDecoder>, } impl GzDecoder { /// Creates a new decoder from the given reader, immediately parsing the /// gzip header. pub fn new(r: R) -> GzDecoder { GzDecoder { inner: bufread::GzDecoder::new(BufReader::new(r)), } } } impl GzDecoder { /// Returns the header associated with this stream, if it was valid. pub fn header(&self) -> Option<&GzHeader> { self.inner.header() } /// Acquires a reference to the underlying reader. /// /// Note that the decoder may have read past the end of the gzip data. /// To prevent this use [`bufread::GzDecoder`] instead. pub fn get_ref(&self) -> &R { self.inner.get_ref().get_ref() } /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if /// this decoder continues to be used. /// /// Note that the decoder may have read past the end of the gzip data. /// To prevent this use [`bufread::GzDecoder`] instead. pub fn get_mut(&mut self) -> &mut R { self.inner.get_mut().get_mut() } /// Consumes this decoder, returning the underlying reader. /// /// Note that the decoder may have read past the end of the gzip data. /// Subsequent reads will skip those bytes. To prevent this use /// [`bufread::GzDecoder`] instead. pub fn into_inner(self) -> R { self.inner.into_inner().into_inner() } } impl Read for GzDecoder { fn read(&mut self, into: &mut [u8]) -> io::Result { self.inner.read(into) } } impl Write for GzDecoder { fn write(&mut self, buf: &[u8]) -> io::Result { self.get_mut().write(buf) } fn flush(&mut self) -> io::Result<()> { self.get_mut().flush() } } /// A gzip streaming decoder that decodes a [gzip file] that may have multiple members. /// /// This structure implements a [`Read`] interface. When read from, it reads /// compressed data from the underlying [`Read`] and provides the uncompressed /// data. /// /// A gzip file consists of a series of *members* concatenated one after another. /// MultiGzDecoder decodes all members of a file and returns Ok(0) once the /// underlying reader does. /// /// To handle members seperately, see [GzDecoder] or read more /// [in the introduction](../index.html#about-multi-member-gzip-files). /// /// [gzip file]: https://www.rfc-editor.org/rfc/rfc1952#page-5 /// /// # Examples /// /// ``` /// use std::io::prelude::*; /// use std::io; /// # use flate2::Compression; /// # use flate2::write::GzEncoder; /// use flate2::read::MultiGzDecoder; /// /// # fn main() { /// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); /// # e.write_all(b"Hello World").unwrap(); /// # let bytes = e.finish().unwrap(); /// # println!("{}", decode_reader(bytes).unwrap()); /// # } /// # /// // Uncompresses a Gz Encoded vector of bytes and returns a string or error /// // Here &[u8] implements Read /// /// fn decode_reader(bytes: Vec) -> io::Result { /// let mut gz = MultiGzDecoder::new(&bytes[..]); /// let mut s = String::new(); /// gz.read_to_string(&mut s)?; /// Ok(s) /// } /// ``` #[derive(Debug)] pub struct MultiGzDecoder { inner: bufread::MultiGzDecoder>, } impl MultiGzDecoder { /// Creates a new decoder from the given reader, immediately parsing the /// (first) gzip header. If the gzip stream contains multiple members all will /// be decoded. pub fn new(r: R) -> MultiGzDecoder { MultiGzDecoder { inner: bufread::MultiGzDecoder::new(BufReader::new(r)), } } } impl MultiGzDecoder { /// Returns the current header associated with this stream, if it's valid. pub fn header(&self) -> Option<&GzHeader> { self.inner.header() } /// Acquires a reference to the underlying reader. pub fn get_ref(&self) -> &R { self.inner.get_ref().get_ref() } /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if /// this decoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.inner.get_mut().get_mut() } /// Consumes this decoder, returning the underlying reader. pub fn into_inner(self) -> R { self.inner.into_inner().into_inner() } } impl Read for MultiGzDecoder { fn read(&mut self, into: &mut [u8]) -> io::Result { self.inner.read(into) } } impl Write for MultiGzDecoder { fn write(&mut self, buf: &[u8]) -> io::Result { self.get_mut().write(buf) } fn flush(&mut self) -> io::Result<()> { self.get_mut().flush() } } #[cfg(test)] mod tests { use std::io::{Cursor, ErrorKind, Read, Result, Write}; use super::GzDecoder; //a cursor turning EOF into blocking errors #[derive(Debug)] pub struct BlockingCursor { pub cursor: Cursor>, } impl BlockingCursor { pub fn new() -> BlockingCursor { BlockingCursor { cursor: Cursor::new(Vec::new()), } } pub fn set_position(&mut self, pos: u64) { return self.cursor.set_position(pos); } } impl Write for BlockingCursor { fn write(&mut self, buf: &[u8]) -> Result { return self.cursor.write(buf); } fn flush(&mut self) -> Result<()> { return self.cursor.flush(); } } impl Read for BlockingCursor { fn read(&mut self, buf: &mut [u8]) -> Result { //use the cursor, except it turns eof into blocking error let r = self.cursor.read(buf); match r { Err(ref err) => { if err.kind() == ErrorKind::UnexpectedEof { return Err(ErrorKind::WouldBlock.into()); } } Ok(0) => { //regular EOF turned into blocking error return Err(ErrorKind::WouldBlock.into()); } Ok(_n) => {} } return r; } } #[test] fn blocked_partial_header_read() { // this is a reader which receives data afterwards let mut r = BlockingCursor::new(); let data = vec![1, 2, 3]; match r.write_all(&data) { Ok(()) => {} _ => { panic!("Unexpected result for write_all"); } } r.set_position(0); // this is unused except for the buffering let mut decoder = GzDecoder::new(r); let mut out = Vec::with_capacity(7); match decoder.read(&mut out) { Err(e) => { assert_eq!(e.kind(), ErrorKind::WouldBlock); } _ => { panic!("Unexpected result for decoder.read"); } } } }