lzma_rs/decode/
lzbuffer.rsuse crate::error;
use std::io;
pub trait LzBuffer<W>
where
W: io::Write,
{
fn len(&self) -> usize;
fn last_or(&self, lit: u8) -> u8;
fn last_n(&self, dist: usize) -> error::Result<u8>;
fn append_literal(&mut self, lit: u8) -> error::Result<()>;
fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()>;
fn get_output(&self) -> &W;
fn get_output_mut(&mut self) -> &mut W;
fn finish(self) -> io::Result<W>;
fn into_output(self) -> W;
}
pub struct LzAccumBuffer<W>
where
W: io::Write,
{
stream: W, buf: Vec<u8>, memlimit: usize, len: usize, }
impl<W> LzAccumBuffer<W>
where
W: io::Write,
{
pub fn from_stream(stream: W, memlimit: usize) -> Self {
Self {
stream,
buf: Vec::new(),
memlimit,
len: 0,
}
}
pub fn append_bytes(&mut self, buf: &[u8]) {
self.buf.extend_from_slice(buf);
self.len += buf.len();
}
pub fn reset(&mut self) -> io::Result<()> {
self.stream.write_all(self.buf.as_slice())?;
self.buf.clear();
self.len = 0;
Ok(())
}
}
impl<W> LzBuffer<W> for LzAccumBuffer<W>
where
W: io::Write,
{
fn len(&self) -> usize {
self.len
}
fn last_or(&self, lit: u8) -> u8 {
let buf_len = self.buf.len();
if buf_len == 0 {
lit
} else {
self.buf[buf_len - 1]
}
}
fn last_n(&self, dist: usize) -> error::Result<u8> {
let buf_len = self.buf.len();
if dist > buf_len {
return Err(error::Error::LzmaError(format!(
"Match distance {} is beyond output size {}",
dist, buf_len
)));
}
Ok(self.buf[buf_len - dist])
}
fn append_literal(&mut self, lit: u8) -> error::Result<()> {
let new_len = self.len + 1;
if new_len > self.memlimit {
Err(error::Error::LzmaError(format!(
"exceeded memory limit of {}",
self.memlimit
)))
} else {
self.buf.push(lit);
self.len = new_len;
Ok(())
}
}
fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()> {
lzma_debug!("LZ {{ len: {}, dist: {} }}", len, dist);
let buf_len = self.buf.len();
if dist > buf_len {
return Err(error::Error::LzmaError(format!(
"LZ distance {} is beyond output size {}",
dist, buf_len
)));
}
let mut offset = buf_len - dist;
for _ in 0..len {
let x = self.buf[offset];
self.buf.push(x);
offset += 1;
}
self.len += len;
Ok(())
}
fn get_output(&self) -> &W {
&self.stream
}
fn get_output_mut(&mut self) -> &mut W {
&mut self.stream
}
fn finish(mut self) -> io::Result<W> {
self.stream.write_all(self.buf.as_slice())?;
self.stream.flush()?;
Ok(self.stream)
}
fn into_output(self) -> W {
self.stream
}
}
pub struct LzCircularBuffer<W>
where
W: io::Write,
{
stream: W, buf: Vec<u8>, dict_size: usize, memlimit: usize, cursor: usize, len: usize, }
impl<W> LzCircularBuffer<W>
where
W: io::Write,
{
pub fn from_stream(stream: W, dict_size: usize, memlimit: usize) -> Self {
lzma_info!("Dict size in LZ buffer: {}", dict_size);
Self {
stream,
buf: Vec::new(),
dict_size,
memlimit,
cursor: 0,
len: 0,
}
}
fn get(&self, index: usize) -> u8 {
*self.buf.get(index).unwrap_or(&0)
}
fn set(&mut self, index: usize, value: u8) -> error::Result<()> {
let new_len = index + 1;
if self.buf.len() < new_len {
if new_len <= self.memlimit {
self.buf.resize(new_len, 0);
} else {
return Err(error::Error::LzmaError(format!(
"exceeded memory limit of {}",
self.memlimit
)));
}
}
self.buf[index] = value;
Ok(())
}
}
impl<W> LzBuffer<W> for LzCircularBuffer<W>
where
W: io::Write,
{
fn len(&self) -> usize {
self.len
}
fn last_or(&self, lit: u8) -> u8 {
if self.len == 0 {
lit
} else {
self.get((self.dict_size + self.cursor - 1) % self.dict_size)
}
}
fn last_n(&self, dist: usize) -> error::Result<u8> {
if dist > self.dict_size {
return Err(error::Error::LzmaError(format!(
"Match distance {} is beyond dictionary size {}",
dist, self.dict_size
)));
}
if dist > self.len {
return Err(error::Error::LzmaError(format!(
"Match distance {} is beyond output size {}",
dist, self.len
)));
}
let offset = (self.dict_size + self.cursor - dist) % self.dict_size;
Ok(self.get(offset))
}
fn append_literal(&mut self, lit: u8) -> error::Result<()> {
self.set(self.cursor, lit)?;
self.cursor += 1;
self.len += 1;
if self.cursor == self.dict_size {
self.stream.write_all(self.buf.as_slice())?;
self.cursor = 0;
}
Ok(())
}
fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()> {
lzma_debug!("LZ {{ len: {}, dist: {} }}", len, dist);
if dist > self.dict_size {
return Err(error::Error::LzmaError(format!(
"LZ distance {} is beyond dictionary size {}",
dist, self.dict_size
)));
}
if dist > self.len {
return Err(error::Error::LzmaError(format!(
"LZ distance {} is beyond output size {}",
dist, self.len
)));
}
let mut offset = (self.dict_size + self.cursor - dist) % self.dict_size;
for _ in 0..len {
let x = self.get(offset);
self.append_literal(x)?;
offset += 1;
if offset == self.dict_size {
offset = 0
}
}
Ok(())
}
fn get_output(&self) -> &W {
&self.stream
}
fn get_output_mut(&mut self) -> &mut W {
&mut self.stream
}
fn finish(mut self) -> io::Result<W> {
if self.cursor > 0 {
self.stream.write_all(&self.buf[0..self.cursor])?;
self.stream.flush()?;
}
Ok(self.stream)
}
fn into_output(self) -> W {
self.stream
}
}