use std::io::{self, BufRead, Read, Write};
use std::vec;
use std::vec::Vec;
use crate::error::Result;
use crate::params::{MAX_INPUT_PER_SYMBOL, Params};
use crate::sevenz::{SevenZDecoder, SevenZEncoder, SevenZStatus};
const STITCH: usize = 2 * MAX_INPUT_PER_SYMBOL;
const WRITE_BUF: usize = 64 << 10;
pub struct SevenZReader<R: BufRead> {
inner: R,
decoder: SevenZDecoder,
stitch: Vec<u8>,
done: bool,
}
impl<R: BufRead> SevenZReader<R> {
pub fn new(inner: R, params: Params, unpacked: Option<u64>) -> Result<Self> {
Ok(Self::from_decoder(
inner,
SevenZDecoder::new(params, unpacked)?,
))
}
pub fn from_decoder(inner: R, decoder: SevenZDecoder) -> Self {
Self {
inner,
decoder,
stitch: Vec::new(),
done: false,
}
}
pub fn decoder(&self) -> &SevenZDecoder {
&self.decoder
}
pub fn get_ref(&self) -> &R {
&self.inner
}
pub fn into_parts(self) -> (R, SevenZDecoder) {
(self.inner, self.decoder)
}
fn step(&mut self, buf: &mut [u8]) -> io::Result<SevenZStatus> {
if self.stitch.is_empty() {
let avail = self.inner.fill_buf()?;
let last = avail.is_empty();
let step = self.decoder.decode(avail, last, buf)?;
let len = avail.len();
if step.status == SevenZStatus::NeedInput {
self.stitch.extend_from_slice(&avail[step.consumed..]);
self.inner.consume(len);
} else {
self.inner.consume(step.consumed);
}
return Ok(self.finish_step(step.produced, step.status));
}
let old = self.stitch.len();
let avail = self.inner.fill_buf()?;
let last = avail.is_empty();
let take = avail.len().min(STITCH - old);
self.stitch.extend_from_slice(&avail[..take]);
let step = self.decoder.decode(&self.stitch, last, buf)?;
if step.consumed >= old {
self.inner.consume(step.consumed - old);
self.stitch.clear();
} else if step.status == SevenZStatus::NeedInput {
self.stitch.drain(..step.consumed);
self.inner.consume(take);
} else {
self.stitch.truncate(old);
self.stitch.drain(..step.consumed);
}
Ok(self.finish_step(step.produced, step.status))
}
fn finish_step(&mut self, _produced: usize, status: SevenZStatus) -> SevenZStatus {
if matches!(status, SevenZStatus::ReachedSize | SevenZStatus::EndMarker) {
self.done = true;
}
status
}
}
impl<R: BufRead> Read for SevenZReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
loop {
if self.done {
return Ok(0);
}
let before = self.decoder.total_out();
let status = self.step(buf)?;
let produced = (self.decoder.total_out() - before) as usize;
match status {
SevenZStatus::NeedInput if produced == 0 => continue,
_ => return Ok(produced),
}
}
}
}
pub struct SevenZWriter<W: Write> {
inner: W,
encoder: SevenZEncoder,
buf: Vec<u8>,
end_marker: bool,
finished: bool,
}
impl<W: Write> SevenZWriter<W> {
pub fn new(inner: W, params: Params) -> Result<Self> {
Ok(Self::from_encoder(inner, SevenZEncoder::new(params)?))
}
pub fn from_encoder(inner: W, encoder: SevenZEncoder) -> Self {
Self {
inner,
encoder,
buf: vec![0u8; WRITE_BUF],
end_marker: false,
finished: false,
}
}
pub fn set_end_marker(&mut self, on: bool) {
self.end_marker = on;
}
pub fn encoder(&self) -> &SevenZEncoder {
&self.encoder
}
pub fn get_ref(&self) -> &W {
&self.inner
}
pub fn finish(&mut self) -> io::Result<()> {
while !self.finished {
let fin = self.encoder.finish(&mut self.buf, self.end_marker)?;
self.inner.write_all(&self.buf[..fin.produced])?;
self.finished = fin.done;
}
self.inner.flush()
}
pub fn into_parts(self) -> (W, SevenZEncoder) {
(self.inner, self.encoder)
}
pub fn into_inner(self) -> W {
self.inner
}
}
impl<W: Write> Write for SevenZWriter<W> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if data.is_empty() {
return Ok(0);
}
loop {
let step = self.encoder.encode(data, &mut self.buf)?;
self.inner.write_all(&self.buf[..step.produced])?;
if step.consumed > 0 {
return Ok(step.consumed);
}
}
}
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}