const MAX_BITS: usize = 15;
const FIXED_LIT_SYMBOLS: usize = 288;
const DIST_SYMBOLS: usize = 30;
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 DIST_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 DIST_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 CL_ORDER: [usize; 19] = [
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
];
struct Bits<'a> {
data: &'a [u8],
pos: usize,
bit_buf: u32,
bit_count: u32,
}
impl<'a> Bits<'a> {
fn new(data: &'a [u8]) -> Bits<'a> {
Bits {
data,
pos: 0,
bit_buf: 0,
bit_count: 0,
}
}
fn need(&mut self, n: u32) -> Result<(), &'static str> {
while self.bit_count < n {
let byte = *self.data.get(self.pos).ok_or("the data ended early")?;
self.pos += 1;
self.bit_buf |= u32::from(byte) << self.bit_count;
self.bit_count += 8;
}
Ok(())
}
fn bits(&mut self, n: u32) -> Result<u32, &'static str> {
if n == 0 {
return Ok(0);
}
self.need(n)?;
let v = self.bit_buf & ((1u32 << n) - 1);
self.bit_buf >>= n;
self.bit_count -= n;
Ok(v)
}
fn align(&mut self) {
self.bit_buf = 0;
self.bit_count = 0;
}
}
struct Huffman {
counts: [u16; MAX_BITS + 1],
symbols: Vec<u16>,
}
impl Huffman {
fn new(lengths: &[u8]) -> Result<Huffman, &'static str> {
let mut counts = [0u16; MAX_BITS + 1];
for &l in lengths {
counts[usize::from(l)] += 1;
}
counts[0] = 0;
let mut left: i32 = 1;
for &c in &counts[1..] {
left <<= 1;
left -= i32::from(c);
if left < 0 {
return Err("an over-subscribed Huffman code");
}
}
let mut offsets = [0u16; MAX_BITS + 2];
for len in 1..=MAX_BITS {
offsets[len + 1] = offsets[len] + counts[len];
}
let mut symbols = vec![0u16; lengths.len()];
for (sym, &l) in lengths.iter().enumerate() {
if l != 0 {
symbols[usize::from(offsets[usize::from(l)])] = sym as u16;
offsets[usize::from(l)] += 1;
}
}
Ok(Huffman { counts, symbols })
}
fn decode(&self, bits: &mut Bits) -> Result<u16, &'static str> {
let mut code: i32 = 0;
let mut first: i32 = 0;
let mut index: i32 = 0;
for len in 1..=MAX_BITS {
code |= bits.bits(1)? as i32;
let count = i32::from(self.counts[len]);
if code - count < first {
return Ok(self.symbols[(index + (code - first)) as usize]);
}
index += count;
first += count;
first <<= 1;
code <<= 1;
}
Err("an invalid Huffman code")
}
}
fn fixed_codes() -> (Huffman, Huffman) {
let mut lengths = [0u8; FIXED_LIT_SYMBOLS];
for (i, l) in lengths.iter_mut().enumerate() {
*l = match i {
0..=143 => 8,
144..=255 => 9,
256..=279 => 7,
_ => 8,
};
}
let lit = Huffman::new(&lengths).expect("the fixed literal code is well formed");
let dist = Huffman::new(&[5u8; DIST_SYMBOLS]).expect("the fixed distance code is well formed");
(lit, dist)
}
fn dynamic_codes(bits: &mut Bits) -> Result<(Huffman, Huffman), &'static str> {
let nlen = bits.bits(5)? as usize + 257;
let ndist = bits.bits(5)? as usize + 1;
let ncode = bits.bits(4)? as usize + 4;
if nlen > 286 || ndist > 30 {
return Err("a dynamic block with too many codes");
}
let mut cl_lengths = [0u8; 19];
for &i in CL_ORDER.iter().take(ncode) {
cl_lengths[i] = bits.bits(3)? as u8;
}
let cl = Huffman::new(&cl_lengths)?;
let mut lengths = vec![0u8; nlen + ndist];
let mut i = 0;
while i < nlen + ndist {
let sym = cl.decode(bits)?;
match sym {
0..=15 => {
lengths[i] = sym as u8;
i += 1;
}
16 => {
if i == 0 {
return Err("a repeat with no length before it");
}
let prev = lengths[i - 1];
let n = 3 + bits.bits(2)? as usize;
if i + n > lengths.len() {
return Err("a repeat past the end of the code lengths");
}
lengths[i..i + n].fill(prev);
i += n;
}
17 | 18 => {
let n = if sym == 17 {
3 + bits.bits(3)? as usize
} else {
11 + bits.bits(7)? as usize
};
if i + n > lengths.len() {
return Err("a repeat past the end of the code lengths");
}
i += n; }
_ => return Err("an invalid code length code"),
}
}
if lengths[256] == 0 {
return Err("a dynamic block with no end-of-block code");
}
let lit = Huffman::new(&lengths[..nlen])?;
let dist = Huffman::new(&lengths[nlen..])?;
Ok((lit, dist))
}
fn inflate_codes(
bits: &mut Bits,
out: &mut Vec<u8>,
lit: &Huffman,
dist: &Huffman,
limit: usize,
) -> Result<(), &'static str> {
loop {
let sym = lit.decode(bits)? as usize;
if sym < 256 {
if out.len() >= limit {
return Err("longer than the limit allows");
}
out.push(sym as u8);
} else if sym == 256 {
return Ok(());
} else {
let li = sym - 257;
if li >= LENGTH_BASE.len() {
return Err("an invalid length code");
}
let len =
usize::from(LENGTH_BASE[li]) + bits.bits(u32::from(LENGTH_EXTRA[li]))? as usize;
let di = dist.decode(bits)? as usize;
if di >= DIST_BASE.len() {
return Err("an invalid distance code");
}
let d = usize::from(DIST_BASE[di]) + bits.bits(u32::from(DIST_EXTRA[di]))? as usize;
if d > out.len() {
return Err("a reference before the start of the output");
}
if out.len() + len > limit {
return Err("longer than the limit allows");
}
let start = out.len() - d;
for k in 0..len {
let b = out[start + k];
out.push(b);
}
}
}
}
pub fn inflate(data: &[u8], hint: usize, limit: usize) -> Result<Vec<u8>, &'static str> {
let mut bits = Bits::new(data);
let mut out: Vec<u8> = Vec::with_capacity(hint.min(limit));
loop {
let last = bits.bits(1)? == 1;
match bits.bits(2)? {
0 => {
bits.align();
let len = usize::from(*bits.data.get(bits.pos).ok_or("the data ended early")?)
| (usize::from(*bits.data.get(bits.pos + 1).ok_or("the data ended early")?)
<< 8);
let nlen = usize::from(*bits.data.get(bits.pos + 2).ok_or("the data ended early")?)
| (usize::from(*bits.data.get(bits.pos + 3).ok_or("the data ended early")?)
<< 8);
if len != (!nlen & 0xFFFF) {
return Err("a stored block whose length check failed");
}
bits.pos += 4;
let block = bits
.data
.get(bits.pos..bits.pos + len)
.ok_or("the data ended early")?;
if out.len() + len > limit {
return Err("longer than the limit allows");
}
out.extend_from_slice(block);
bits.pos += len;
}
1 => {
let (lit, dist) = fixed_codes();
inflate_codes(&mut bits, &mut out, &lit, &dist, limit)?;
}
2 => {
let (lit, dist) = dynamic_codes(&mut bits)?;
inflate_codes(&mut bits, &mut out, &lit, &dist, limit)?;
}
_ => return Err("an invalid block type"),
}
if last {
return Ok(out);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const ABC_FIXED: &[u8] = &[0x4b, 0x4c, 0x4a, 0x06, 0x00];
const ABC_STORED: &[u8] = &[0x01, 0x03, 0x00, 0xfc, 0xff, 0x61, 0x62, 0x63];
const REP_FIXED: &[u8] = &[
0x73, 0x2b, 0x4a, 0xac, 0x4a, 0x2c, 0xca, 0x57, 0x28, 0x2f, 0xca, 0x2c, 0x49, 0x2d, 0x56,
0x28, 0xcf, 0x2f, 0xca, 0x4e, 0xca, 0xcf, 0xcf, 0x2e, 0xd6, 0x53, 0x70, 0x1b, 0x95, 0xc1,
0x23, 0x03, 0x00,
];
const XML_DYNAMIC: &[u8] = &[
0x75, 0xd0, 0xd1, 0x0a, 0xc2, 0x20, 0x14, 0x06, 0xe0, 0x57, 0x19, 0xde, 0xd7, 0x99, 0x2e,
0x22, 0xc2, 0x09, 0x1b, 0xbd, 0x88, 0x98, 0xcb, 0x68, 0x4e, 0x51, 0xd9, 0x7a, 0xfc, 0xce,
0x24, 0x64, 0x2c, 0xba, 0xf3, 0xfc, 0xff, 0xf1, 0x03, 0xe5, 0x8b, 0x0b, 0xaf, 0x68, 0xb4,
0x4e, 0xd5, 0xdb, 0x8e, 0x53, 0x6c, 0x89, 0x49, 0xc9, 0x5f, 0x01, 0xa2, 0x32, 0xda, 0xca,
0x78, 0x74, 0x5e, 0x4f, 0xd8, 0x0c, 0x2e, 0x58, 0x99, 0x70, 0x0c, 0x0f, 0x88, 0x3e, 0x68,
0x79, 0xcf, 0x97, 0xec, 0x08, 0xac, 0xae, 0xcf, 0x60, 0xe5, 0x73, 0x22, 0x82, 0xe7, 0xec,
0x26, 0x93, 0x14, 0x3c, 0xb8, 0xa5, 0x0a, 0x2d, 0xa1, 0x98, 0xaa, 0xf5, 0xd0, 0x51, 0x52,
0xa5, 0x96, 0x44, 0x9c, 0x67, 0x51, 0x73, 0x98, 0x05, 0x07, 0xf5, 0xed, 0x7a, 0x9a, 0x53,
0x8a, 0x54, 0x29, 0x00, 0x81, 0xa2, 0xb0, 0xa2, 0xb0, 0x8d, 0x42, 0x77, 0x0a, 0xcb, 0xe9,
0xe5, 0x1f, 0xd2, 0x14, 0xa4, 0xd9, 0x20, 0x6c, 0x87, 0xac, 0x5b, 0x83, 0xe8, 0xe9, 0xa1,
0xc7, 0x66, 0x58, 0x37, 0x4e, 0x3f, 0x20, 0x6c, 0xde, 0x09, 0xe5, 0x03, 0xc5, 0x07,
];
const XML: &str = "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><sheetData><row r=\"1\"><c r=\"A1\" t=\"s\"><v>0</v></c><c r=\"B1\"><v>1200</v></c></row><row r=\"2\"><c r=\"A2\" t=\"s\"><v>1</v></c><c r=\"B2\"><v>800</v></c></row><row r=\"3\"><c r=\"A3\" t=\"s\"><v>2</v></c><c r=\"B3\"><f>B1-B2</f><v>400</v></c></row></sheetData></worksheet>";
#[test]
fn each_block_kind_decodes() {
assert_eq!(inflate(ABC_FIXED, 3, 1 << 20).unwrap(), b"abc");
assert_eq!(inflate(ABC_STORED, 3, 1 << 20).unwrap(), b"abc");
let rep = "Frazaro writes workbooks. ".repeat(12);
assert_eq!(inflate(REP_FIXED, 312, 1 << 20).unwrap(), rep.as_bytes());
assert_eq!(inflate(XML_DYNAMIC, 332, 1 << 20).unwrap(), XML.as_bytes());
assert_eq!(XML.len(), 332);
}
#[test]
fn what_is_wrong_is_named_and_nothing_panics() {
assert_eq!(
inflate(&ABC_FIXED[..3], 3, 1 << 20),
Err("the data ended early")
);
assert_eq!(inflate(&[], 0, 1 << 20), Err("the data ended early"));
assert_eq!(inflate(&[0x07], 0, 1 << 20), Err("an invalid block type"));
assert_eq!(
inflate(
&[0x01, 0x03, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63],
3,
1 << 20
),
Err("a stored block whose length check failed")
);
assert_eq!(
inflate(REP_FIXED, 312, 100),
Err("longer than the limit allows")
);
assert_eq!(
inflate(ABC_STORED, 3, 2),
Err("longer than the limit allows")
);
assert_eq!(
inflate(&[0x03, 0x02], 0, 1 << 20),
Err("a reference before the start of the output")
);
for seed in 0u32..64 {
let bytes: Vec<u8> = (0..32)
.map(|i| (seed.wrapping_mul(2654435761).wrapping_add(i * 40503) >> 13) as u8)
.collect();
let _ = inflate(&bytes, 0, 1 << 16);
}
}
}