diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /vendor/xz2/src/read.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/xz2/src/read.rs')
-rw-r--r-- | vendor/xz2/src/read.rs | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/vendor/xz2/src/read.rs b/vendor/xz2/src/read.rs new file mode 100644 index 000000000..40b4ce951 --- /dev/null +++ b/vendor/xz2/src/read.rs @@ -0,0 +1,341 @@ +//! Reader-based compression/decompression streams + +use std::io::prelude::*; +use std::io::{self, BufReader}; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use bufread; +use stream::Stream; + +/// A compression stream which wraps an uncompressed stream of data. Compressed +/// data will be read from the stream. +pub struct XzEncoder<R: Read> { + inner: bufread::XzEncoder<BufReader<R>>, +} + +/// A decompression stream which wraps a compressed stream of data. Decompressed +/// data will be read from the stream. +pub struct XzDecoder<R: Read> { + inner: bufread::XzDecoder<BufReader<R>>, +} + +impl<R: Read> XzEncoder<R> { + /// Create a new compression stream which will compress at the given level + /// to read compress output to the give output stream. + /// + /// The `level` argument here is typically 0-9 with 6 being a good default. + pub fn new(r: R, level: u32) -> XzEncoder<R> { + XzEncoder { + inner: bufread::XzEncoder::new(BufReader::new(r), level), + } + } + + /// Creates a new encoder with a custom `Stream`. + /// + /// The `Stream` can be pre-configured for multithreaded encoding, different + /// compression options/tuning, etc. + pub fn new_stream(r: R, stream: Stream) -> XzEncoder<R> { + XzEncoder { + inner: bufread::XzEncoder::new_stream(BufReader::new(r), stream), + } + } + + /// Acquires a reference to the underlying stream + 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 encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Unwrap the underlying writer, finishing the compression stream. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes produced by the compressor + /// (e.g. the number of bytes read from this stream) + /// + /// Note that, due to buffering, this only bears any relation to + /// total_in() when the compressor chooses to flush its data + /// (unfortunately, this won't happen this won't happen in general + /// at the end of the stream, because the compressor doesn't know + /// if there's more data to come). At that point, + /// `total_out() / total_in()` would be the compression ratio. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } + + /// Returns the number of bytes consumed by the compressor + /// (e.g. the number of bytes read from the underlying stream) + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } +} + +impl<R: Read> Read for XzEncoder<R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl<R: AsyncRead> AsyncRead for XzEncoder<R> { +} + +impl<W: Write + Read> Write for XzEncoder<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl<R: AsyncWrite + Read> AsyncWrite for XzEncoder<R> { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +impl<R: Read> XzDecoder<R> { + /// Create a new decompression stream, which will read compressed + /// data from the given input stream, and decompress one xz stream. + /// It may also consume input data that follows the xz stream. + /// Use [`xz::bufread::XzDecoder`] instead to process a mix of xz and non-xz data. + pub fn new(r: R) -> XzDecoder<R> { + XzDecoder { + inner: bufread::XzDecoder::new(BufReader::new(r)), + } + } + + /// Create a new decompression stream, which will read compressed + /// data from the given input and decompress all the xz stream it contains. + pub fn new_multi_decoder(r: R) -> XzDecoder<R> { + XzDecoder { + inner: bufread::XzDecoder::new_multi_decoder(BufReader::new(r)), + } + } + + /// Creates a new decoder with a custom `Stream`. + /// + /// The `Stream` can be pre-configured for various checks, different + /// decompression options/tuning, etc. + pub fn new_stream(r: R, stream: Stream) -> XzDecoder<R> { + XzDecoder { + inner: bufread::XzDecoder::new_stream(BufReader::new(r), stream), + } + } + + /// Acquires a reference to the underlying stream + 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 encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Unwrap the underlying writer, finishing the compression stream. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes produced by the decompressor + /// (e.g. the number of bytes read from this stream) + /// + /// Note that, due to buffering, this only bears any relation to + /// total_in() when the decompressor reaches a sync point + /// (e.g. where the original compressed stream was flushed). + /// At that point, `total_in() / total_out()` is the compression ratio. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } + + /// Returns the number of bytes consumed by the decompressor + /// (e.g. the number of bytes read from the underlying stream) + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } +} + +impl<R: Read> Read for XzDecoder<R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl<R: AsyncRead + Read> AsyncRead for XzDecoder<R> { +} + +impl<W: Write + Read> Write for XzDecoder<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl<R: AsyncWrite + Read> AsyncWrite for XzDecoder<R> { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use read::{XzEncoder, XzDecoder}; + use rand::{thread_rng, Rng}; + + #[test] + fn smoke() { + let m: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8]; + let mut c = XzEncoder::new(m, 6); + let mut data = vec![]; + c.read_to_end(&mut data).unwrap(); + let mut d = XzDecoder::new(&data[..]); + let mut data2 = Vec::new(); + d.read_to_end(&mut data2).unwrap(); + assert_eq!(data2, m); + } + + #[test] + fn smoke2() { + let m: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8]; + let c = XzEncoder::new(m, 6); + let mut d = XzDecoder::new(c); + let mut data = vec![]; + d.read_to_end(&mut data).unwrap(); + assert_eq!(data, [1, 2, 3, 4, 5, 6, 7, 8]); + } + + #[test] + fn smoke3() { + let m = vec![3u8; 128 * 1024 + 1]; + let c = XzEncoder::new(&m[..], 6); + let mut d = XzDecoder::new(c); + let mut data = vec![]; + d.read_to_end(&mut data).unwrap(); + assert!(data == &m[..]); + } + + #[test] + fn self_terminating() { + let m = vec![3u8; 128 * 1024 + 1]; + let mut c = XzEncoder::new(&m[..], 6); + + let mut result = Vec::new(); + c.read_to_end(&mut result).unwrap(); + + let v = thread_rng().gen_iter::<u8>().take(1024).collect::<Vec<_>>(); + for _ in 0..200 { + result.extend(v.iter().map(|x| *x)); + } + + let mut d = XzDecoder::new(&result[..]); + let mut data = Vec::with_capacity(m.len()); + unsafe { data.set_len(m.len()); } + assert!(d.read(&mut data).unwrap() == m.len()); + assert!(data == &m[..]); + } + + #[test] + fn zero_length_read_at_eof() { + let m = Vec::new(); + let mut c = XzEncoder::new(&m[..], 6); + + let mut result = Vec::new(); + c.read_to_end(&mut result).unwrap(); + + let mut d = XzDecoder::new(&result[..]); + let mut data = Vec::new(); + assert!(d.read(&mut data).unwrap() == 0); + } + + #[test] + fn zero_length_read_with_data() { + let m = vec![3u8; 128 * 1024 + 1]; + let mut c = XzEncoder::new(&m[..], 6); + + let mut result = Vec::new(); + c.read_to_end(&mut result).unwrap(); + + let mut d = XzDecoder::new(&result[..]); + let mut data = Vec::new(); + assert!(d.read(&mut data).unwrap() == 0); + } + + #[test] + fn qc() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec<u8>) -> bool { + let r = XzEncoder::new(&v[..], 6); + let mut r = XzDecoder::new(r); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn two_streams() { + let mut input_stream1: Vec<u8> = Vec::new(); + let mut input_stream2: Vec<u8> = Vec::new(); + let mut all_input : Vec<u8> = Vec::new(); + + // Generate input data. + const STREAM1_SIZE: usize = 1024; + for num in 0..STREAM1_SIZE { + input_stream1.push(num as u8) + } + const STREAM2_SIZE: usize = 532; + for num in 0..STREAM2_SIZE { + input_stream2.push((num + 32) as u8) + } + all_input.extend(&input_stream1); + all_input.extend(&input_stream2); + + // Make a vector with compressed data + let mut decoder_input = Vec::new(); + { + let mut encoder = XzEncoder::new(&input_stream1[..], 6); + encoder.read_to_end(&mut decoder_input).unwrap(); + } + { + let mut encoder = XzEncoder::new(&input_stream2[..], 6); + encoder.read_to_end(&mut decoder_input).unwrap(); + } + + // Decoder must be able to read the 2 concatenated xz streams and get the same data as input. + let mut decoder_reader = &decoder_input[..]; + { + // using `XzDecoder::new` here would fail because only 1 xz stream would be processed. + let mut decoder = XzDecoder::new_multi_decoder(&mut decoder_reader); + let mut decompressed_data = vec![0u8; all_input.len()]; + + assert_eq!(decoder.read(&mut decompressed_data).unwrap(), all_input.len()); + assert_eq!(decompressed_data, &all_input[..]); + } + } +} |