use crate::*;
use std::io;
use std::io::Write;
pub struct Encoder<W: io::Write> {
inner: W,
stream: ZStream,
out_buf: Vec<u8>,
dsts: usize,
dste: usize,
total_in: usize,
total_out: usize,
codec: Codec,
}
impl<W: io::Write> Encoder<W> {
pub fn new(writer: W, level: CompressionLevel, codec: Codec) -> Encoder<W> {
let out_buf = Vec::with_capacity(BUF_SIZE);
let mut zstream = ZStream::new(level, ZStreamKind::Stateful);
zstream.stream.end_of_stream = 0;
zstream.stream.flush = FlushFlags::NoFlush as _;
zstream.stream.gzip_flag = codec as _;
Self {
inner: writer,
stream: zstream,
out_buf,
dste: 0,
dsts: 0,
total_in: 0,
total_out: 0,
codec,
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner
}
pub fn get_ref(&self) -> &W {
&self.inner
}
pub fn finish(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.inner)
}
pub fn total_out(&self) -> usize {
self.stream.stream.total_out as usize + self.total_out
}
pub fn total_in(&self) -> usize {
self.stream.stream.total_in as usize + self.total_in
}
#[inline(always)]
fn write_from_out_buf(&mut self) -> io::Result<usize> {
let count = self.dste - self.dsts;
self.inner
.write_all(&mut self.out_buf[self.dsts..self.dste])?;
self.out_buf.truncate(0);
self.dsts = 0;
self.dste = 0;
Ok(count)
}
}
impl<W: io::Write> io::Write for Encoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
self.stream.stream.avail_in = buf.len() as _;
self.stream.stream.next_in = buf.as_ptr() as *mut _;
while self.stream.stream.avail_in > 0 {
self.out_buf.resize(self.dste + BUF_SIZE, 0);
self.stream.stream.avail_out = BUF_SIZE as _;
self.stream.stream.next_out =
self.out_buf[self.dste..self.dste + BUF_SIZE].as_mut_ptr();
self.stream.deflate()?;
self.dste += BUF_SIZE - self.stream.stream.avail_out as usize;
}
self.write_from_out_buf()?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
self.stream.stream.end_of_stream = 1;
self.stream.stream.flush = FlushFlags::FullFlush as _;
while self.stream.stream.internal_state.state != isal::isal_zstate_state_ZSTATE_END {
self.out_buf.resize(self.dste + BUF_SIZE, 0);
self.stream.stream.avail_out = BUF_SIZE as _;
self.stream.stream.next_out =
self.out_buf[self.dste..self.dste + BUF_SIZE].as_mut_ptr();
self.stream.deflate()?;
self.dste += BUF_SIZE - self.stream.stream.avail_out as usize;
}
self.write_from_out_buf()?;
self.inner.flush()?;
self.total_in += self.stream.stream.total_in as usize;
self.total_out += self.stream.stream.total_out as usize;
unsafe { isal::isal_deflate_reset(&mut self.stream.stream) };
self.stream.stream.flush = FlushFlags::NoFlush as _;
self.stream.stream.end_of_stream = 0;
self.stream.stream.gzip_flag = self.codec as _;
Ok(())
}
}
pub struct Decoder<W: io::Write> {
inner: W,
zst: InflateState,
out_buf: Vec<u8>,
total_out: usize,
total_in: usize,
#[allow(dead_code)]
codec: Codec,
}
impl<W: io::Write> Decoder<W> {
pub fn new(writer: W, codec: Codec) -> Decoder<W> {
let zst = InflateState::new(codec);
Self {
inner: writer,
zst,
out_buf: Vec::with_capacity(BUF_SIZE),
total_out: 0,
total_in: 0,
codec,
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner
}
pub fn get_ref(&self) -> &W {
&self.inner
}
}
impl<W: io::Write> io::Write for Decoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.zst.state.avail_in = buf.len() as _;
self.zst.state.next_in = buf.as_ptr() as *mut _;
self.total_in += buf.len();
let mut n_bytes = 0;
loop {
loop {
self.out_buf.resize(n_bytes + BUF_SIZE, 0);
self.zst.state.next_out = self.out_buf[n_bytes..n_bytes + BUF_SIZE].as_mut_ptr();
self.zst.state.avail_out = BUF_SIZE as _;
self.zst.step_inflate()?;
n_bytes += BUF_SIZE - self.zst.state.avail_out as usize;
self.total_out += n_bytes;
if self.zst.block_state() == isal::isal_block_state_ISAL_BLOCK_FINISH {
break;
}
}
if self.zst.block_state() == isal::isal_block_state_ISAL_BLOCK_FINISH {
self.zst.reset();
}
if self.zst.state.avail_in == 0 {
break;
}
}
self.inner.write_all(&self.out_buf[..n_bytes])?;
let nbytes = buf.len() - self.zst.state.avail_in as usize;
Ok(nbytes)
}
fn flush(&mut self) -> io::Result<()> {
if self.total_out == 0 && self.total_in == 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
Error::DecompressionError(DecompCode::EndInput),
));
}
self.inner.flush()
}
}
pub struct DeflateEncoder<R: io::Write> {
inner: Encoder<R>,
}
impl<W: io::Write> DeflateEncoder<W> {
pub fn new(writer: W, level: CompressionLevel) -> Self {
Self {
inner: Encoder::new(writer, level, Codec::Deflate),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
pub fn finish(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.inner.inner)
}
pub fn total_out(&self) -> usize {
self.inner.stream.stream.total_out as usize + self.inner.total_out
}
pub fn total_in(&self) -> usize {
self.inner.stream.stream.total_in as usize + self.inner.total_in
}
}
impl<W: io::Write> io::Write for DeflateEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub struct DeflateDecoder<W: io::Write> {
inner: Decoder<W>,
}
impl<W: io::Write> DeflateDecoder<W> {
pub fn new(writer: W) -> Self {
Self {
inner: Decoder::new(writer, Codec::Deflate),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
}
impl<W: io::Write> io::Write for DeflateDecoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub struct ZlibEncoder<R: io::Write> {
inner: Encoder<R>,
}
impl<W: io::Write> ZlibEncoder<W> {
pub fn new(writer: W, level: CompressionLevel) -> Self {
Self {
inner: Encoder::new(writer, level, Codec::Zlib),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
pub fn finish(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.inner.inner)
}
pub fn total_out(&self) -> usize {
self.inner.stream.stream.total_out as usize + self.inner.total_out
}
pub fn total_in(&self) -> usize {
self.inner.stream.stream.total_in as usize + self.inner.total_in
}
}
impl<W: io::Write> io::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()
}
}
pub struct ZlibDecoder<W: io::Write> {
inner: Decoder<W>,
}
impl<W: io::Write> ZlibDecoder<W> {
pub fn new(writer: W) -> Self {
Self {
inner: Decoder::new(writer, Codec::Zlib),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
}
impl<W: io::Write> io::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()
}
}
pub struct GzipEncoder<R: io::Write> {
inner: Encoder<R>,
}
impl<W: io::Write> GzipEncoder<W> {
pub fn new(writer: W, level: CompressionLevel) -> Self {
Self {
inner: Encoder::new(writer, level, Codec::Gzip),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
pub fn finish(mut self) -> io::Result<W> {
self.flush()?;
Ok(self.inner.inner)
}
pub fn total_out(&self) -> usize {
self.inner.stream.stream.total_out as usize + self.inner.total_out
}
pub fn total_in(&self) -> usize {
self.inner.stream.stream.total_in as usize + self.inner.total_in
}
}
impl<W: io::Write> io::Write for GzipEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
pub struct GzipDecoder<W: io::Write> {
inner: Decoder<W>,
}
impl<W: io::Write> GzipDecoder<W> {
pub fn new(writer: W) -> Self {
Self {
inner: Decoder::new(writer, Codec::Gzip),
}
}
pub fn get_ref_mut(&mut self) -> &mut W {
&mut self.inner.inner
}
pub fn get_ref(&self) -> &W {
&self.inner.inner
}
}
impl<W: io::Write> io::Write for GzipDecoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}