From a990de90fe41456a23e58bd087d2f107d321f3a1 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Fri, 19 Jul 2024 16:37:58 +0400 Subject: Deleted vendor folder --- vendor/flate2/src/gz/bufread.rs | 483 ------------------------------ vendor/flate2/src/gz/mod.rs | 644 ---------------------------------------- vendor/flate2/src/gz/read.rs | 378 ----------------------- vendor/flate2/src/gz/write.rs | 641 --------------------------------------- 4 files changed, 2146 deletions(-) delete mode 100644 vendor/flate2/src/gz/bufread.rs delete mode 100644 vendor/flate2/src/gz/mod.rs delete mode 100644 vendor/flate2/src/gz/read.rs delete mode 100644 vendor/flate2/src/gz/write.rs (limited to 'vendor/flate2/src/gz') diff --git a/vendor/flate2/src/gz/bufread.rs b/vendor/flate2/src/gz/bufread.rs deleted file mode 100644 index 679b4a7..0000000 --- a/vendor/flate2/src/gz/bufread.rs +++ /dev/null @@ -1,483 +0,0 @@ -use std::cmp; -use std::io; -use std::io::prelude::*; -use std::mem; - -use super::{corrupt, read_into, GzBuilder, GzHeader, GzHeaderParser}; -use crate::crc::CrcReader; -use crate::deflate; -use crate::Compression; - -fn copy(into: &mut [u8], from: &[u8], pos: &mut usize) -> usize { - let min = cmp::min(into.len(), from.len() - *pos); - for (slot, val) in into.iter_mut().zip(from[*pos..*pos + min].iter()) { - *slot = *val; - } - *pos += min; - min -} - -/// A gzip streaming encoder -/// -/// This structure implements a [`Read`] interface. When read from, it reads -/// uncompressed data from the underlying [`BufRead`] and provides the compressed data. -/// -/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html -/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::io; -/// use flate2::Compression; -/// use flate2::bufread::GzEncoder; -/// use std::fs::File; -/// use std::io::BufReader; -/// -/// // Opens sample file, compresses the contents and returns a Vector or error -/// // File wrapped in a BufReader implements BufRead -/// -/// fn open_hello_world() -> io::Result> { -/// let f = File::open("examples/hello_world.txt")?; -/// let b = BufReader::new(f); -/// let mut gz = GzEncoder::new(b, Compression::fast()); -/// let mut buffer = Vec::new(); -/// gz.read_to_end(&mut buffer)?; -/// Ok(buffer) -/// } -/// ``` -#[derive(Debug)] -pub struct GzEncoder { - inner: deflate::bufread::DeflateEncoder>, - header: Vec, - pos: usize, - eof: bool, -} - -pub fn gz_encoder(header: Vec, r: R, lvl: Compression) -> GzEncoder { - let crc = CrcReader::new(r); - GzEncoder { - inner: deflate::bufread::DeflateEncoder::new(crc, lvl), - header, - pos: 0, - eof: false, - } -} - -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().buf_read(r, level) - } - - fn read_footer(&mut self, into: &mut [u8]) -> io::Result { - if self.pos == 8 { - return Ok(0); - } - let crc = self.inner.get_ref().crc(); - let ref arr = [ - (crc.sum() >> 0) as u8, - (crc.sum() >> 8) as u8, - (crc.sum() >> 16) as u8, - (crc.sum() >> 24) as u8, - (crc.amount() >> 0) as u8, - (crc.amount() >> 8) as u8, - (crc.amount() >> 16) as u8, - (crc.amount() >> 24) as u8, - ]; - Ok(copy(into, arr, &mut self.pos)) - } -} - -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() - } -} - -#[inline] -fn finish(buf: &[u8; 8]) -> (u32, u32) { - let crc = ((buf[0] as u32) << 0) - | ((buf[1] as u32) << 8) - | ((buf[2] as u32) << 16) - | ((buf[3] as u32) << 24); - let amt = ((buf[4] as u32) << 0) - | ((buf[5] as u32) << 8) - | ((buf[6] as u32) << 16) - | ((buf[7] as u32) << 24); - (crc, amt) -} - -impl Read for GzEncoder { - fn read(&mut self, mut into: &mut [u8]) -> io::Result { - let mut amt = 0; - if self.eof { - return self.read_footer(into); - } else if self.pos < self.header.len() { - amt += copy(into, &self.header, &mut self.pos); - if amt == into.len() { - return Ok(amt); - } - let tmp = into; - into = &mut tmp[amt..]; - } - match self.inner.read(into)? { - 0 => { - self.eof = true; - self.pos = 0; - self.read_footer(into) - } - n => Ok(amt + n), - } - } -} - -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 [`BufRead`] 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. -/// If you need the following bytes, call `into_inner()` after Ok(0) to -/// recover the underlying reader. -/// -/// 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 -/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html -/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::io; -/// # use flate2::Compression; -/// # use flate2::write::GzEncoder; -/// use flate2::bufread::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 BufRead -/// -/// 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 { - state: GzState, - reader: CrcReader>, - multi: bool, -} - -#[derive(Debug)] -enum GzState { - Header(GzHeaderParser), - Body(GzHeader), - Finished(GzHeader, usize, [u8; 8]), - Err(io::Error), - End(Option), -} - -impl GzDecoder { - /// Creates a new decoder from the given reader, immediately parsing the - /// gzip header. - pub fn new(mut r: R) -> GzDecoder { - let mut header_parser = GzHeaderParser::new(); - - let state = match header_parser.parse(&mut r) { - Ok(_) => GzState::Body(GzHeader::from(header_parser)), - Err(ref err) if io::ErrorKind::WouldBlock == err.kind() => { - GzState::Header(header_parser) - } - Err(err) => GzState::Err(err), - }; - - GzDecoder { - state, - reader: CrcReader::new(deflate::bufread::DeflateDecoder::new(r)), - multi: false, - } - } - - fn multi(mut self, flag: bool) -> GzDecoder { - self.multi = flag; - self - } -} - -impl GzDecoder { - /// Returns the header associated with this stream, if it was valid - pub fn header(&self) -> Option<&GzHeader> { - match &self.state { - GzState::Body(header) | GzState::Finished(header, _, _) => Some(header), - GzState::End(header) => header.as_ref(), - _ => None, - } - } - - /// Acquires a reference to the underlying reader. - pub fn get_ref(&self) -> &R { - self.reader.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.reader.get_mut().get_mut() - } - - /// Consumes this decoder, returning the underlying reader. - pub fn into_inner(self) -> R { - self.reader.into_inner().into_inner() - } -} - -impl Read for GzDecoder { - fn read(&mut self, into: &mut [u8]) -> io::Result { - loop { - match &mut self.state { - GzState::Header(parser) => { - parser.parse(self.reader.get_mut().get_mut())?; - self.state = GzState::Body(GzHeader::from(mem::take(parser))); - } - GzState::Body(header) => { - if into.is_empty() { - return Ok(0); - } - match self.reader.read(into)? { - 0 => { - self.state = GzState::Finished(mem::take(header), 0, [0; 8]); - } - n => { - return Ok(n); - } - } - } - GzState::Finished(header, pos, buf) => { - if *pos < buf.len() { - *pos += read_into(self.reader.get_mut().get_mut(), &mut buf[*pos..])?; - } else { - let (crc, amt) = finish(&buf); - - if crc != self.reader.crc().sum() || amt != self.reader.crc().amount() { - self.state = GzState::End(Some(mem::take(header))); - return Err(corrupt()); - } else if self.multi { - let is_eof = self - .reader - .get_mut() - .get_mut() - .fill_buf() - .map(|buf| buf.is_empty())?; - - if is_eof { - self.state = GzState::End(Some(mem::take(header))); - } else { - self.reader.reset(); - self.reader.get_mut().reset_data(); - self.state = GzState::Header(GzHeaderParser::new()) - } - } else { - self.state = GzState::End(Some(mem::take(header))); - } - } - } - GzState::Err(err) => { - let result = Err(mem::replace(err, io::ErrorKind::Other.into())); - self.state = GzState::End(None); - return result; - } - GzState::End(_) => return Ok(0), - } - } - } -} - -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 [`BufRead`] and provides the uncompressed data. -/// -/// A gzip file consists of a series of *members* concatenated one after another. -/// MultiGzDecoder decodes all members from the data and only returns Ok(0) when the -/// underlying reader does. For a file, this reads to the end of the file. -/// -/// 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 -/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html -/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::io; -/// # use flate2::Compression; -/// # use flate2::write::GzEncoder; -/// use flate2::bufread::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 BufRead -/// -/// 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(GzDecoder); - -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(GzDecoder::new(r).multi(true)) - } -} - -impl MultiGzDecoder { - /// Returns the current header associated with this stream, if it's valid - pub fn header(&self) -> Option<&GzHeader> { - self.0.header() - } - - /// Acquires a reference to the underlying reader. - pub fn get_ref(&self) -> &R { - self.0.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.0.get_mut() - } - - /// Consumes this decoder, returning the underlying reader. - pub fn into_inner(self) -> R { - self.0.into_inner() - } -} - -impl Read for MultiGzDecoder { - fn read(&mut self, into: &mut [u8]) -> io::Result { - self.0.read(into) - } -} - -#[cfg(test)] -mod test { - use crate::bufread::GzDecoder; - use crate::gz::write; - use crate::Compression; - use std::io::{Read, Write}; - - // GzDecoder consumes one gzip member and then returns 0 for subsequent reads, allowing any - // additional data to be consumed by the caller. - #[test] - fn decode_extra_data() { - let expected = "Hello World"; - - let compressed = { - let mut e = write::GzEncoder::new(Vec::new(), Compression::default()); - e.write(expected.as_ref()).unwrap(); - let mut b = e.finish().unwrap(); - b.push(b'x'); - b - }; - - let mut output = Vec::new(); - let mut decoder = GzDecoder::new(compressed.as_slice()); - let decoded_bytes = decoder.read_to_end(&mut output).unwrap(); - assert_eq!(decoded_bytes, output.len()); - let actual = std::str::from_utf8(&output).expect("String parsing error"); - assert_eq!( - actual, expected, - "after decompression we obtain the original input" - ); - - output.clear(); - assert_eq!( - decoder.read(&mut output).unwrap(), - 0, - "subsequent read of decoder returns 0, but inner reader can return additional data" - ); - let mut reader = decoder.into_inner(); - assert_eq!( - reader.read_to_end(&mut output).unwrap(), - 1, - "extra data is accessible in underlying buf-read" - ); - assert_eq!(output, b"x"); - } -} diff --git a/vendor/flate2/src/gz/mod.rs b/vendor/flate2/src/gz/mod.rs deleted file mode 100644 index 31a6961..0000000 --- a/vendor/flate2/src/gz/mod.rs +++ /dev/null @@ -1,644 +0,0 @@ -use std::ffi::CString; -use std::io::{BufRead, Error, ErrorKind, Read, Result, Write}; -use std::time; - -use crate::bufreader::BufReader; -use crate::{Compression, Crc}; - -pub static FHCRC: u8 = 1 << 1; -pub static FEXTRA: u8 = 1 << 2; -pub static FNAME: u8 = 1 << 3; -pub static FCOMMENT: u8 = 1 << 4; -pub static FRESERVED: u8 = 1 << 5 | 1 << 6 | 1 << 7; - -pub mod bufread; -pub mod read; -pub mod write; - -// The maximum length of the header filename and comment fields. More than -// enough for these fields in reasonable use, but prevents possible attacks. -const MAX_HEADER_BUF: usize = 65535; - -/// A structure representing the header of a gzip stream. -/// -/// The header can contain metadata about the file that was compressed, if -/// present. -#[derive(PartialEq, Clone, Debug, Default)] -pub struct GzHeader { - extra: Option>, - filename: Option>, - comment: Option>, - operating_system: u8, - mtime: u32, -} - -impl GzHeader { - /// Returns the `filename` field of this gzip stream's header, if present. - pub fn filename(&self) -> Option<&[u8]> { - self.filename.as_ref().map(|s| &s[..]) - } - - /// Returns the `extra` field of this gzip stream's header, if present. - pub fn extra(&self) -> Option<&[u8]> { - self.extra.as_ref().map(|s| &s[..]) - } - - /// Returns the `comment` field of this gzip stream's header, if present. - pub fn comment(&self) -> Option<&[u8]> { - self.comment.as_ref().map(|s| &s[..]) - } - - /// Returns the `operating_system` field of this gzip stream's header. - /// - /// There are predefined values for various operating systems. - /// 255 means that the value is unknown. - pub fn operating_system(&self) -> u8 { - self.operating_system - } - - /// This gives the most recent modification time of the original file being compressed. - /// - /// The time is in Unix format, i.e., seconds since 00:00:00 GMT, Jan. 1, 1970. - /// (Note that this may cause problems for MS-DOS and other systems that use local - /// rather than Universal time.) If the compressed data did not come from a file, - /// `mtime` is set to the time at which compression started. - /// `mtime` = 0 means no time stamp is available. - /// - /// The usage of `mtime` is discouraged because of Year 2038 problem. - pub fn mtime(&self) -> u32 { - self.mtime - } - - /// Returns the most recent modification time represented by a date-time type. - /// Returns `None` if the value of the underlying counter is 0, - /// indicating no time stamp is available. - /// - /// - /// The time is measured as seconds since 00:00:00 GMT, Jan. 1 1970. - /// See [`mtime`](#method.mtime) for more detail. - pub fn mtime_as_datetime(&self) -> Option { - if self.mtime == 0 { - None - } else { - let duration = time::Duration::new(u64::from(self.mtime), 0); - let datetime = time::UNIX_EPOCH + duration; - Some(datetime) - } - } -} - -#[derive(Debug)] -pub enum GzHeaderState { - Start(u8, [u8; 10]), - Xlen(Option>, u8, [u8; 2]), - Extra(Option>, u16), - Filename(Option>), - Comment(Option>), - Crc(Option>, u8, [u8; 2]), - Complete, -} - -impl Default for GzHeaderState { - fn default() -> Self { - Self::Complete - } -} - -#[derive(Debug, Default)] -pub struct GzHeaderParser { - state: GzHeaderState, - flags: u8, - header: GzHeader, -} - -impl GzHeaderParser { - fn new() -> Self { - GzHeaderParser { - state: GzHeaderState::Start(0, [0; 10]), - flags: 0, - header: GzHeader::default(), - } - } - - fn parse<'a, R: Read>(&mut self, r: &'a mut R) -> Result<()> { - loop { - match &mut self.state { - GzHeaderState::Start(count, buffer) => { - while (*count as usize) < buffer.len() { - *count += read_into(r, &mut buffer[*count as usize..])? as u8; - } - // Gzip identification bytes - if buffer[0] != 0x1f || buffer[1] != 0x8b { - return Err(bad_header()); - } - // Gzip compression method (8 = deflate) - if buffer[2] != 8 { - return Err(bad_header()); - } - self.flags = buffer[3]; - // RFC1952: "must give an error indication if any reserved bit is non-zero" - if self.flags & FRESERVED != 0 { - return Err(bad_header()); - } - self.header.mtime = ((buffer[4] as u32) << 0) - | ((buffer[5] as u32) << 8) - | ((buffer[6] as u32) << 16) - | ((buffer[7] as u32) << 24); - let _xfl = buffer[8]; - self.header.operating_system = buffer[9]; - let crc = if self.flags & FHCRC != 0 { - let mut crc = Box::new(Crc::new()); - crc.update(buffer); - Some(crc) - } else { - None - }; - self.state = GzHeaderState::Xlen(crc, 0, [0; 2]); - } - GzHeaderState::Xlen(crc, count, buffer) => { - if self.flags & FEXTRA != 0 { - while (*count as usize) < buffer.len() { - *count += read_into(r, &mut buffer[*count as usize..])? as u8; - } - if let Some(crc) = crc { - crc.update(buffer); - } - let xlen = parse_le_u16(&buffer); - self.header.extra = Some(vec![0; xlen as usize]); - self.state = GzHeaderState::Extra(crc.take(), 0); - } else { - self.state = GzHeaderState::Filename(crc.take()); - } - } - GzHeaderState::Extra(crc, count) => { - debug_assert!(self.header.extra.is_some()); - let extra = self.header.extra.as_mut().unwrap(); - while (*count as usize) < extra.len() { - *count += read_into(r, &mut extra[*count as usize..])? as u16; - } - if let Some(crc) = crc { - crc.update(extra); - } - self.state = GzHeaderState::Filename(crc.take()); - } - GzHeaderState::Filename(crc) => { - if self.flags & FNAME != 0 { - let filename = self.header.filename.get_or_insert_with(Vec::new); - read_to_nul(r, filename)?; - if let Some(crc) = crc { - crc.update(filename); - crc.update(b"\0"); - } - } - self.state = GzHeaderState::Comment(crc.take()); - } - GzHeaderState::Comment(crc) => { - if self.flags & FCOMMENT != 0 { - let comment = self.header.comment.get_or_insert_with(Vec::new); - read_to_nul(r, comment)?; - if let Some(crc) = crc { - crc.update(comment); - crc.update(b"\0"); - } - } - self.state = GzHeaderState::Crc(crc.take(), 0, [0; 2]); - } - GzHeaderState::Crc(crc, count, buffer) => { - if let Some(crc) = crc { - debug_assert!(self.flags & FHCRC != 0); - while (*count as usize) < buffer.len() { - *count += read_into(r, &mut buffer[*count as usize..])? as u8; - } - let stored_crc = parse_le_u16(&buffer); - let calced_crc = crc.sum() as u16; - if stored_crc != calced_crc { - return Err(corrupt()); - } - } - self.state = GzHeaderState::Complete; - } - GzHeaderState::Complete => { - return Ok(()); - } - } - } - } - - fn header(&self) -> Option<&GzHeader> { - match self.state { - GzHeaderState::Complete => Some(&self.header), - _ => None, - } - } -} - -impl From for GzHeader { - fn from(parser: GzHeaderParser) -> Self { - debug_assert!(matches!(parser.state, GzHeaderState::Complete)); - parser.header - } -} - -// Attempt to fill the `buffer` from `r`. Return the number of bytes read. -// Return an error if EOF is read before the buffer is full. This differs -// from `read` in that Ok(0) means that more data may be available. -fn read_into(r: &mut R, buffer: &mut [u8]) -> Result { - debug_assert!(!buffer.is_empty()); - match r.read(buffer) { - Ok(0) => Err(ErrorKind::UnexpectedEof.into()), - Ok(n) => Ok(n), - Err(ref e) if e.kind() == ErrorKind::Interrupted => Ok(0), - Err(e) => Err(e), - } -} - -// Read `r` up to the first nul byte, pushing non-nul bytes to `buffer`. -fn read_to_nul(r: &mut R, buffer: &mut Vec) -> Result<()> { - let mut bytes = r.bytes(); - loop { - match bytes.next().transpose()? { - Some(byte) if byte == 0 => { - return Ok(()); - } - Some(_) if buffer.len() == MAX_HEADER_BUF => { - return Err(Error::new( - ErrorKind::InvalidInput, - "gzip header field too long", - )); - } - Some(byte) => { - buffer.push(byte); - } - None => { - return Err(ErrorKind::UnexpectedEof.into()); - } - } - } -} - -fn parse_le_u16(buffer: &[u8; 2]) -> u16 { - (buffer[0] as u16) | ((buffer[1] as u16) << 8) -} - -fn bad_header() -> Error { - Error::new(ErrorKind::InvalidInput, "invalid gzip header") -} - -fn corrupt() -> Error { - Error::new( - ErrorKind::InvalidInput, - "corrupt gzip stream does not have a matching checksum", - ) -} - -/// A builder structure to create a new gzip Encoder. -/// -/// This structure controls header configuration options such as the filename. -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// # use std::io; -/// use std::fs::File; -/// use flate2::GzBuilder; -/// use flate2::Compression; -/// -/// // GzBuilder opens a file and writes a sample string using GzBuilder pattern -/// -/// # fn sample_builder() -> Result<(), io::Error> { -/// let f = File::create("examples/hello_world.gz")?; -/// let mut gz = GzBuilder::new() -/// .filename("hello_world.txt") -/// .comment("test file, please delete") -/// .write(f, Compression::default()); -/// gz.write_all(b"hello world")?; -/// gz.finish()?; -/// # Ok(()) -/// # } -/// ``` -#[derive(Debug)] -pub struct GzBuilder { - extra: Option>, - filename: Option, - comment: Option, - operating_system: Option, - mtime: u32, -} - -impl Default for GzBuilder { - fn default() -> Self { - Self::new() - } -} - -impl GzBuilder { - /// Create a new blank builder with no header by default. - pub fn new() -> GzBuilder { - GzBuilder { - extra: None, - filename: None, - comment: None, - operating_system: None, - mtime: 0, - } - } - - /// Configure the `mtime` field in the gzip header. - pub fn mtime(mut self, mtime: u32) -> GzBuilder { - self.mtime = mtime; - self - } - - /// Configure the `operating_system` field in the gzip header. - pub fn operating_system(mut self, os: u8) -> GzBuilder { - self.operating_system = Some(os); - self - } - - /// Configure the `extra` field in the gzip header. - pub fn extra>>(mut self, extra: T) -> GzBuilder { - self.extra = Some(extra.into()); - self - } - - /// Configure the `filename` field in the gzip header. - /// - /// # Panics - /// - /// Panics if the `filename` slice contains a zero. - pub fn filename>>(mut self, filename: T) -> GzBuilder { - self.filename = Some(CString::new(filename.into()).unwrap()); - self - } - - /// Configure the `comment` field in the gzip header. - /// - /// # Panics - /// - /// Panics if the `comment` slice contains a zero. - pub fn comment>>(mut self, comment: T) -> GzBuilder { - self.comment = Some(CString::new(comment.into()).unwrap()); - self - } - - /// Consume this builder, creating a writer encoder in the process. - /// - /// The data written to the returned encoder will be compressed and then - /// written out to the supplied parameter `w`. - pub fn write(self, w: W, lvl: Compression) -> write::GzEncoder { - write::gz_encoder(self.into_header(lvl), w, lvl) - } - - /// Consume this builder, creating a reader encoder in the process. - /// - /// Data read from the returned encoder will be the compressed version of - /// the data read from the given reader. - pub fn read(self, r: R, lvl: Compression) -> read::GzEncoder { - read::gz_encoder(self.buf_read(BufReader::new(r), lvl)) - } - - /// Consume this builder, creating a reader encoder in the process. - /// - /// Data read from the returned encoder will be the compressed version of - /// the data read from the given reader. - pub fn buf_read(self, r: R, lvl: Compression) -> bufread::GzEncoder - where - R: BufRead, - { - bufread::gz_encoder(self.into_header(lvl), r, lvl) - } - - fn into_header(self, lvl: Compression) -> Vec { - let GzBuilder { - extra, - filename, - comment, - operating_system, - mtime, - } = self; - let mut flg = 0; - let mut header = vec![0u8; 10]; - if let Some(v) = extra { - flg |= FEXTRA; - header.push((v.len() >> 0) as u8); - header.push((v.len() >> 8) as u8); - header.extend(v); - } - if let Some(filename) = filename { - flg |= FNAME; - header.extend(filename.as_bytes_with_nul().iter().copied()); - } - if let Some(comment) = comment { - flg |= FCOMMENT; - header.extend(comment.as_bytes_with_nul().iter().copied()); - } - header[0] = 0x1f; - header[1] = 0x8b; - header[2] = 8; - header[3] = flg; - header[4] = (mtime >> 0) as u8; - header[5] = (mtime >> 8) as u8; - header[6] = (mtime >> 16) as u8; - header[7] = (mtime >> 24) as u8; - header[8] = if lvl.0 >= Compression::best().0 { - 2 - } else if lvl.0 <= Compression::fast().0 { - 4 - } else { - 0 - }; - - // Typically this byte indicates what OS the gz stream was created on, - // but in an effort to have cross-platform reproducible streams just - // default this value to 255. I'm not sure that if we "correctly" set - // this it'd do anything anyway... - header[9] = operating_system.unwrap_or(255); - header - } -} - -#[cfg(test)] -mod tests { - use std::io::prelude::*; - - use super::{read, write, GzBuilder, GzHeaderParser}; - use crate::{Compression, GzHeader}; - use rand::{thread_rng, Rng}; - - #[test] - fn roundtrip() { - let mut e = write::GzEncoder::new(Vec::new(), Compression::default()); - e.write_all(b"foo bar baz").unwrap(); - let inner = e.finish().unwrap(); - let mut d = read::GzDecoder::new(&inner[..]); - let mut s = String::new(); - d.read_to_string(&mut s).unwrap(); - assert_eq!(s, "foo bar baz"); - } - - #[test] - fn roundtrip_zero() { - let e = write::GzEncoder::new(Vec::new(), Compression::default()); - let inner = e.finish().unwrap(); - let mut d = read::GzDecoder::new(&inner[..]); - let mut s = String::new(); - d.read_to_string(&mut s).unwrap(); - assert_eq!(s, ""); - } - - #[test] - fn roundtrip_big() { - let mut real = Vec::new(); - let mut w = write::GzEncoder::new(Vec::new(), Compression::default()); - let v = crate::random_bytes().take(1024).collect::>(); - for _ in 0..200 { - let to_write = &v[..thread_rng().gen_range(0..v.len())]; - real.extend(to_write.iter().copied()); - w.write_all(to_write).unwrap(); - } - let result = w.finish().unwrap(); - let mut r = read::GzDecoder::new(&result[..]); - let mut v = Vec::new(); - r.read_to_end(&mut v).unwrap(); - assert_eq!(v, real); - } - - #[test] - fn roundtrip_big2() { - let v = crate::random_bytes().take(1024 * 1024).collect::>(); - let mut r = read::GzDecoder::new(read::GzEncoder::new(&v[..], Compression::default())); - let mut res = Vec::new(); - r.read_to_end(&mut res).unwrap(); - assert_eq!(res, v); - } - - // A Rust implementation of CRC that closely matches the C code in RFC1952. - // Only use this to create CRCs for tests. - struct Rfc1952Crc { - /* Table of CRCs of all 8-bit messages. */ - crc_table: [u32; 256], - } - - impl Rfc1952Crc { - fn new() -> Self { - let mut crc = Rfc1952Crc { - crc_table: [0; 256], - }; - /* Make the table for a fast CRC. */ - for n in 0usize..256 { - let mut c = n as u32; - for _k in 0..8 { - if c & 1 != 0 { - c = 0xedb88320 ^ (c >> 1); - } else { - c = c >> 1; - } - } - crc.crc_table[n] = c; - } - crc - } - - /* - Update a running crc with the bytes buf and return - the updated crc. The crc should be initialized to zero. Pre- and - post-conditioning (one's complement) is performed within this - function so it shouldn't be done by the caller. - */ - fn update_crc(&self, crc: u32, buf: &[u8]) -> u32 { - let mut c = crc ^ 0xffffffff; - - for b in buf { - c = self.crc_table[(c as u8 ^ *b) as usize] ^ (c >> 8); - } - c ^ 0xffffffff - } - - /* Return the CRC of the bytes buf. */ - fn crc(&self, buf: &[u8]) -> u32 { - self.update_crc(0, buf) - } - } - - #[test] - fn roundtrip_header() { - let mut header = GzBuilder::new() - .mtime(1234) - .operating_system(57) - .filename("filename") - .comment("comment") - .into_header(Compression::fast()); - - // Add a CRC to the header - header[3] = header[3] ^ super::FHCRC; - let rfc1952_crc = Rfc1952Crc::new(); - let crc32 = rfc1952_crc.crc(&header); - let crc16 = crc32 as u16; - header.extend(&crc16.to_le_bytes()); - - let mut parser = GzHeaderParser::new(); - parser.parse(&mut header.as_slice()).unwrap(); - let actual = parser.header().unwrap(); - assert_eq!( - actual, - &GzHeader { - extra: None, - filename: Some("filename".as_bytes().to_vec()), - comment: Some("comment".as_bytes().to_vec()), - operating_system: 57, - mtime: 1234 - } - ) - } - - #[test] - fn fields() { - let r = vec![0, 2, 4, 6]; - let e = GzBuilder::new() - .filename("foo.rs") - .comment("bar") - .extra(vec![0, 1, 2, 3]) - .read(&r[..], Compression::default()); - let mut d = read::GzDecoder::new(e); - assert_eq!(d.header().unwrap().filename(), Some(&b"foo.rs"[..])); - assert_eq!(d.header().unwrap().comment(), Some(&b"bar"[..])); - assert_eq!(d.header().unwrap().extra(), Some(&b"\x00\x01\x02\x03"[..])); - let mut res = Vec::new(); - d.read_to_end(&mut res).unwrap(); - assert_eq!(res, vec![0, 2, 4, 6]); - } - - #[test] - fn keep_reading_after_end() { - let mut e = write::GzEncoder::new(Vec::new(), Compression::default()); - e.write_all(b"foo bar baz").unwrap(); - let inner = e.finish().unwrap(); - let mut d = read::GzDecoder::new(&inner[..]); - let mut s = String::new(); - d.read_to_string(&mut s).unwrap(); - assert_eq!(s, "foo bar baz"); - d.read_to_string(&mut s).unwrap(); - assert_eq!(s, "foo bar baz"); - } - - #[test] - fn qc_reader() { - ::quickcheck::quickcheck(test as fn(_) -> _); - - fn test(v: Vec) -> bool { - let r = read::GzEncoder::new(&v[..], Compression::default()); - let mut r = read::GzDecoder::new(r); - let mut v2 = Vec::new(); - r.read_to_end(&mut v2).unwrap(); - v == v2 - } - } - - #[test] - fn flush_after_write() { - let mut f = write::GzEncoder::new(Vec::new(), Compression::default()); - write!(f, "Hello world").unwrap(); - f.flush().unwrap(); - } -} diff --git a/vendor/flate2/src/gz/read.rs b/vendor/flate2/src/gz/read.rs deleted file mode 100644 index 9dbadbd..0000000 --- a/vendor/flate2/src/gz/read.rs +++ /dev/null @@ -1,378 +0,0 @@ -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"); - } - } - } -} diff --git a/vendor/flate2/src/gz/write.rs b/vendor/flate2/src/gz/write.rs deleted file mode 100644 index 74d6c5a..0000000 --- a/vendor/flate2/src/gz/write.rs +++ /dev/null @@ -1,641 +0,0 @@ -use std::cmp; -use std::io; -use std::io::prelude::*; - -use super::{corrupt, GzBuilder, GzHeader, GzHeaderParser}; -use crate::crc::{Crc, CrcWriter}; -use crate::zio; -use crate::{Compress, Compression, Decompress, Status}; - -/// A gzip streaming encoder -/// -/// This structure exposes a [`Write`] interface that will emit compressed data -/// to the underlying writer `W`. -/// -/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use flate2::Compression; -/// use flate2::write::GzEncoder; -/// -/// // Vec implements Write to print the compressed bytes of sample string -/// # fn main() { -/// -/// let mut e = GzEncoder::new(Vec::new(), Compression::default()); -/// e.write_all(b"Hello World").unwrap(); -/// println!("{:?}", e.finish().unwrap()); -/// # } -/// ``` -#[derive(Debug)] -pub struct GzEncoder { - inner: zio::Writer, - crc: Crc, - crc_bytes_written: usize, - header: Vec, -} - -pub fn gz_encoder(header: Vec, w: W, lvl: Compression) -> GzEncoder { - GzEncoder { - inner: zio::Writer::new(w, Compress::new(lvl, false)), - crc: Crc::new(), - header, - crc_bytes_written: 0, - } -} - -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 written to the returned encoder will be compressed and then - /// written to the stream `w`. - pub fn new(w: W, level: Compression) -> GzEncoder { - GzBuilder::new().write(w, level) - } - - /// Acquires a reference to the underlying writer. - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - - /// Acquires a mutable reference to the underlying writer. - /// - /// Note that mutation of the writer may result in surprising results if - /// this encoder is continued to be used. - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut() - } - - /// Attempt to finish this output stream, writing out final chunks of data. - /// - /// Note that this function can only be used once data has finished being - /// written to the output stream. After this function is called then further - /// calls to `write` may result in a panic. - /// - /// # Panics - /// - /// Attempts to write data to this stream may result in a panic after this - /// function is called. - /// - /// # Errors - /// - /// This function will perform I/O to complete this stream, and any I/O - /// errors which occur will be returned from this function. - pub fn try_finish(&mut self) -> io::Result<()> { - self.write_header()?; - self.inner.finish()?; - - while self.crc_bytes_written < 8 { - let (sum, amt) = (self.crc.sum(), self.crc.amount()); - let buf = [ - (sum >> 0) as u8, - (sum >> 8) as u8, - (sum >> 16) as u8, - (sum >> 24) as u8, - (amt >> 0) as u8, - (amt >> 8) as u8, - (amt >> 16) as u8, - (amt >> 24) as u8, - ]; - let inner = self.inner.get_mut(); - let n = inner.write(&buf[self.crc_bytes_written..])?; - self.crc_bytes_written += n; - } - Ok(()) - } - - /// Finish encoding this stream, returning the underlying writer once the - /// encoding is done. - /// - /// Note that this function may not be suitable to call in a situation where - /// the underlying stream is an asynchronous I/O stream. To finish a stream - /// the `try_finish` (or `shutdown`) method should be used instead. To - /// re-acquire ownership of a stream it is safe to call this method after - /// `try_finish` or `shutdown` has returned `Ok`. - /// - /// # Errors - /// - /// This function will perform I/O to complete this stream, and any I/O - /// errors which occur will be returned from this function. - pub fn finish(mut self) -> io::Result { - self.try_finish()?; - Ok(self.inner.take_inner()) - } - - fn write_header(&mut self) -> io::Result<()> { - while !self.header.is_empty() { - let n = self.inner.get_mut().write(&self.header)?; - self.header.drain(..n); - } - Ok(()) - } -} - -impl Write for GzEncoder { - fn write(&mut self, buf: &[u8]) -> io::Result { - assert_eq!(self.crc_bytes_written, 0); - self.write_header()?; - let n = self.inner.write(buf)?; - self.crc.update(&buf[..n]); - Ok(n) - } - - fn flush(&mut self) -> io::Result<()> { - assert_eq!(self.crc_bytes_written, 0); - self.write_header()?; - self.inner.flush() - } -} - -impl Read for GzEncoder { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.get_mut().read(buf) - } -} - -impl Drop for GzEncoder { - fn drop(&mut self) { - if self.inner.is_present() { - let _ = self.try_finish(); - } - } -} - -/// A decoder for a single member of a [gzip file]. -/// -/// This structure exposes a [`Write`] interface, receiving compressed data and -/// writing uncompressed data to the underlying writer. -/// -/// After decoding a single member of the gzip data this writer will return the number of bytes up to -/// to the end of the gzip member and subsequent writes will return Ok(0) allowing the caller to -/// handle any data following the gzip member. -/// -/// 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 -/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::io; -/// use flate2::Compression; -/// use flate2::write::{GzEncoder, GzDecoder}; -/// -/// # fn main() { -/// # let mut e = GzEncoder::new(Vec::new(), Compression::default()); -/// # e.write(b"Hello World").unwrap(); -/// # let bytes = e.finish().unwrap(); -/// # assert_eq!("Hello World", decode_writer(bytes).unwrap()); -/// # } -/// // Uncompresses a gzip encoded vector of bytes and returns a string or error -/// // Here Vec implements Write -/// fn decode_writer(bytes: Vec) -> io::Result { -/// let mut writer = Vec::new(); -/// let mut decoder = GzDecoder::new(writer); -/// decoder.write_all(&bytes[..])?; -/// writer = decoder.finish()?; -/// let return_string = String::from_utf8(writer).expect("String parsing error"); -/// Ok(return_string) -/// } -/// ``` -#[derive(Debug)] -pub struct GzDecoder { - inner: zio::Writer, Decompress>, - crc_bytes: Vec, - header_parser: GzHeaderParser, -} - -const CRC_BYTES_LEN: usize = 8; - -impl GzDecoder { - /// Creates a new decoder which will write uncompressed data to the stream. - /// - /// When this encoder is dropped or unwrapped the final pieces of data will - /// be flushed. - pub fn new(w: W) -> GzDecoder { - GzDecoder { - inner: zio::Writer::new(CrcWriter::new(w), Decompress::new(false)), - crc_bytes: Vec::with_capacity(CRC_BYTES_LEN), - header_parser: GzHeaderParser::new(), - } - } - - /// Returns the header associated with this stream. - pub fn header(&self) -> Option<&GzHeader> { - self.header_parser.header() - } - - /// Acquires a reference to the underlying writer. - pub fn get_ref(&self) -> &W { - self.inner.get_ref().get_ref() - } - - /// Acquires a mutable reference to the underlying writer. - /// - /// Note that mutating the output/input state of the stream may corrupt this - /// object, so care must be taken when using this method. - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut().get_mut() - } - - /// Attempt to finish this output stream, writing out final chunks of data. - /// - /// Note that this function can only be used once data has finished being - /// written to the output stream. After this function is called then further - /// calls to `write` may result in a panic. - /// - /// # Panics - /// - /// Attempts to write data to this stream may result in a panic after this - /// function is called. - /// - /// # Errors - /// - /// This function will perform I/O to finish the stream, returning any - /// errors which happen. - pub fn try_finish(&mut self) -> io::Result<()> { - self.finish_and_check_crc()?; - Ok(()) - } - - /// Consumes this decoder, flushing the output stream. - /// - /// This will flush the underlying data stream and then return the contained - /// writer if the flush succeeded. - /// - /// Note that this function may not be suitable to call in a situation where - /// the underlying stream is an asynchronous I/O stream. To finish a stream - /// the `try_finish` (or `shutdown`) method should be used instead. To - /// re-acquire ownership of a stream it is safe to call this method after - /// `try_finish` or `shutdown` has returned `Ok`. - /// - /// # Errors - /// - /// This function will perform I/O to complete this stream, and any I/O - /// errors which occur will be returned from this function. - pub fn finish(mut self) -> io::Result { - self.finish_and_check_crc()?; - Ok(self.inner.take_inner().into_inner()) - } - - fn finish_and_check_crc(&mut self) -> io::Result<()> { - self.inner.finish()?; - - if self.crc_bytes.len() != 8 { - return Err(corrupt()); - } - - let crc = ((self.crc_bytes[0] as u32) << 0) - | ((self.crc_bytes[1] as u32) << 8) - | ((self.crc_bytes[2] as u32) << 16) - | ((self.crc_bytes[3] as u32) << 24); - let amt = ((self.crc_bytes[4] as u32) << 0) - | ((self.crc_bytes[5] as u32) << 8) - | ((self.crc_bytes[6] as u32) << 16) - | ((self.crc_bytes[7] as u32) << 24); - if crc != self.inner.get_ref().crc().sum() { - return Err(corrupt()); - } - if amt != self.inner.get_ref().crc().amount() { - return Err(corrupt()); - } - Ok(()) - } -} - -impl Write for GzDecoder { - fn write(&mut self, mut buf: &[u8]) -> io::Result { - let buflen = buf.len(); - if self.header().is_none() { - match self.header_parser.parse(&mut buf) { - Err(err) => { - if err.kind() == io::ErrorKind::UnexpectedEof { - // all data read but header still not complete - Ok(buflen) - } else { - Err(err) - } - } - Ok(_) => { - debug_assert!(self.header().is_some()); - // buf now contains the unread part of the original buf - let n = buflen - buf.len(); - Ok(n) - } - } - } else { - let (n, status) = self.inner.write_with_status(buf)?; - - if status == Status::StreamEnd && n < buf.len() && self.crc_bytes.len() < 8 { - let remaining = buf.len() - n; - let crc_bytes = cmp::min(remaining, CRC_BYTES_LEN - self.crc_bytes.len()); - self.crc_bytes.extend(&buf[n..n + crc_bytes]); - return Ok(n + crc_bytes); - } - Ok(n) - } - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -impl Read for GzDecoder { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.inner.get_mut().get_mut().read(buf) - } -} - -/// A gzip streaming decoder that decodes a [gzip file] with multiple members. -/// -/// This structure exposes a [`Write`] interface that will consume compressed data and -/// write uncompressed data to the underlying writer. -/// -/// A gzip file consists of a series of *members* concatenated one after another. -/// `MultiGzDecoder` decodes all members of a file and writes them to the -/// underlying writer one after another. -/// -/// To handle members separately, 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 -#[derive(Debug)] -pub struct MultiGzDecoder { - inner: GzDecoder, -} - -impl MultiGzDecoder { - /// Creates a new decoder which will write uncompressed data to the stream. - /// If the gzip stream contains multiple members all will be decoded. - pub fn new(w: W) -> MultiGzDecoder { - MultiGzDecoder { - inner: GzDecoder::new(w), - } - } - - /// Returns the header associated with the current member. - pub fn header(&self) -> Option<&GzHeader> { - self.inner.header() - } - - /// Acquires a reference to the underlying writer. - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - - /// Acquires a mutable reference to the underlying writer. - /// - /// Note that mutating the output/input state of the stream may corrupt this - /// object, so care must be taken when using this method. - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut() - } - - /// Attempt to finish this output stream, writing out final chunks of data. - /// - /// Note that this function can only be used once data has finished being - /// written to the output stream. After this function is called then further - /// calls to `write` may result in a panic. - /// - /// # Panics - /// - /// Attempts to write data to this stream may result in a panic after this - /// function is called. - /// - /// # Errors - /// - /// This function will perform I/O to finish the stream, returning any - /// errors which happen. - pub fn try_finish(&mut self) -> io::Result<()> { - self.inner.try_finish() - } - - /// Consumes this decoder, flushing the output stream. - /// - /// This will flush the underlying data stream and then return the contained - /// writer if the flush succeeded. - /// - /// Note that this function may not be suitable to call in a situation where - /// the underlying stream is an asynchronous I/O stream. To finish a stream - /// the `try_finish` (or `shutdown`) method should be used instead. To - /// re-acquire ownership of a stream it is safe to call this method after - /// `try_finish` or `shutdown` has returned `Ok`. - /// - /// # Errors - /// - /// This function will perform I/O to complete this stream, and any I/O - /// errors which occur will be returned from this function. - pub fn finish(self) -> io::Result { - self.inner.finish() - } -} - -impl Write for MultiGzDecoder { - fn write(&mut self, buf: &[u8]) -> io::Result { - if buf.is_empty() { - Ok(0) - } else { - match self.inner.write(buf) { - Ok(0) => { - // When the GzDecoder indicates that it has finished - // create a new GzDecoder to handle additional data. - self.inner.try_finish()?; - let w = self.inner.inner.take_inner().into_inner(); - self.inner = GzDecoder::new(w); - self.inner.write(buf) - } - res => res, - } - } - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ - Hello World Hello World Hello World Hello World Hello World \ - Hello World Hello World Hello World Hello World Hello World \ - Hello World Hello World Hello World Hello World Hello World \ - Hello World Hello World Hello World Hello World Hello World"; - - #[test] - fn decode_writer_one_chunk() { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let bytes = e.finish().unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - let n = decoder.write(&bytes[..]).unwrap(); - decoder.write(&bytes[n..]).unwrap(); - decoder.try_finish().unwrap(); - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - #[test] - fn decode_writer_partial_header() { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let bytes = e.finish().unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - assert_eq!(decoder.write(&bytes[..5]).unwrap(), 5); - let n = decoder.write(&bytes[5..]).unwrap(); - if n < bytes.len() - 5 { - decoder.write(&bytes[n + 5..]).unwrap(); - } - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - #[test] - fn decode_writer_partial_header_filename() { - let filename = "test.txt"; - let mut e = GzBuilder::new() - .filename(filename) - .read(STR.as_bytes(), Compression::default()); - let mut bytes = Vec::new(); - e.read_to_end(&mut bytes).unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - assert_eq!(decoder.write(&bytes[..12]).unwrap(), 12); - let n = decoder.write(&bytes[12..]).unwrap(); - if n < bytes.len() - 12 { - decoder.write(&bytes[n + 12..]).unwrap(); - } - assert_eq!( - decoder.header().unwrap().filename().unwrap(), - filename.as_bytes() - ); - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - #[test] - fn decode_writer_partial_header_comment() { - let comment = "test comment"; - let mut e = GzBuilder::new() - .comment(comment) - .read(STR.as_bytes(), Compression::default()); - let mut bytes = Vec::new(); - e.read_to_end(&mut bytes).unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - assert_eq!(decoder.write(&bytes[..12]).unwrap(), 12); - let n = decoder.write(&bytes[12..]).unwrap(); - if n < bytes.len() - 12 { - decoder.write(&bytes[n + 12..]).unwrap(); - } - assert_eq!( - decoder.header().unwrap().comment().unwrap(), - comment.as_bytes() - ); - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - #[test] - fn decode_writer_exact_header() { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let bytes = e.finish().unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - assert_eq!(decoder.write(&bytes[..10]).unwrap(), 10); - decoder.write(&bytes[10..]).unwrap(); - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - #[test] - fn decode_writer_partial_crc() { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let bytes = e.finish().unwrap(); - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - let l = bytes.len() - 5; - let n = decoder.write(&bytes[..l]).unwrap(); - decoder.write(&bytes[n..]).unwrap(); - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(return_string, STR); - } - - // Two or more gzip files concatenated form a multi-member gzip file. MultiGzDecoder will - // concatenate the decoded contents of all members. - #[test] - fn decode_multi_writer() { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let bytes = e.finish().unwrap().repeat(2); - - let mut writer = Vec::new(); - let mut decoder = MultiGzDecoder::new(writer); - let mut count = 0; - while count < bytes.len() { - let n = decoder.write(&bytes[count..]).unwrap(); - assert!(n != 0); - count += n; - } - writer = decoder.finish().unwrap(); - let return_string = String::from_utf8(writer).expect("String parsing error"); - let expected = STR.repeat(2); - assert_eq!(return_string, expected); - } - - // GzDecoder consumes one gzip member and then returns 0 for subsequent writes, allowing any - // additional data to be consumed by the caller. - #[test] - fn decode_extra_data() { - let compressed = { - let mut e = GzEncoder::new(Vec::new(), Compression::default()); - e.write(STR.as_ref()).unwrap(); - let mut b = e.finish().unwrap(); - b.push(b'x'); - b - }; - - let mut writer = Vec::new(); - let mut decoder = GzDecoder::new(writer); - let mut consumed_bytes = 0; - loop { - let n = decoder.write(&compressed[consumed_bytes..]).unwrap(); - if n == 0 { - break; - } - consumed_bytes += n; - } - writer = decoder.finish().unwrap(); - let actual = String::from_utf8(writer).expect("String parsing error"); - assert_eq!(actual, STR); - assert_eq!(&compressed[consumed_bytes..], b"x"); - } -} -- cgit v1.2.3