blob: f2462344e901903c04adc21e5956ff73ec72fe40 [file] [log] [blame]
use std::io;
use std::io::Read;
use std::cmp;
use std::ptr;
use std::vec::Vec;
use byteorder::ReadBytesExt;
use byteorder::LittleEndian;
use bit;
use lz77;
use util;
use super::symbol;
/// DEFLATE decoder.
#[derive(Debug)]
pub struct Decoder<R> {
bit_reader: bit::BitReader<R>,
buffer: Vec<u8>,
offset: usize,
eos: bool,
}
impl<R> Decoder<R>
where
R: Read,
{
/// Makes a new decoder instance.
///
/// `inner` is to be decoded DEFLATE stream.
///
/// # Examples
/// ```
/// use std::io::{Cursor, Read};
/// use libflate::deflate::Decoder;
///
/// let encoded_data = [243, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73, 81, 4, 0];
/// let mut decoder = Decoder::new(&encoded_data[..]);
/// let mut buf = Vec::new();
/// decoder.read_to_end(&mut buf).unwrap();
///
/// assert_eq!(buf, b"Hello World!");
/// ```
pub fn new(inner: R) -> Self {
Decoder {
bit_reader: bit::BitReader::new(inner),
buffer: Vec::new(),
offset: 0,
eos: false,
}
}
/// Returns the immutable reference to the inner stream.
pub fn as_inner_ref(&self) -> &R {
self.bit_reader.as_inner_ref()
}
/// Returns the mutable reference to the inner stream.
pub fn as_inner_mut(&mut self) -> &mut R {
self.bit_reader.as_inner_mut()
}
/// Unwraps this `Decoder`, returning the underlying reader.
///
/// # Examples
/// ```
/// use std::io::Cursor;
/// use libflate::deflate::Decoder;
///
/// let encoded_data = [243, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73, 81, 4, 0];
/// let decoder = Decoder::new(Cursor::new(&encoded_data));
/// assert_eq!(decoder.into_inner().into_inner(), &encoded_data);
/// ```
pub fn into_inner(self) -> R {
self.bit_reader.into_inner()
}
fn read_non_compressed_block(&mut self) -> io::Result<()> {
self.bit_reader.reset();
let len = self.bit_reader.as_inner_mut().read_u16::<LittleEndian>()?;
let nlen = self.bit_reader.as_inner_mut().read_u16::<LittleEndian>()?;
if !len != nlen {
Err(invalid_data_error!(
"LEN={} is not the one's complement of NLEN={}",
len,
nlen
))
} else {
let old_len = self.buffer.len();
self.buffer.reserve(len as usize);
unsafe { self.buffer.set_len(old_len + len as usize) };
self.bit_reader.as_inner_mut().read_exact(
&mut self.buffer[old_len..],
)?;
Ok(())
}
}
fn read_compressed_block<H>(&mut self, huffman: H) -> io::Result<()>
where
H: symbol::HuffmanCodec,
{
let symbol_decoder = huffman.load(&mut self.bit_reader)?;
loop {
let s = symbol_decoder.decode_unchecked(&mut self.bit_reader);
self.bit_reader.check_last_error()?;
match s {
symbol::Symbol::Literal(b) => {
self.buffer.push(b);
}
symbol::Symbol::Share { length, distance } => {
if self.buffer.len() < distance as usize {
return Err(invalid_data_error!(
"Too long backword reference: buffer.len={}, distance={}",
self.buffer.len(),
distance
));
}
let old_len = self.buffer.len();
self.buffer.reserve(length as usize);
unsafe {
self.buffer.set_len(old_len + length as usize);
let start = old_len - distance as usize;
let ptr = self.buffer.as_mut_ptr();
util::ptr_copy(
ptr.offset(start as isize),
ptr.offset(old_len as isize),
length as usize,
length > distance,
);
}
}
symbol::Symbol::EndOfBlock => {
break;
}
}
}
Ok(())
}
fn truncate_old_buffer(&mut self) {
if self.buffer.len() > lz77::MAX_DISTANCE as usize * 4 {
let new_len = lz77::MAX_DISTANCE as usize;
unsafe {
let ptr = self.buffer.as_mut_ptr();
let src = ptr.offset((self.buffer.len() - new_len) as isize);
ptr::copy_nonoverlapping(src, ptr, new_len);
}
self.buffer.truncate(new_len);
self.offset = new_len;
}
}
}
impl<R> Read for Decoder<R>
where
R: Read,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.offset < self.buffer.len() {
let copy_size = cmp::min(buf.len(), self.buffer.len() - self.offset);
buf[..copy_size].copy_from_slice(&self.buffer[self.offset..][..copy_size]);
self.offset += copy_size;
Ok(copy_size)
} else if self.eos {
Ok(0)
} else {
let bfinal = self.bit_reader.read_bit()?;
let btype = self.bit_reader.read_bits(2)?;
self.eos = bfinal;
self.truncate_old_buffer();
match btype {
0b00 => {
self.read_non_compressed_block()?;
self.read(buf)
}
0b01 => {
self.read_compressed_block(symbol::FixedHuffmanCodec)?;
self.read(buf)
}
0b10 => {
self.read_compressed_block(symbol::DynamicHuffmanCodec)?;
self.read(buf)
}
0b11 => Err(invalid_data_error!(
"btype 0x11 of DEFLATE is reserved(error) value"
)),
_ => unreachable!(),
}
}
}
}
#[cfg(test)]
mod test {
use std::io;
use deflate::symbol::{HuffmanCodec, DynamicHuffmanCodec};
use super::*;
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_issues_3() {
// see: https://github.com/sile/libflate/issues/3
let input =
[180, 253, 73, 143, 28, 201, 150, 46, 8, 254, 150, 184, 139, 75, 18, 69,
247, 32, 157, 51, 27, 141, 132, 207, 78, 210, 167, 116, 243, 160, 223,
136, 141, 66, 205, 76, 221, 76, 195, 213, 84, 236, 234, 224, 78, 227, 34,
145, 221, 139, 126, 232, 69, 173, 170, 208, 192, 219, 245, 67, 3, 15, 149,
120, 171, 70, 53, 106, 213, 175, 23, 21, 153, 139, 254, 27, 249, 75, 234,
124, 71, 116, 56, 71, 68, 212, 204, 121, 115, 64, 222, 160, 203, 119,
142, 170, 169, 138, 202, 112, 228, 140, 38];
let mut bit_reader = ::bit::BitReader::new(&input[..]);
assert_eq!(bit_reader.read_bit().unwrap(), false); // not final block
assert_eq!(bit_reader.read_bits(2).unwrap(), 0b10); // DynamicHuffmanCodec
DynamicHuffmanCodec.load(&mut bit_reader).unwrap();
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn it_works() {
let input =
[180, 253, 73, 143, 28, 201, 150, 46, 8, 254, 150, 184, 139, 75, 18,
69, 247, 32, 157, 51, 27, 141, 132, 207, 78, 210, 167, 116, 243,
160, 223, 136, 141, 66, 205, 76, 221, 76, 195, 213, 84, 236, 234,
224, 78, 227, 34, 145, 221, 139, 126, 232, 69, 173, 170, 208, 192,
219, 245, 67, 3, 15, 149, 120, 171, 70, 53, 106, 213, 175, 23, 21,
153, 139, 254, 27, 249, 75, 234, 124, 71, 116, 56, 71, 68, 212, 204,
121, 115, 64, 222, 160, 203, 119, 142, 170, 169, 138, 202, 112, 228,
140, 38, 171, 162, 88, 212, 235, 56, 136, 231, 233, 239, 113, 249,
163, 252, 16, 42, 138, 49, 226, 108, 73, 28, 153];
let mut decoder = Decoder::new(&input[..]);
let result = io::copy(&mut decoder, &mut io::sink());
assert!(result.is_err());
let error = result.err().unwrap();
assert_eq!(error.kind(), io::ErrorKind::InvalidData);
assert!(error.to_string().starts_with("Too long backword reference"));
}
}