diff options
Diffstat (limited to 'vendor/flate2/src/gz')
-rw-r--r-- | vendor/flate2/src/gz/bufread.rs | 18 | ||||
-rw-r--r-- | vendor/flate2/src/gz/mod.rs | 10 | ||||
-rw-r--r-- | vendor/flate2/src/gz/read.rs | 4 | ||||
-rw-r--r-- | vendor/flate2/src/gz/write.rs | 136 |
4 files changed, 148 insertions, 20 deletions
diff --git a/vendor/flate2/src/gz/bufread.rs b/vendor/flate2/src/gz/bufread.rs index 6be144d0c..c6ac5a98b 100644 --- a/vendor/flate2/src/gz/bufread.rs +++ b/vendor/flate2/src/gz/bufread.rs @@ -74,7 +74,7 @@ fn read_gz_header_part<'a, R: Read>(r: &'a mut Buffer<'a, R>) -> io::Result<()> } GzHeaderParsingState::Filename => { if r.part.flg & FNAME != 0 { - if None == r.part.header.filename { + if r.part.header.filename.is_none() { r.part.header.filename = Some(Vec::new()); }; for byte in r.bytes() { @@ -88,7 +88,7 @@ fn read_gz_header_part<'a, R: Read>(r: &'a mut Buffer<'a, R>) -> io::Result<()> } GzHeaderParsingState::Comment => { if r.part.flg & FCOMMENT != 0 { - if None == r.part.header.comment { + if r.part.header.comment.is_none() { r.part.header.comment = Some(Vec::new()); }; for byte in r.bytes() { @@ -483,7 +483,7 @@ impl<R> GzDecoder<R> { /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if - /// this encoder is continued to be used. + /// this decoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.reader.get_mut().get_mut() } @@ -681,7 +681,7 @@ impl<R> MultiGzDecoder<R> { /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if - /// this encoder is continued to be used. + /// this decoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.0.get_mut() } @@ -718,20 +718,20 @@ pub mod tests { } pub fn set_position(&mut self, pos: u64) { - return self.cursor.set_position(pos); + self.cursor.set_position(pos) } pub fn position(&mut self) -> u64 { - return self.cursor.position(); + self.cursor.position() } } impl Write for BlockingCursor { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - return self.cursor.write(buf); + self.cursor.write(buf) } fn flush(&mut self) -> io::Result<()> { - return self.cursor.flush(); + self.cursor.flush() } } @@ -751,7 +751,7 @@ pub mod tests { } Ok(_n) => {} } - return r; + r } } #[test] diff --git a/vendor/flate2/src/gz/mod.rs b/vendor/flate2/src/gz/mod.rs index 505450e3e..d31aa60be 100644 --- a/vendor/flate2/src/gz/mod.rs +++ b/vendor/flate2/src/gz/mod.rs @@ -218,11 +218,11 @@ impl GzBuilder { } if let Some(filename) = filename { flg |= FNAME; - header.extend(filename.as_bytes_with_nul().iter().map(|x| *x)); + header.extend(filename.as_bytes_with_nul().iter().copied()); } if let Some(comment) = comment { flg |= FCOMMENT; - header.extend(comment.as_bytes_with_nul().iter().map(|x| *x)); + header.extend(comment.as_bytes_with_nul().iter().copied()); } header[0] = 0x1f; header[1] = 0x8b; @@ -285,14 +285,14 @@ mod tests { let v = crate::random_bytes().take(1024).collect::<Vec<_>>(); for _ in 0..200 { let to_write = &v[..thread_rng().gen_range(0..v.len())]; - real.extend(to_write.iter().map(|x| *x)); + 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!(v == real); + assert_eq!(v, real); } #[test] @@ -301,7 +301,7 @@ mod tests { 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!(res == v); + assert_eq!(res, v); } #[test] diff --git a/vendor/flate2/src/gz/read.rs b/vendor/flate2/src/gz/read.rs index dbbe63282..cfeb992e8 100644 --- a/vendor/flate2/src/gz/read.rs +++ b/vendor/flate2/src/gz/read.rs @@ -153,7 +153,7 @@ impl<R> GzDecoder<R> { /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if - /// this encoder is continued to be used. + /// this decoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.inner.get_mut().get_mut() } @@ -250,7 +250,7 @@ impl<R> MultiGzDecoder<R> { /// Acquires a mutable reference to the underlying stream. /// /// Note that mutation of the stream may result in surprising results if - /// this encoder is continued to be used. + /// this decoder is continued to be used. pub fn get_mut(&mut self) -> &mut R { self.inner.get_mut().get_mut() } diff --git a/vendor/flate2/src/gz/write.rs b/vendor/flate2/src/gz/write.rs index 7cf1a7cd4..83eebb757 100644 --- a/vendor/flate2/src/gz/write.rs +++ b/vendor/flate2/src/gz/write.rs @@ -92,7 +92,7 @@ impl<W: Write> GzEncoder<W> { self.inner.finish()?; while self.crc_bytes_written < 8 { - let (sum, amt) = (self.crc.sum() as u32, self.crc.amount()); + let (sum, amt) = (self.crc.sum(), self.crc.amount()); let buf = [ (sum >> 0) as u8, (sum >> 8) as u8, @@ -169,7 +169,7 @@ impl<W: Write> Drop for GzEncoder<W> { /// A gzip streaming decoder /// -/// This structure exposes a [`Write`] interface that will emit compressed data +/// This structure exposes a [`Write`] interface that will emit uncompressed data /// to the underlying writer `W`. /// /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html @@ -296,7 +296,7 @@ impl<W: Write> GzDecoder<W> { | ((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() as u32 { + if crc != self.inner.get_ref().crc().sum() { return Err(corrupt()); } if amt != self.inner.get_ref().crc().amount() { @@ -373,11 +373,117 @@ impl<W: Read + Write> Read for GzDecoder<W> { } } +/// A gzip streaming decoder that decodes all members of a multistream +/// +/// A gzip member consists of a header, compressed data and a trailer. The [gzip +/// specification](https://tools.ietf.org/html/rfc1952), however, allows multiple +/// gzip members to be joined in a single stream. `MultiGzDecoder` will +/// decode all consecutive members while `GzDecoder` will only decompress +/// the first gzip member. The multistream format is commonly used in +/// bioinformatics, for example when using the BGZF compressed data. +/// +/// This structure exposes a [`Write`] interface that will consume all gzip members +/// from the written buffers and write uncompressed data to the writer. +#[derive(Debug)] +pub struct MultiGzDecoder<W: Write> { + inner: GzDecoder<W>, +} + +impl<W: Write> MultiGzDecoder<W> { + /// 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<W> { + 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<W> { + self.inner.finish() + } +} + +impl<W: Write> Write for MultiGzDecoder<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + 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: &'static str = "Hello World Hello World Hello World Hello World Hello World \ + 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 \ @@ -447,4 +553,26 @@ mod tests { 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); + } } |