use std::io::{self, Read};
use lzma_sys::*;
use std;
use error::LzmaError;
use ::Direction;
use lzma_stream_wrapper::LzmaStreamWrapper;
const DEFAULT_BUF_SIZE: usize = 4 * 1024;
pub struct LzmaReader<T> {
inner: T,
stream: LzmaStreamWrapper,
buffer: Vec<u8>,
buffer_offset: usize,
buffer_len: usize,
direction: Direction,
}
impl<T: Read> LzmaReader<T> {
pub fn new_compressor(inner: T, preset: u32) -> Result<LzmaReader<T>, LzmaError> {
LzmaReader::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Compress, preset)
}
pub fn new_decompressor(inner: T) -> Result<LzmaReader<T>, LzmaError> {
LzmaReader::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Decompress, 0)
}
pub fn with_capacity(capacity: usize, inner: T, direction: Direction, preset: u32) -> Result<LzmaReader<T>, LzmaError> {
let mut reader = LzmaReader {
inner,
stream: LzmaStreamWrapper::new(),
buffer: vec![0; capacity],
buffer_offset: 0,
buffer_len: 0,
direction,
};
match reader.direction {
Direction::Compress => {
reader.stream.easy_encoder(preset, lzma_check::LzmaCheckCrc64)?
},
Direction::Decompress => {
reader.stream.stream_decoder(std::u64::MAX, 0)?
},
}
Ok(reader)
}
pub fn into_inner(self) -> T { self.inner }
}
impl<R: Read> Read for LzmaReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
loop {
let mut action = lzma_action::LzmaRun;
if self.buffer_len == 0 {
self.buffer_offset = 0;
self.buffer_len = self.inner.read(&mut self.buffer)?;
if self.buffer_len == 0 {
action = lzma_action::LzmaFinish;
}
}
let result = self.stream.code(&self.buffer[self.buffer_offset..(self.buffer_offset+self.buffer_len)], buf, action);
self.buffer_offset += result.bytes_read;
self.buffer_len -= result.bytes_read;
let stream_end = match result.ret {
Ok(lzma_ret::LzmaStreamEnd) => true,
Ok(_) => false,
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err)),
};
if stream_end || result.bytes_written > 0 {
return Ok(result.bytes_written);
}
}
}
}