Revision control

Copy as Markdown

Other Tools

use std::io;
use std::io::prelude::*;
use crate::zio;
use crate::{Compress, Decompress};
/// A ZLIB encoder, or compressor.
///
/// This structure implements a [`Write`] interface and takes a stream of
/// uncompressed data, writing the compressed data to the wrapped writer.
///
///
/// # Examples
///
/// ```
/// use std::io::prelude::*;
/// use flate2::Compression;
/// use flate2::write::ZlibEncoder;
///
/// // Vec<u8> implements Write, assigning the compressed bytes of sample string
///
/// # fn zlib_encoding() -> std::io::Result<()> {
/// let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
/// e.write_all(b"Hello World")?;
/// let compressed = e.finish()?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct ZlibEncoder<W: Write> {
inner: zio::Writer<W, Compress>,
}
impl<W: Write> ZlibEncoder<W> {
/// Creates a new encoder which will write compressed data to the stream
/// given at the given compression level.
///
/// When this encoder is dropped or unwrapped the final pieces of data will
/// be flushed.
pub fn new(w: W, level: crate::Compression) -> ZlibEncoder<W> {
ZlibEncoder {
inner: zio::Writer::new(w, Compress::new(level, true)),
}
}
/// Creates a new encoder which will write compressed data to the stream
/// `w` with the given `compression` settings.
pub fn new_with_compress(w: W, compression: Compress) -> ZlibEncoder<W> {
ZlibEncoder {
inner: zio::Writer::new(w, compression),
}
}
/// 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()
}
/// Resets the state of this encoder entirely, swapping out the output
/// stream for another.
///
/// This function will finish encoding the current stream into the current
/// output stream before swapping out the two output streams.
///
/// After the current stream has been finished, this will reset the internal
/// state of this encoder and replace the output stream with the one
/// provided, returning the previous output stream. Future data written to
/// this encoder will be the compressed into the stream `w` provided.
///
/// # 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 reset(&mut self, w: W) -> io::Result<W> {
self.inner.finish()?;
self.inner.data.reset();
Ok(self.inner.replace(w))
}
/// 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.inner.finish()
}
/// Consumes this encoder, flushing the output stream.
///
/// This will flush the underlying data stream, close off the compressed
/// stream and, if successful, return the contained writer.
///
/// 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<W> {
self.inner.finish()?;
Ok(self.inner.take_inner())
}
/// Consumes this encoder, flushing the output stream.
///
/// This will flush the underlying data stream and then return the contained
/// writer if the flush succeeded.
/// The compressed stream will not closed but only flushed. This
/// means that obtained byte array can by extended by another deflated
/// stream. To close the stream add the two bytes 0x3 and 0x0.
///
/// # 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 flush_finish(mut self) -> io::Result<W> {
self.inner.flush()?;
Ok(self.inner.take_inner())
}
/// Returns the number of bytes that have been written to this compressor.
///
/// Note that not all bytes written to this object may be accounted for,
/// there may still be some active buffering.
pub fn total_in(&self) -> u64 {
self.inner.data.total_in()
}
/// Returns the number of bytes that the compressor has produced.
///
/// Note that not all bytes may have been written yet, some may still be
/// buffered.
pub fn total_out(&self) -> u64 {
self.inner.data.total_out()
}
}
impl<W: Write> Write for ZlibEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<W: Read + Write> Read for ZlibEncoder<W> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.get_mut().read(buf)
}
}
/// A ZLIB decoder, or decompressor.
///
/// This structure implements a [`Write`] and will emit a stream of decompressed
/// data when fed a stream of compressed data.
///
///
/// # Examples
///
/// ```
/// use std::io::prelude::*;
/// use std::io;
/// # use flate2::Compression;
/// # use flate2::write::ZlibEncoder;
/// use flate2::write::ZlibDecoder;
///
/// # fn main() {
/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
/// # e.write_all(b"Hello World").unwrap();
/// # let bytes = e.finish().unwrap();
/// # println!("{}", decode_reader(bytes).unwrap());
/// # }
/// #
/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error
/// // Here Vec<u8> implements Write
///
/// fn decode_reader(bytes: Vec<u8>) -> io::Result<String> {
/// let mut writer = Vec::new();
/// let mut z = ZlibDecoder::new(writer);
/// z.write_all(&bytes[..])?;
/// writer = z.finish()?;
/// let return_string = String::from_utf8(writer).expect("String parsing error");
/// Ok(return_string)
/// }
/// ```
#[derive(Debug)]
pub struct ZlibDecoder<W: Write> {
inner: zio::Writer<W, Decompress>,
}
impl<W: Write> ZlibDecoder<W> {
/// Creates a new decoder which will write uncompressed data to the stream.
///
/// When this decoder is dropped or unwrapped the final pieces of data will
/// be flushed.
pub fn new(w: W) -> ZlibDecoder<W> {
ZlibDecoder {
inner: zio::Writer::new(w, Decompress::new(true)),
}
}
/// Creates a new decoder which will write uncompressed data to the stream `w`
/// using the given `decompression` settings.
///
/// When this decoder is dropped or unwrapped the final pieces of data will
/// be flushed.
pub fn new_with_decompress(w: W, decompression: Decompress) -> ZlibDecoder<W> {
ZlibDecoder {
inner: zio::Writer::new(w, decompression),
}
}
/// 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()
}
/// Resets the state of this decoder entirely, swapping out the output
/// stream for another.
///
/// This will reset the internal state of this decoder and replace the
/// output stream with the one provided, returning the previous output
/// stream. Future data written to this decoder will be decompressed into
/// the output stream `w`.
///
/// # 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 reset(&mut self, w: W) -> io::Result<W> {
self.inner.finish()?;
self.inner.data = Decompress::new(true);
Ok(self.inner.replace(w))
}
/// 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.inner.finish()
}
/// Consumes this encoder, 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<W> {
self.inner.finish()?;
Ok(self.inner.take_inner())
}
/// Returns the number of bytes that the decompressor has consumed for
/// decompression.
///
/// Note that this will likely be smaller than the number of bytes
/// successfully written to this stream due to internal buffering.
pub fn total_in(&self) -> u64 {
self.inner.data.total_in()
}
/// Returns the number of bytes that the decompressor has written to its
/// output stream.
pub fn total_out(&self) -> u64 {
self.inner.data.total_out()
}
}
impl<W: Write> Write for ZlibDecoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<W: Read + Write> Read for ZlibDecoder<W> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.get_mut().read(buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Compression;
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";
// ZlibDecoder consumes one zlib archive 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 = ZlibEncoder::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 = ZlibDecoder::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");
}
}