flate2/zlib/write.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
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.
///
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
///
/// # 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.
///
/// After decoding a single member of the ZLIB data this writer will return the number of bytes up to
/// to the end of the ZLIB member and subsequent writes will return Ok(0) allowing the caller to
/// handle any data following the ZLIB member.
///
/// [`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::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");
}
}