use crate::error::{Error, Result};
#[derive(Clone, Copy)]
struct HuffmanSym {
bits: u8,
code: u32,
}
static HUFFMAN_TABLE: [HuffmanSym; 257] = [
HuffmanSym {
bits: 13,
code: 0xffc0_0000,
}, HuffmanSym {
bits: 23,
code: 0xffff_b000,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe20,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe30,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe40,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe50,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe60,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe70,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe80,
}, HuffmanSym {
bits: 24,
code: 0xffff_ea00,
}, HuffmanSym {
bits: 30,
code: 0xffff_fff0,
}, HuffmanSym {
bits: 28,
code: 0xffff_fe90,
}, HuffmanSym {
bits: 28,
code: 0xffff_fea0,
}, HuffmanSym {
bits: 30,
code: 0xffff_fff4,
}, HuffmanSym {
bits: 28,
code: 0xffff_feb0,
}, HuffmanSym {
bits: 28,
code: 0xffff_fec0,
}, HuffmanSym {
bits: 28,
code: 0xffff_fed0,
}, HuffmanSym {
bits: 28,
code: 0xffff_fee0,
}, HuffmanSym {
bits: 28,
code: 0xffff_fef0,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff00,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff10,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff20,
}, HuffmanSym {
bits: 30,
code: 0xffff_fff8,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff30,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff40,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff50,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff60,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff70,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff80,
}, HuffmanSym {
bits: 28,
code: 0xffff_ff90,
}, HuffmanSym {
bits: 28,
code: 0xffff_ffa0,
}, HuffmanSym {
bits: 28,
code: 0xffff_ffb0,
}, HuffmanSym {
bits: 6,
code: 0x5000_0000,
}, HuffmanSym {
bits: 10,
code: 0xfe00_0000,
}, HuffmanSym {
bits: 10,
code: 0xfe40_0000,
}, HuffmanSym {
bits: 12,
code: 0xffa0_0000,
}, HuffmanSym {
bits: 13,
code: 0xffc8_0000,
}, HuffmanSym {
bits: 6,
code: 0x5400_0000,
}, HuffmanSym {
bits: 8,
code: 0xf800_0000,
}, HuffmanSym {
bits: 11,
code: 0xff40_0000,
}, HuffmanSym {
bits: 10,
code: 0xfe80_0000,
}, HuffmanSym {
bits: 10,
code: 0xfec0_0000,
}, HuffmanSym {
bits: 8,
code: 0xf900_0000,
}, HuffmanSym {
bits: 11,
code: 0xff60_0000,
}, HuffmanSym {
bits: 8,
code: 0xfa00_0000,
}, HuffmanSym {
bits: 6,
code: 0x5800_0000,
}, HuffmanSym {
bits: 6,
code: 0x5c00_0000,
}, HuffmanSym {
bits: 6,
code: 0x6000_0000,
}, HuffmanSym {
bits: 5,
code: 0x0000_0000,
}, HuffmanSym {
bits: 5,
code: 0x0800_0000,
}, HuffmanSym {
bits: 5,
code: 0x1000_0000,
}, HuffmanSym {
bits: 6,
code: 0x6400_0000,
}, HuffmanSym {
bits: 6,
code: 0x6800_0000,
}, HuffmanSym {
bits: 6,
code: 0x6c00_0000,
}, HuffmanSym {
bits: 6,
code: 0x7000_0000,
}, HuffmanSym {
bits: 6,
code: 0x7400_0000,
}, HuffmanSym {
bits: 6,
code: 0x7800_0000,
}, HuffmanSym {
bits: 6,
code: 0x7c00_0000,
}, HuffmanSym {
bits: 7,
code: 0xb800_0000,
}, HuffmanSym {
bits: 8,
code: 0xfb00_0000,
}, HuffmanSym {
bits: 15,
code: 0xfff8_0000,
}, HuffmanSym {
bits: 6,
code: 0x8000_0000,
}, HuffmanSym {
bits: 12,
code: 0xffb0_0000,
}, HuffmanSym {
bits: 10,
code: 0xff00_0000,
}, HuffmanSym {
bits: 13,
code: 0xffd0_0000,
}, HuffmanSym {
bits: 6,
code: 0x8400_0000,
}, HuffmanSym {
bits: 7,
code: 0xba00_0000,
}, HuffmanSym {
bits: 7,
code: 0xbc00_0000,
}, HuffmanSym {
bits: 7,
code: 0xbe00_0000,
}, HuffmanSym {
bits: 7,
code: 0xc000_0000,
}, HuffmanSym {
bits: 7,
code: 0xc200_0000,
}, HuffmanSym {
bits: 7,
code: 0xc400_0000,
}, HuffmanSym {
bits: 7,
code: 0xc600_0000,
}, HuffmanSym {
bits: 7,
code: 0xc800_0000,
}, HuffmanSym {
bits: 7,
code: 0xca00_0000,
}, HuffmanSym {
bits: 7,
code: 0xcc00_0000,
}, HuffmanSym {
bits: 7,
code: 0xce00_0000,
}, HuffmanSym {
bits: 7,
code: 0xd000_0000,
}, HuffmanSym {
bits: 7,
code: 0xd200_0000,
}, HuffmanSym {
bits: 7,
code: 0xd400_0000,
}, HuffmanSym {
bits: 7,
code: 0xd600_0000,
}, HuffmanSym {
bits: 7,
code: 0xd800_0000,
}, HuffmanSym {
bits: 7,
code: 0xda00_0000,
}, HuffmanSym {
bits: 7,
code: 0xdc00_0000,
}, HuffmanSym {
bits: 7,
code: 0xde00_0000,
}, HuffmanSym {
bits: 7,
code: 0xe000_0000,
}, HuffmanSym {
bits: 7,
code: 0xe200_0000,
}, HuffmanSym {
bits: 7,
code: 0xe400_0000,
}, HuffmanSym {
bits: 8,
code: 0xfc00_0000,
}, HuffmanSym {
bits: 7,
code: 0xe600_0000,
}, HuffmanSym {
bits: 8,
code: 0xfd00_0000,
}, HuffmanSym {
bits: 13,
code: 0xffd8_0000,
}, HuffmanSym {
bits: 19,
code: 0xfffe_0000,
}, HuffmanSym {
bits: 13,
code: 0xffe0_0000,
}, HuffmanSym {
bits: 14,
code: 0xfff0_0000,
}, HuffmanSym {
bits: 6,
code: 0x8800_0000,
}, HuffmanSym {
bits: 15,
code: 0xfffa_0000,
}, HuffmanSym {
bits: 5,
code: 0x1800_0000,
}, HuffmanSym {
bits: 6,
code: 0x8c00_0000,
}, HuffmanSym {
bits: 5,
code: 0x2000_0000,
}, HuffmanSym {
bits: 6,
code: 0x9000_0000,
}, HuffmanSym {
bits: 5,
code: 0x2800_0000,
}, HuffmanSym {
bits: 6,
code: 0x9400_0000,
}, HuffmanSym {
bits: 6,
code: 0x9800_0000,
}, HuffmanSym {
bits: 6,
code: 0x9c00_0000,
}, HuffmanSym {
bits: 5,
code: 0x3000_0000,
}, HuffmanSym {
bits: 7,
code: 0xe800_0000,
}, HuffmanSym {
bits: 7,
code: 0xea00_0000,
}, HuffmanSym {
bits: 6,
code: 0xa000_0000,
}, HuffmanSym {
bits: 6,
code: 0xa400_0000,
}, HuffmanSym {
bits: 6,
code: 0xa800_0000,
}, HuffmanSym {
bits: 5,
code: 0x3800_0000,
}, HuffmanSym {
bits: 6,
code: 0xac00_0000,
}, HuffmanSym {
bits: 7,
code: 0xec00_0000,
}, HuffmanSym {
bits: 6,
code: 0xb000_0000,
}, HuffmanSym {
bits: 5,
code: 0x4000_0000,
}, HuffmanSym {
bits: 5,
code: 0x4800_0000,
}, HuffmanSym {
bits: 6,
code: 0xb400_0000,
}, HuffmanSym {
bits: 7,
code: 0xee00_0000,
}, HuffmanSym {
bits: 7,
code: 0xf000_0000,
}, HuffmanSym {
bits: 7,
code: 0xf200_0000,
}, HuffmanSym {
bits: 7,
code: 0xf400_0000,
}, HuffmanSym {
bits: 7,
code: 0xf600_0000,
}, HuffmanSym {
bits: 15,
code: 0xfffc_0000,
}, HuffmanSym {
bits: 11,
code: 0xff80_0000,
}, HuffmanSym {
bits: 14,
code: 0xfff4_0000,
}, HuffmanSym {
bits: 13,
code: 0xffe8_0000,
}, HuffmanSym {
bits: 28,
code: 0xffff_ffc0,
}, HuffmanSym {
bits: 20,
code: 0xfffe_6000,
}, HuffmanSym {
bits: 22,
code: 0xffff_4800,
}, HuffmanSym {
bits: 20,
code: 0xfffe_7000,
}, HuffmanSym {
bits: 20,
code: 0xfffe_8000,
}, HuffmanSym {
bits: 22,
code: 0xffff_4c00,
}, HuffmanSym {
bits: 22,
code: 0xffff_5000,
}, HuffmanSym {
bits: 22,
code: 0xffff_5400,
}, HuffmanSym {
bits: 23,
code: 0xffff_b200,
}, HuffmanSym {
bits: 22,
code: 0xffff_5800,
}, HuffmanSym {
bits: 23,
code: 0xffff_b400,
}, HuffmanSym {
bits: 23,
code: 0xffff_b600,
}, HuffmanSym {
bits: 23,
code: 0xffff_b800,
}, HuffmanSym {
bits: 23,
code: 0xffff_ba00,
}, HuffmanSym {
bits: 23,
code: 0xffff_bc00,
}, HuffmanSym {
bits: 24,
code: 0xffff_eb00,
}, HuffmanSym {
bits: 23,
code: 0xffff_be00,
}, HuffmanSym {
bits: 24,
code: 0xffff_ec00,
}, HuffmanSym {
bits: 24,
code: 0xffff_ed00,
}, HuffmanSym {
bits: 22,
code: 0xffff_5c00,
}, HuffmanSym {
bits: 23,
code: 0xffff_c000,
}, HuffmanSym {
bits: 24,
code: 0xffff_ee00,
}, HuffmanSym {
bits: 23,
code: 0xffff_c200,
}, HuffmanSym {
bits: 23,
code: 0xffff_c400,
}, HuffmanSym {
bits: 23,
code: 0xffff_c600,
}, HuffmanSym {
bits: 23,
code: 0xffff_c800,
}, HuffmanSym {
bits: 21,
code: 0xfffe_e000,
}, HuffmanSym {
bits: 22,
code: 0xffff_6000,
}, HuffmanSym {
bits: 23,
code: 0xffff_ca00,
}, HuffmanSym {
bits: 22,
code: 0xffff_6400,
}, HuffmanSym {
bits: 23,
code: 0xffff_cc00,
}, HuffmanSym {
bits: 23,
code: 0xffff_ce00,
}, HuffmanSym {
bits: 24,
code: 0xffff_ef00,
}, HuffmanSym {
bits: 22,
code: 0xffff_6800,
}, HuffmanSym {
bits: 21,
code: 0xfffe_e800,
}, HuffmanSym {
bits: 20,
code: 0xfffe_9000,
}, HuffmanSym {
bits: 22,
code: 0xffff_6c00,
}, HuffmanSym {
bits: 22,
code: 0xffff_7000,
}, HuffmanSym {
bits: 23,
code: 0xffff_d000,
}, HuffmanSym {
bits: 23,
code: 0xffff_d200,
}, HuffmanSym {
bits: 21,
code: 0xfffe_f000,
}, HuffmanSym {
bits: 23,
code: 0xffff_d400,
}, HuffmanSym {
bits: 22,
code: 0xffff_7400,
}, HuffmanSym {
bits: 22,
code: 0xffff_7800,
}, HuffmanSym {
bits: 24,
code: 0xffff_f000,
}, HuffmanSym {
bits: 21,
code: 0xfffe_f800,
}, HuffmanSym {
bits: 22,
code: 0xffff_7c00,
}, HuffmanSym {
bits: 23,
code: 0xffff_d600,
}, HuffmanSym {
bits: 23,
code: 0xffff_d800,
}, HuffmanSym {
bits: 21,
code: 0xffff_0000,
}, HuffmanSym {
bits: 21,
code: 0xffff_0800,
}, HuffmanSym {
bits: 22,
code: 0xffff_8000,
}, HuffmanSym {
bits: 21,
code: 0xffff_1000,
}, HuffmanSym {
bits: 23,
code: 0xffff_da00,
}, HuffmanSym {
bits: 22,
code: 0xffff_8400,
}, HuffmanSym {
bits: 23,
code: 0xffff_dc00,
}, HuffmanSym {
bits: 23,
code: 0xffff_de00,
}, HuffmanSym {
bits: 20,
code: 0xfffe_a000,
}, HuffmanSym {
bits: 22,
code: 0xffff_8800,
}, HuffmanSym {
bits: 22,
code: 0xffff_8c00,
}, HuffmanSym {
bits: 22,
code: 0xffff_9000,
}, HuffmanSym {
bits: 23,
code: 0xffff_e000,
}, HuffmanSym {
bits: 22,
code: 0xffff_9400,
}, HuffmanSym {
bits: 22,
code: 0xffff_9800,
}, HuffmanSym {
bits: 23,
code: 0xffff_e200,
}, HuffmanSym {
bits: 26,
code: 0xffff_f800,
}, HuffmanSym {
bits: 26,
code: 0xffff_f840,
}, HuffmanSym {
bits: 20,
code: 0xfffe_b000,
}, HuffmanSym {
bits: 19,
code: 0xfffe_2000,
}, HuffmanSym {
bits: 22,
code: 0xffff_9c00,
}, HuffmanSym {
bits: 23,
code: 0xffff_e400,
}, HuffmanSym {
bits: 22,
code: 0xffff_a000,
}, HuffmanSym {
bits: 25,
code: 0xffff_f600,
}, HuffmanSym {
bits: 26,
code: 0xffff_f880,
}, HuffmanSym {
bits: 26,
code: 0xffff_f8c0,
}, HuffmanSym {
bits: 26,
code: 0xffff_f900,
}, HuffmanSym {
bits: 27,
code: 0xffff_fbc0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fbe0,
}, HuffmanSym {
bits: 26,
code: 0xffff_f940,
}, HuffmanSym {
bits: 24,
code: 0xffff_f100,
}, HuffmanSym {
bits: 25,
code: 0xffff_f680,
}, HuffmanSym {
bits: 19,
code: 0xfffe_4000,
}, HuffmanSym {
bits: 21,
code: 0xffff_1800,
}, HuffmanSym {
bits: 26,
code: 0xffff_f980,
}, HuffmanSym {
bits: 27,
code: 0xffff_fc00,
}, HuffmanSym {
bits: 27,
code: 0xffff_fc20,
}, HuffmanSym {
bits: 26,
code: 0xffff_f9c0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fc40,
}, HuffmanSym {
bits: 24,
code: 0xffff_f200,
}, HuffmanSym {
bits: 21,
code: 0xffff_2000,
}, HuffmanSym {
bits: 21,
code: 0xffff_2800,
}, HuffmanSym {
bits: 26,
code: 0xffff_fa00,
}, HuffmanSym {
bits: 26,
code: 0xffff_fa40,
}, HuffmanSym {
bits: 28,
code: 0xffff_ffd0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fc60,
}, HuffmanSym {
bits: 27,
code: 0xffff_fc80,
}, HuffmanSym {
bits: 27,
code: 0xffff_fca0,
}, HuffmanSym {
bits: 20,
code: 0xfffe_c000,
}, HuffmanSym {
bits: 24,
code: 0xffff_f300,
}, HuffmanSym {
bits: 20,
code: 0xfffe_d000,
}, HuffmanSym {
bits: 21,
code: 0xffff_3000,
}, HuffmanSym {
bits: 22,
code: 0xffff_a400,
}, HuffmanSym {
bits: 21,
code: 0xffff_3800,
}, HuffmanSym {
bits: 21,
code: 0xffff_4000,
}, HuffmanSym {
bits: 23,
code: 0xffff_e600,
}, HuffmanSym {
bits: 22,
code: 0xffff_a800,
}, HuffmanSym {
bits: 22,
code: 0xffff_ac00,
}, HuffmanSym {
bits: 25,
code: 0xffff_f700,
}, HuffmanSym {
bits: 25,
code: 0xffff_f780,
}, HuffmanSym {
bits: 24,
code: 0xffff_f400,
}, HuffmanSym {
bits: 24,
code: 0xffff_f500,
}, HuffmanSym {
bits: 26,
code: 0xffff_fa80,
}, HuffmanSym {
bits: 23,
code: 0xffff_e800,
}, HuffmanSym {
bits: 26,
code: 0xffff_fac0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fcc0,
}, HuffmanSym {
bits: 26,
code: 0xffff_fb00,
}, HuffmanSym {
bits: 26,
code: 0xffff_fb40,
}, HuffmanSym {
bits: 27,
code: 0xffff_fce0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fd00,
}, HuffmanSym {
bits: 27,
code: 0xffff_fd20,
}, HuffmanSym {
bits: 27,
code: 0xffff_fd40,
}, HuffmanSym {
bits: 27,
code: 0xffff_fd60,
}, HuffmanSym {
bits: 28,
code: 0xffff_ffe0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fd80,
}, HuffmanSym {
bits: 27,
code: 0xffff_fda0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fdc0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fde0,
}, HuffmanSym {
bits: 27,
code: 0xffff_fe00,
}, HuffmanSym {
bits: 26,
code: 0xffff_fb80,
}, HuffmanSym {
bits: 30,
code: 0xffff_fffc,
}, ];
#[must_use]
pub fn encoded_len(data: &[u8]) -> usize {
let bits: usize = data
.iter()
.map(|&b| HUFFMAN_TABLE[b as usize].bits as usize)
.sum();
bits.div_ceil(8)
}
pub fn encode(buf: &mut [u8], data: &[u8]) -> Result<usize> {
let required = encoded_len(data);
if buf.len() < required {
return Err(Error::buffer_too_short());
}
let mut acc: u64 = 0;
let mut acc_bits: u32 = 0;
let mut offset = 0;
for &byte in data {
let sym = &HUFFMAN_TABLE[byte as usize];
let code_64 = (sym.code as u64) << 32;
acc |= code_64 >> acc_bits;
acc_bits += u32::from(sym.bits);
while acc_bits >= 8 {
buf[offset] = (acc >> 56) as u8;
offset += 1;
acc <<= 8;
acc_bits -= 8;
}
}
if acc_bits > 0 {
let padding_bits = 8 - acc_bits;
let padding_mask = (1u64 << padding_bits) - 1;
let byte = ((acc >> 56) as u8) | (padding_mask as u8);
buf[offset] = byte;
offset += 1;
}
Ok(offset)
}
#[must_use]
pub fn encode_to_vec(data: &[u8]) -> Vec<u8> {
let len = encoded_len(data);
let mut buf = vec![0u8; len];
let _ = encode(&mut buf, data);
buf
}
pub fn decode(data: &[u8]) -> Result<Vec<u8>> {
let mut result = Vec::with_capacity(data.len() * 2);
let mut acc: u64 = 0;
let mut acc_bits: u32 = 0;
for &byte in data {
acc = (acc << 8) | (byte as u64);
acc_bits += 8;
'decode: while acc_bits >= 5 {
let current = if acc_bits >= 32 {
(acc >> (acc_bits - 32)) as u32
} else {
(acc << (32 - acc_bits)) as u32
};
for (sym_idx, sym) in HUFFMAN_TABLE.iter().enumerate() {
if u32::from(sym.bits) <= acc_bits {
let mask = if sym.bits >= 32 {
0xffff_ffff_u32
} else {
!((1u32 << (32 - sym.bits)) - 1)
};
if (current & mask) == sym.code {
if sym_idx == 256 {
return Err(Error::hpack_error(
"EOS symbol in Huffman-encoded string literal is not allowed",
));
}
result.push(sym_idx as u8);
acc_bits -= u32::from(sym.bits);
if acc_bits > 0 {
acc &= (1u64 << acc_bits) - 1;
} else {
acc = 0;
}
continue 'decode;
}
}
}
break;
}
}
if acc_bits > 0 && acc_bits <= 7 {
let mask = (1u64 << acc_bits) - 1;
if (acc & mask) == mask {
return Ok(result);
}
return Err(Error::hpack_error("invalid Huffman padding"));
}
if acc_bits > 7 {
return Err(Error::hpack_error("incomplete Huffman data"));
}
Ok(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_encode_decode_simple() {
let input = b"www.example.com";
let encoded_length = encoded_len(input);
let mut buf = vec![0u8; encoded_length];
let len = encode(&mut buf, input).unwrap();
assert_eq!(len, encoded_length);
let decoded = decode(&buf).unwrap();
assert_eq!(decoded, input);
}
#[test]
fn test_encode_decode_method() {
let input = b"GET";
let mut buf = vec![0u8; encoded_len(input)];
encode(&mut buf, input).unwrap();
let decoded = decode(&buf).unwrap();
assert_eq!(decoded, input);
}
#[test]
fn test_encode_decode_path() {
let input = b"/index.html";
let mut buf = vec![0u8; encoded_len(input)];
encode(&mut buf, input).unwrap();
let decoded = decode(&buf).unwrap();
assert_eq!(decoded, input);
}
#[test]
fn test_encoded_len() {
assert_eq!(encoded_len(b"www.example.com"), 12);
}
#[test]
fn test_encode_buffer_too_short() {
let input = b"test";
let mut buf = [0u8; 1];
assert!(encode(&mut buf, input).is_err());
}
}