#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InflateError {
UnexpectedEnd,
BadBlockType,
BadStoredLength,
BadCode,
BadDistance,
OutputOverflow,
}
const MAX_BITS: usize = 15;
const LENGTH_BASE: [u16; 29] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
163, 195, 227, 258,
];
const LENGTH_EXTRA: [u8; 29] = [
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
];
const DISTANCE_BASE: [u16; 30] = [
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
];
const DISTANCE_EXTRA: [u8; 30] = [
0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13,
13,
];
const CODE_LENGTH_ORDER: [usize; 19] = [
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
];
struct Huffman {
counts: [u16; MAX_BITS + 1],
symbols: Vec<u16>,
}
impl Huffman {
fn build(lengths: &[u8]) -> Self {
let mut counts = [0u16; MAX_BITS + 1];
for &length in lengths {
counts[length as usize] += 1;
}
counts[0] = 0;
let mut offsets = [0u16; MAX_BITS + 2];
for length in 1..=MAX_BITS {
offsets[length + 1] = offsets[length] + counts[length];
}
let mut symbols = vec![0u16; lengths.len()];
for (symbol, &length) in lengths.iter().enumerate() {
if length != 0 {
symbols[offsets[length as usize] as usize] = symbol as u16;
offsets[length as usize] += 1;
}
}
Self { counts, symbols }
}
}
struct BitReader<'a> {
data: &'a [u8],
byte_position: usize,
bit_buffer: u32,
bit_count: u32,
}
impl<'a> BitReader<'a> {
fn new(data: &'a [u8]) -> Self {
Self { data, byte_position: 0, bit_buffer: 0, bit_count: 0 }
}
fn bits(&mut self, count: u32) -> Result<u32, InflateError> {
while self.bit_count < count {
let byte = *self.data.get(self.byte_position).ok_or(InflateError::UnexpectedEnd)?;
self.byte_position += 1;
self.bit_buffer |= (byte as u32) << self.bit_count;
self.bit_count += 8;
}
let value = self.bit_buffer & ((1u32 << count) - 1);
self.bit_buffer >>= count;
self.bit_count -= count;
Ok(value)
}
fn align_to_byte(&mut self) {
let drop = self.bit_count % 8;
self.bit_buffer >>= drop;
self.bit_count -= drop;
}
fn decode(&mut self, table: &Huffman) -> Result<u16, InflateError> {
let mut code = 0i32;
let mut first = 0i32;
let mut index = 0i32;
for length in 1..=MAX_BITS {
code |= self.bits(1)? as i32;
let count = table.counts[length] as i32;
if code - first < count {
return Ok(table.symbols[(index + (code - first)) as usize]);
}
index += count;
first = (first + count) << 1;
code <<= 1;
}
Err(InflateError::BadCode)
}
}
pub fn inflate(input: &[u8], expected_size: usize) -> Result<Vec<u8>, InflateError> {
let mut reader = BitReader::new(input);
let mut output = Vec::with_capacity(expected_size);
loop {
let is_final = reader.bits(1)?;
let block_type = reader.bits(2)?;
match block_type {
0 => inflate_stored(&mut reader, &mut output, expected_size)?,
1 => inflate_block(&mut reader, &mut output, &fixed_tables(), expected_size)?,
2 => {
let (literals, distances) = read_dynamic_tables(&mut reader)?;
inflate_block_with(&mut reader, &mut output, &literals, &distances, expected_size)?
}
_ => return Err(InflateError::BadBlockType),
}
if is_final == 1 {
break;
}
}
Ok(output)
}
fn inflate_stored(
reader: &mut BitReader,
output: &mut Vec<u8>,
expected_size: usize,
) -> Result<(), InflateError> {
reader.align_to_byte();
let length = reader.bits(16)? as usize;
let complement = reader.bits(16)? as usize;
if length != (!complement & 0xffff) {
return Err(InflateError::BadStoredLength);
}
for _ in 0..length {
if output.len() >= expected_size {
return Err(InflateError::OutputOverflow);
}
output.push(reader.bits(8)? as u8);
}
Ok(())
}
fn fixed_tables() -> (Huffman, Huffman) {
let mut literal_lengths = [0u8; 288];
for (symbol, length) in literal_lengths.iter_mut().enumerate() {
*length = match symbol {
0..=143 => 8,
144..=255 => 9,
256..=279 => 7,
_ => 8,
};
}
let distance_lengths = [5u8; 30];
(Huffman::build(&literal_lengths), Huffman::build(&distance_lengths))
}
fn inflate_block(
reader: &mut BitReader,
output: &mut Vec<u8>,
tables: &(Huffman, Huffman),
expected_size: usize,
) -> Result<(), InflateError> {
inflate_block_with(reader, output, &tables.0, &tables.1, expected_size)
}
fn read_dynamic_tables(reader: &mut BitReader) -> Result<(Huffman, Huffman), InflateError> {
let literal_count = reader.bits(5)? as usize + 257;
let distance_count = reader.bits(5)? as usize + 1;
let code_length_count = reader.bits(4)? as usize + 4;
let mut code_length_lengths = [0u8; 19];
for index in 0..code_length_count {
code_length_lengths[CODE_LENGTH_ORDER[index]] = reader.bits(3)? as u8;
}
let code_length_table = Huffman::build(&code_length_lengths);
let total = literal_count + distance_count;
let mut lengths = vec![0u8; total];
let mut index = 0;
while index < total {
let symbol = reader.decode(&code_length_table)?;
match symbol {
0..=15 => {
lengths[index] = symbol as u8;
index += 1;
}
16 => {
if index == 0 {
return Err(InflateError::BadCode);
}
let previous = lengths[index - 1];
let repeat = reader.bits(2)? as usize + 3;
for _ in 0..repeat {
if index >= total {
return Err(InflateError::BadCode);
}
lengths[index] = previous;
index += 1;
}
}
17 => {
let repeat = reader.bits(3)? as usize + 3;
index = fill_zeros(&mut lengths, index, repeat)?;
}
18 => {
let repeat = reader.bits(7)? as usize + 11;
index = fill_zeros(&mut lengths, index, repeat)?;
}
_ => return Err(InflateError::BadCode),
}
}
let literals = Huffman::build(&lengths[..literal_count]);
let distances = Huffman::build(&lengths[literal_count..]);
Ok((literals, distances))
}
fn fill_zeros(lengths: &mut [u8], mut index: usize, repeat: usize) -> Result<usize, InflateError> {
for _ in 0..repeat {
if index >= lengths.len() {
return Err(InflateError::BadCode);
}
lengths[index] = 0;
index += 1;
}
Ok(index)
}
fn inflate_block_with(
reader: &mut BitReader,
output: &mut Vec<u8>,
literals: &Huffman,
distances: &Huffman,
expected_size: usize,
) -> Result<(), InflateError> {
loop {
let symbol = reader.decode(literals)?;
match symbol {
0..=255 => {
if output.len() >= expected_size {
return Err(InflateError::OutputOverflow);
}
output.push(symbol as u8);
}
256 => return Ok(()), 257..=285 => {
let length_symbol = (symbol - 257) as usize;
let length = LENGTH_BASE[length_symbol] as usize
+ reader.bits(LENGTH_EXTRA[length_symbol] as u32)? as usize;
let distance_symbol = reader.decode(distances)? as usize;
if distance_symbol >= DISTANCE_BASE.len() {
return Err(InflateError::BadCode);
}
let distance = DISTANCE_BASE[distance_symbol] as usize
+ reader.bits(DISTANCE_EXTRA[distance_symbol] as u32)? as usize;
if distance > output.len() {
return Err(InflateError::BadDistance);
}
let start = output.len() - distance;
for offset in 0..length {
if output.len() >= expected_size {
return Err(InflateError::OutputOverflow);
}
output.push(output[start + offset]);
}
}
_ => return Err(InflateError::BadCode),
}
}
}