use std::io;
use std::io::prelude::*;
use crate::{Action, Compress, Compression, Decompress, Status};
pub struct BzEncoder<R> {
obj: R,
data: Compress,
done: bool,
}
pub struct BzDecoder<R> {
obj: R,
data: Decompress,
done: bool,
multi: bool,
}
impl<R: BufRead> BzEncoder<R> {
pub fn new(r: R, level: Compression) -> Self {
Self {
obj: r,
data: Compress::new(level, 30),
done: false,
}
}
}
impl<R> BzEncoder<R> {
pub fn get_ref(&self) -> &R {
&self.obj
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.obj
}
pub fn into_inner(self) -> R {
self.obj
}
pub fn total_out(&self) -> u64 {
self.data.total_out()
}
pub fn total_in(&self) -> u64 {
self.data.total_in()
}
}
impl<R: BufRead> Read for BzEncoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.done {
return Ok(0);
}
loop {
let (read, consumed, eof, ret);
{
let input = self.obj.fill_buf()?;
eof = input.is_empty();
let before_out = self.data.total_out();
let before_in = self.data.total_in();
let action = if eof { Action::Finish } else { Action::Run };
ret = self.data.compress(input, buf, action);
read = (self.data.total_out() - before_out) as usize;
consumed = (self.data.total_in() - before_in) as usize;
}
self.obj.consume(consumed);
let ret = ret.unwrap();
if read == 0 && !eof && !buf.is_empty() {
continue;
}
if ret == Status::StreamEnd {
self.done = true;
}
return Ok(read);
}
}
}
impl<W: Write> Write for BzEncoder<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()
}
}
impl<R: BufRead> BzDecoder<R> {
pub fn new(r: R) -> Self {
Self {
obj: r,
data: Decompress::new(false),
done: false,
multi: false,
}
}
fn multi(mut self, flag: bool) -> Self {
self.multi = flag;
self
}
}
impl<R> BzDecoder<R> {
pub fn get_ref(&self) -> &R {
&self.obj
}
pub fn get_mut(&mut self) -> &mut R {
&mut self.obj
}
pub fn into_inner(self) -> R {
self.obj
}
pub fn total_in(&self) -> u64 {
self.data.total_in()
}
pub fn total_out(&self) -> u64 {
self.data.total_out()
}
}
impl<R: BufRead> Read for BzDecoder<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
loop {
if self.done && !self.multi {
return Ok(0);
}
let (read, consumed, remaining, ret);
{
let input = self.obj.fill_buf()?;
if self.done {
assert!(self.multi);
if input.is_empty() {
return Ok(0);
} else {
self.data = Decompress::new(false);
self.done = false;
}
}
let before_out = self.data.total_out();
let before_in = self.data.total_in();
ret = self.data.decompress(input, buf);
read = (self.data.total_out() - before_out) as usize;
consumed = (self.data.total_in() - before_in) as usize;
remaining = input.len() - consumed;
}
self.obj.consume(consumed);
let ret = ret.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
if ret == Status::StreamEnd {
self.done = true;
} else if consumed == 0 && remaining == 0 && read == 0 {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"decompression not finished but EOF reached",
));
}
if read > 0 || buf.is_empty() {
return Ok(read);
}
}
}
}
impl<W: Write> Write for BzDecoder<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()
}
}
pub struct MultiBzDecoder<R>(BzDecoder<R>);
impl<R: BufRead> MultiBzDecoder<R> {
pub fn new(r: R) -> Self {
Self(BzDecoder::new(r).multi(true))
}
}
impl<R> MultiBzDecoder<R> {
pub fn get_ref(&self) -> &R {
self.0.get_ref()
}
pub fn get_mut(&mut self) -> &mut R {
self.0.get_mut()
}
pub fn into_inner(self) -> R {
self.0.into_inner()
}
}
impl<R: BufRead> Read for MultiBzDecoder<R> {
fn read(&mut self, into: &mut [u8]) -> io::Result<usize> {
self.0.read(into)
}
}
impl<R: BufRead + Write> Write for MultiBzDecoder<R> {
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(test)]
mod tests {
use super::MultiBzDecoder;
use std::io::{BufReader, Read};
#[test]
fn bug_61() {
let compressed_bytes = include_bytes!("../tests/bug_61.bz2");
let uncompressed_bytes = include_bytes!("../tests/bug_61.raw");
let reader = BufReader::with_capacity(8192, compressed_bytes.as_ref());
let mut d = MultiBzDecoder::new(reader);
let mut data = Vec::new();
assert_eq!(d.read_to_end(&mut data).unwrap(), uncompressed_bytes.len());
assert_eq!(data, uncompressed_bytes);
}
}