use std::io::Write;
use std::{thread, io};
use byteorder::{WriteBytesExt, BigEndian};
use checksum::{Adler32Checksum, RollingChecksum};
use compress::compress_data_dynamic_n;
use compress::Flush;
use deflate_state::DeflateState;
use compression_options::CompressionOptions;
use zlib::{write_zlib_header, CompressionLevel};
const ERR_STR: &'static str = "Error! The wrapped writer is missing.\
This is a bug, please file an issue.";
pub fn compress_until_done<W: Write>(
mut input: &[u8],
deflate_state: &mut DeflateState<W>,
flush_mode: Flush,
) -> io::Result<()> {
assert!(flush_mode != Flush::None);
loop {
match compress_data_dynamic_n(input, deflate_state, flush_mode) {
Ok(0) => {
if deflate_state.output_buf().is_empty() {
break;
} else {
input = &[];
}
}
Ok(n) => {
if n < input.len() {
input = &input[n..]
} else {
input = &[];
}
}
Err(e) => {
match e.kind() {
io::ErrorKind::Interrupted => (),
_ => return Err(e),
}
}
}
}
debug_assert_eq!(
deflate_state.bytes_written,
deflate_state.bytes_written_control.get()
);
Ok(())
}
pub struct DeflateEncoder<W: Write> {
deflate_state: DeflateState<W>,
}
impl<W: Write> DeflateEncoder<W> {
pub fn new<O: Into<CompressionOptions>>(writer: W, options: O) -> DeflateEncoder<W> {
DeflateEncoder {
deflate_state: DeflateState::new(options.into(), writer),
}
}
pub fn finish(mut self) -> io::Result<W> {
self.output_all()?;
Ok(self.deflate_state.inner.take().expect(ERR_STR))
}
pub fn reset(&mut self, w: W) -> io::Result<W> {
self.output_all()?;
self.deflate_state.reset(w)
}
fn output_all(&mut self) -> io::Result<()> {
compress_until_done(&[], &mut self.deflate_state, Flush::Finish)
}
}
impl<W: Write> io::Write for DeflateEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let flush_mode = self.deflate_state.flush_mode;
compress_data_dynamic_n(buf, &mut self.deflate_state, flush_mode)
}
fn flush(&mut self) -> io::Result<()> {
compress_until_done(&[], &mut self.deflate_state, Flush::Sync)
}
}
impl<W: Write> Drop for DeflateEncoder<W> {
fn drop(&mut self) {
if self.deflate_state.inner.is_some() && !thread::panicking() {
let _ = self.output_all();
}
}
}
pub struct ZlibEncoder<W: Write> {
deflate_state: DeflateState<W>,
checksum: Adler32Checksum,
header_written: bool,
}
impl<W: Write> ZlibEncoder<W> {
pub fn new<O: Into<CompressionOptions>>(writer: W, options: O) -> ZlibEncoder<W> {
ZlibEncoder {
deflate_state: DeflateState::new(options.into(), writer),
checksum: Adler32Checksum::new(),
header_written: false,
}
}
fn output_all(&mut self) -> io::Result<()> {
self.check_write_header()?;
compress_until_done(&[], &mut self.deflate_state, Flush::Finish)?;
self.write_trailer()
}
pub fn finish(mut self) -> io::Result<W> {
self.output_all()?;
Ok(self.deflate_state.inner.take().expect(ERR_STR))
}
pub fn reset(&mut self, writer: W) -> io::Result<W> {
self.output_all()?;
self.header_written = false;
self.checksum = Adler32Checksum::new();
self.deflate_state.reset(writer)
}
fn check_write_header(&mut self) -> io::Result<()> {
if !self.header_written {
write_zlib_header(self.deflate_state.output_buf(), CompressionLevel::Default)?;
self.header_written = true;
}
Ok(())
}
fn write_trailer(&mut self) -> io::Result<()> {
let hash = self.checksum.current_hash();
self.deflate_state
.inner
.as_mut()
.expect(ERR_STR)
.write_u32::<BigEndian>(hash)
}
pub fn checksum(&self) -> u32 {
self.checksum.current_hash()
}
}
impl<W: Write> io::Write for ZlibEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.check_write_header()?;
let flush_mode = self.deflate_state.flush_mode;
let res = compress_data_dynamic_n(buf, &mut self.deflate_state, flush_mode);
match res {
Ok(0) => self.checksum.update_from_slice(buf),
Ok(n) => self.checksum.update_from_slice(&buf[0..n]),
_ => (),
};
res
}
fn flush(&mut self) -> io::Result<()> {
compress_until_done(&[], &mut self.deflate_state, Flush::Sync)
}
}
impl<W: Write> Drop for ZlibEncoder<W> {
fn drop(&mut self) {
if self.deflate_state.inner.is_some() && !thread::panicking() {
let _ = self.output_all();
}
}
}
#[cfg(feature = "gzip")]
pub mod gzip {
use std::io::{Write, Cursor};
use std::{thread, io};
use super::*;
use byteorder::{WriteBytesExt, LittleEndian};
use gzip_header::{Crc, GzBuilder};
pub struct GzEncoder<W: Write> {
inner: DeflateEncoder<W>,
checksum: Crc,
header: Vec<u8>,
}
impl<W: Write> GzEncoder<W> {
pub fn new<O: Into<CompressionOptions>>(writer: W, options: O) -> GzEncoder<W> {
GzEncoder::from_builder(GzBuilder::new(), writer, options)
}
pub fn from_builder<O: Into<CompressionOptions>>(
builder: GzBuilder,
writer: W,
options: O,
) -> GzEncoder<W> {
GzEncoder {
inner: DeflateEncoder::new(writer, options),
checksum: Crc::new(),
header: builder.into_header(),
}
}
fn check_write_header(&mut self) {
if !self.header.is_empty() {
self.inner
.deflate_state
.output_buf()
.extend_from_slice(&self.header);
self.header.clear();
}
}
fn output_all(&mut self) -> io::Result<()> {
self.check_write_header();
self.inner.output_all()?;
self.write_trailer()
}
pub fn finish(mut self) -> io::Result<W> {
self.output_all()?;
Ok(self.inner.deflate_state.inner.take().expect(ERR_STR))
}
fn reset_no_header(&mut self, writer: W) -> io::Result<W> {
self.output_all()?;
self.checksum = Crc::new();
self.inner.deflate_state.reset(writer)
}
pub fn reset(&mut self, writer: W) -> io::Result<W> {
let w = self.reset_no_header(writer);
self.header = GzBuilder::new().into_header();
w
}
pub fn reset_with_builder(&mut self, writer: W, builder: GzBuilder) -> io::Result<W> {
let w = self.reset_no_header(writer);
self.header = builder.into_header();
w
}
fn write_trailer(&mut self) -> io::Result<()> {
let crc = self.checksum.sum();
let amount = self.checksum.amt_as_u32();
let mut buf = [0u8; 8];
let mut temp = Cursor::new(&mut buf[..]);
temp.write_u32::<LittleEndian>(crc).unwrap();
temp.write_u32::<LittleEndian>(amount).unwrap();
self.inner
.deflate_state
.inner
.as_mut()
.expect(ERR_STR)
.write_all(temp.into_inner())
}
pub fn checksum(&self) -> u32 {
self.checksum.sum()
}
}
impl<W: Write> io::Write for GzEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.check_write_header();
let res = self.inner.write(buf);
match res {
Ok(0) => self.checksum.update(buf),
Ok(n) => self.checksum.update(&buf[0..n]),
_ => (),
};
res
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
impl<W: Write> Drop for GzEncoder<W> {
fn drop(&mut self) {
if self.inner.deflate_state.inner.is_some() && !thread::panicking() {
let _ = self.output_all();
}
}
}
#[cfg(test)]
mod test {
use super::*;
use test_utils::{get_test_data, decompress_gzip};
#[test]
fn gzip_writer() {
let data = get_test_data();
let comment = b"Comment";
let compressed = {
let mut compressor = GzEncoder::from_builder(
GzBuilder::new().comment(&comment[..]),
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
compressor.write_all(&data[0..data.len() / 2]).unwrap();
compressor.write_all(&data[data.len() / 2..]).unwrap();
compressor.finish().unwrap()
};
let (dec, res) = decompress_gzip(&compressed);
assert_eq!(dec.header().comment().unwrap(), comment);
assert!(res == data);
}
}
}
#[cfg(test)]
mod test {
use super::*;
use test_utils::{get_test_data, decompress_to_end, decompress_zlib};
use compression_options::CompressionOptions;
use std::io::Write;
#[test]
fn deflate_writer() {
let data = get_test_data();
let compressed = {
let mut compressor = DeflateEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::high(),
);
compressor.write_all(&data[0..data.len() / 2]).unwrap();
compressor.write_all(&data[data.len() / 2..]).unwrap();
compressor.finish().unwrap()
};
let res = decompress_to_end(&compressed);
assert!(res == data);
}
#[test]
fn zlib_writer() {
let data = get_test_data();
let compressed = {
let mut compressor = ZlibEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::high(),
);
compressor.write_all(&data[0..data.len() / 2]).unwrap();
compressor.write_all(&data[data.len() / 2..]).unwrap();
compressor.finish().unwrap()
};
let res = decompress_zlib(&compressed);
assert!(res == data);
}
#[test]
fn writer_reset() {
let data = get_test_data();
let mut compressor = DeflateEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
compressor.write_all(&data).unwrap();
let res1 = compressor
.reset(Vec::with_capacity(data.len() / 3))
.unwrap();
compressor.write_all(&data).unwrap();
let res2 = compressor.finish().unwrap();
assert!(res1 == res2);
}
#[test]
fn writer_reset_zlib() {
let data = get_test_data();
let mut compressor = ZlibEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
compressor.write_all(&data).unwrap();
let res1 = compressor
.reset(Vec::with_capacity(data.len() / 3))
.unwrap();
compressor.write_all(&data).unwrap();
let res2 = compressor.finish().unwrap();
assert!(res1 == res2);
}
#[test]
fn writer_sync() {
let data = get_test_data();
let compressed = {
let mut compressor = DeflateEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
let split = data.len() / 2;
compressor.write_all(&data[..split]).unwrap();
compressor.flush().unwrap();
{
let buf = &mut compressor.deflate_state.inner.as_mut().unwrap();
let buf_len = buf.len();
assert_eq!(buf[buf_len - 4..], [0, 0, 255, 255]);
}
compressor.write_all(&data[split..]).unwrap();
compressor.finish().unwrap()
};
let decompressed = decompress_to_end(&compressed);
assert!(decompressed == data);
}
#[test]
fn issue_18() {
use compression_options::Compression;
let data = vec![0; 61000];
let compressed = {
let mut compressor = ZlibEncoder::new(Vec::new(), Compression::Default);
compressor.write_all(&data[..]).unwrap();
compressor.finish().unwrap()
};
let decompressed = decompress_zlib(&compressed);
assert!(decompressed == data);
}
#[test]
fn writer_sync_multiple() {
use std::cmp;
let data = get_test_data();
let compressed = {
let mut compressor = DeflateEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
let split = data.len() / 2;
compressor.write_all(&data[..split]).unwrap();
compressor.flush().unwrap();
compressor.flush().unwrap();
{
let buf = &mut compressor.deflate_state.inner.as_mut().unwrap();
let buf_len = buf.len();
assert_eq!(buf[buf_len - 4..], [0, 0, 255, 255]);
}
compressor
.write_all(&data[split..cmp::min(split + 2, data.len())])
.unwrap();
compressor.flush().unwrap();
compressor
.write_all(&data[cmp::min(split + 2, data.len())..])
.unwrap();
compressor.finish().unwrap()
};
let decompressed = decompress_to_end(&compressed);
assert!(decompressed == data);
let mut compressor = DeflateEncoder::new(
Vec::with_capacity(data.len() / 3),
CompressionOptions::default(),
);
compressor.flush().unwrap();
compressor.write_all(&[1, 2]).unwrap();
compressor.flush().unwrap();
compressor.write_all(&[3]).unwrap();
compressor.flush().unwrap();
let compressed = compressor.finish().unwrap();
let decompressed = decompress_to_end(&compressed);
assert_eq!(decompressed, [1, 2, 3]);
}
}