use crate::error::QpackError;
#[derive(Clone, Copy)]
struct HuffmanSym {
bits: u8,
code: u32,
}
static HUFFMAN_TABLE: [HuffmanSym; 257] = [
HuffmanSym {
bits: 13,
code: 0xffc00000,
}, HuffmanSym {
bits: 23,
code: 0xffffb000,
}, HuffmanSym {
bits: 28,
code: 0xfffffe20,
}, HuffmanSym {
bits: 28,
code: 0xfffffe30,
}, HuffmanSym {
bits: 28,
code: 0xfffffe40,
}, HuffmanSym {
bits: 28,
code: 0xfffffe50,
}, HuffmanSym {
bits: 28,
code: 0xfffffe60,
}, HuffmanSym {
bits: 28,
code: 0xfffffe70,
}, HuffmanSym {
bits: 28,
code: 0xfffffe80,
}, HuffmanSym {
bits: 24,
code: 0xffffea00,
}, HuffmanSym {
bits: 30,
code: 0xfffffff0,
}, HuffmanSym {
bits: 28,
code: 0xfffffe90,
}, HuffmanSym {
bits: 28,
code: 0xfffffea0,
}, HuffmanSym {
bits: 30,
code: 0xfffffff4,
}, HuffmanSym {
bits: 28,
code: 0xfffffeb0,
}, HuffmanSym {
bits: 28,
code: 0xfffffec0,
}, HuffmanSym {
bits: 28,
code: 0xfffffed0,
}, HuffmanSym {
bits: 28,
code: 0xfffffee0,
}, HuffmanSym {
bits: 28,
code: 0xfffffef0,
}, HuffmanSym {
bits: 28,
code: 0xffffff00,
}, HuffmanSym {
bits: 28,
code: 0xffffff10,
}, HuffmanSym {
bits: 28,
code: 0xffffff20,
}, HuffmanSym {
bits: 30,
code: 0xfffffff8,
}, HuffmanSym {
bits: 28,
code: 0xffffff30,
}, HuffmanSym {
bits: 28,
code: 0xffffff40,
}, HuffmanSym {
bits: 28,
code: 0xffffff50,
}, HuffmanSym {
bits: 28,
code: 0xffffff60,
}, HuffmanSym {
bits: 28,
code: 0xffffff70,
}, HuffmanSym {
bits: 28,
code: 0xffffff80,
}, HuffmanSym {
bits: 28,
code: 0xffffff90,
}, HuffmanSym {
bits: 28,
code: 0xffffffa0,
}, HuffmanSym {
bits: 28,
code: 0xffffffb0,
}, HuffmanSym {
bits: 6,
code: 0x50000000,
}, HuffmanSym {
bits: 10,
code: 0xfe000000,
}, HuffmanSym {
bits: 10,
code: 0xfe400000,
}, HuffmanSym {
bits: 12,
code: 0xffa00000,
}, HuffmanSym {
bits: 13,
code: 0xffc80000,
}, HuffmanSym {
bits: 6,
code: 0x54000000,
}, HuffmanSym {
bits: 8,
code: 0xf8000000,
}, HuffmanSym {
bits: 11,
code: 0xff400000,
}, HuffmanSym {
bits: 10,
code: 0xfe800000,
}, HuffmanSym {
bits: 10,
code: 0xfec00000,
}, HuffmanSym {
bits: 8,
code: 0xf9000000,
}, HuffmanSym {
bits: 11,
code: 0xff600000,
}, HuffmanSym {
bits: 8,
code: 0xfa000000,
}, HuffmanSym {
bits: 6,
code: 0x58000000,
}, HuffmanSym {
bits: 6,
code: 0x5c000000,
}, HuffmanSym {
bits: 6,
code: 0x60000000,
}, HuffmanSym {
bits: 5,
code: 0x00000000,
}, HuffmanSym {
bits: 5,
code: 0x08000000,
}, HuffmanSym {
bits: 5,
code: 0x10000000,
}, HuffmanSym {
bits: 6,
code: 0x64000000,
}, HuffmanSym {
bits: 6,
code: 0x68000000,
}, HuffmanSym {
bits: 6,
code: 0x6c000000,
}, HuffmanSym {
bits: 6,
code: 0x70000000,
}, HuffmanSym {
bits: 6,
code: 0x74000000,
}, HuffmanSym {
bits: 6,
code: 0x78000000,
}, HuffmanSym {
bits: 6,
code: 0x7c000000,
}, HuffmanSym {
bits: 7,
code: 0xb8000000,
}, HuffmanSym {
bits: 8,
code: 0xfb000000,
}, HuffmanSym {
bits: 15,
code: 0xfff80000,
}, HuffmanSym {
bits: 6,
code: 0x80000000,
}, HuffmanSym {
bits: 12,
code: 0xffb00000,
}, HuffmanSym {
bits: 10,
code: 0xff000000,
}, HuffmanSym {
bits: 13,
code: 0xffd00000,
}, HuffmanSym {
bits: 6,
code: 0x84000000,
}, HuffmanSym {
bits: 7,
code: 0xba000000,
}, HuffmanSym {
bits: 7,
code: 0xbc000000,
}, HuffmanSym {
bits: 7,
code: 0xbe000000,
}, HuffmanSym {
bits: 7,
code: 0xc0000000,
}, HuffmanSym {
bits: 7,
code: 0xc2000000,
}, HuffmanSym {
bits: 7,
code: 0xc4000000,
}, HuffmanSym {
bits: 7,
code: 0xc6000000,
}, HuffmanSym {
bits: 7,
code: 0xc8000000,
}, HuffmanSym {
bits: 7,
code: 0xca000000,
}, HuffmanSym {
bits: 7,
code: 0xcc000000,
}, HuffmanSym {
bits: 7,
code: 0xce000000,
}, HuffmanSym {
bits: 7,
code: 0xd0000000,
}, HuffmanSym {
bits: 7,
code: 0xd2000000,
}, HuffmanSym {
bits: 7,
code: 0xd4000000,
}, HuffmanSym {
bits: 7,
code: 0xd6000000,
}, HuffmanSym {
bits: 7,
code: 0xd8000000,
}, HuffmanSym {
bits: 7,
code: 0xda000000,
}, HuffmanSym {
bits: 7,
code: 0xdc000000,
}, HuffmanSym {
bits: 7,
code: 0xde000000,
}, HuffmanSym {
bits: 7,
code: 0xe0000000,
}, HuffmanSym {
bits: 7,
code: 0xe2000000,
}, HuffmanSym {
bits: 7,
code: 0xe4000000,
}, HuffmanSym {
bits: 8,
code: 0xfc000000,
}, HuffmanSym {
bits: 7,
code: 0xe6000000,
}, HuffmanSym {
bits: 8,
code: 0xfd000000,
}, HuffmanSym {
bits: 13,
code: 0xffd80000,
}, HuffmanSym {
bits: 19,
code: 0xfffe0000,
}, HuffmanSym {
bits: 13,
code: 0xffe00000,
}, HuffmanSym {
bits: 14,
code: 0xfff00000,
}, HuffmanSym {
bits: 6,
code: 0x88000000,
}, HuffmanSym {
bits: 15,
code: 0xfffa0000,
}, HuffmanSym {
bits: 5,
code: 0x18000000,
}, HuffmanSym {
bits: 6,
code: 0x8c000000,
}, HuffmanSym {
bits: 5,
code: 0x20000000,
}, HuffmanSym {
bits: 6,
code: 0x90000000,
}, HuffmanSym {
bits: 5,
code: 0x28000000,
}, HuffmanSym {
bits: 6,
code: 0x94000000,
}, HuffmanSym {
bits: 6,
code: 0x98000000,
}, HuffmanSym {
bits: 6,
code: 0x9c000000,
}, HuffmanSym {
bits: 5,
code: 0x30000000,
}, HuffmanSym {
bits: 7,
code: 0xe8000000,
}, HuffmanSym {
bits: 7,
code: 0xea000000,
}, HuffmanSym {
bits: 6,
code: 0xa0000000,
}, HuffmanSym {
bits: 6,
code: 0xa4000000,
}, HuffmanSym {
bits: 6,
code: 0xa8000000,
}, HuffmanSym {
bits: 5,
code: 0x38000000,
}, HuffmanSym {
bits: 6,
code: 0xac000000,
}, HuffmanSym {
bits: 7,
code: 0xec000000,
}, HuffmanSym {
bits: 6,
code: 0xb0000000,
}, HuffmanSym {
bits: 5,
code: 0x40000000,
}, HuffmanSym {
bits: 5,
code: 0x48000000,
}, HuffmanSym {
bits: 6,
code: 0xb4000000,
}, HuffmanSym {
bits: 7,
code: 0xee000000,
}, HuffmanSym {
bits: 7,
code: 0xf0000000,
}, HuffmanSym {
bits: 7,
code: 0xf2000000,
}, HuffmanSym {
bits: 7,
code: 0xf4000000,
}, HuffmanSym {
bits: 7,
code: 0xf6000000,
}, HuffmanSym {
bits: 15,
code: 0xfffc0000,
}, HuffmanSym {
bits: 11,
code: 0xff800000,
}, HuffmanSym {
bits: 14,
code: 0xfff40000,
}, HuffmanSym {
bits: 13,
code: 0xffe80000,
}, HuffmanSym {
bits: 28,
code: 0xffffffc0,
}, HuffmanSym {
bits: 20,
code: 0xfffe6000,
}, HuffmanSym {
bits: 22,
code: 0xffff4800,
}, HuffmanSym {
bits: 20,
code: 0xfffe7000,
}, HuffmanSym {
bits: 20,
code: 0xfffe8000,
}, HuffmanSym {
bits: 22,
code: 0xffff4c00,
}, HuffmanSym {
bits: 22,
code: 0xffff5000,
}, HuffmanSym {
bits: 22,
code: 0xffff5400,
}, HuffmanSym {
bits: 23,
code: 0xffffb200,
}, HuffmanSym {
bits: 22,
code: 0xffff5800,
}, HuffmanSym {
bits: 23,
code: 0xffffb400,
}, HuffmanSym {
bits: 23,
code: 0xffffb600,
}, HuffmanSym {
bits: 23,
code: 0xffffb800,
}, HuffmanSym {
bits: 23,
code: 0xffffba00,
}, HuffmanSym {
bits: 23,
code: 0xffffbc00,
}, HuffmanSym {
bits: 24,
code: 0xffffeb00,
}, HuffmanSym {
bits: 23,
code: 0xffffbe00,
}, HuffmanSym {
bits: 24,
code: 0xffffec00,
}, HuffmanSym {
bits: 24,
code: 0xffffed00,
}, HuffmanSym {
bits: 22,
code: 0xffff5c00,
}, HuffmanSym {
bits: 23,
code: 0xffffc000,
}, HuffmanSym {
bits: 24,
code: 0xffffee00,
}, HuffmanSym {
bits: 23,
code: 0xffffc200,
}, HuffmanSym {
bits: 23,
code: 0xffffc400,
}, HuffmanSym {
bits: 23,
code: 0xffffc600,
}, HuffmanSym {
bits: 23,
code: 0xffffc800,
}, HuffmanSym {
bits: 21,
code: 0xfffee000,
}, HuffmanSym {
bits: 22,
code: 0xffff6000,
}, HuffmanSym {
bits: 23,
code: 0xffffca00,
}, HuffmanSym {
bits: 22,
code: 0xffff6400,
}, HuffmanSym {
bits: 23,
code: 0xffffcc00,
}, HuffmanSym {
bits: 23,
code: 0xffffce00,
}, HuffmanSym {
bits: 24,
code: 0xffffef00,
}, HuffmanSym {
bits: 22,
code: 0xffff6800,
}, HuffmanSym {
bits: 21,
code: 0xfffee800,
}, HuffmanSym {
bits: 20,
code: 0xfffe9000,
}, HuffmanSym {
bits: 22,
code: 0xffff6c00,
}, HuffmanSym {
bits: 22,
code: 0xffff7000,
}, HuffmanSym {
bits: 23,
code: 0xffffd000,
}, HuffmanSym {
bits: 23,
code: 0xffffd200,
}, HuffmanSym {
bits: 21,
code: 0xfffef000,
}, HuffmanSym {
bits: 23,
code: 0xffffd400,
}, HuffmanSym {
bits: 22,
code: 0xffff7400,
}, HuffmanSym {
bits: 22,
code: 0xffff7800,
}, HuffmanSym {
bits: 24,
code: 0xfffff000,
}, HuffmanSym {
bits: 21,
code: 0xfffef800,
}, HuffmanSym {
bits: 22,
code: 0xffff7c00,
}, HuffmanSym {
bits: 23,
code: 0xffffd600,
}, HuffmanSym {
bits: 23,
code: 0xffffd800,
}, HuffmanSym {
bits: 21,
code: 0xffff0000,
}, HuffmanSym {
bits: 21,
code: 0xffff0800,
}, HuffmanSym {
bits: 22,
code: 0xffff8000,
}, HuffmanSym {
bits: 21,
code: 0xffff1000,
}, HuffmanSym {
bits: 23,
code: 0xffffda00,
}, HuffmanSym {
bits: 22,
code: 0xffff8400,
}, HuffmanSym {
bits: 23,
code: 0xffffdc00,
}, HuffmanSym {
bits: 23,
code: 0xffffde00,
}, HuffmanSym {
bits: 20,
code: 0xfffea000,
}, HuffmanSym {
bits: 22,
code: 0xffff8800,
}, HuffmanSym {
bits: 22,
code: 0xffff8c00,
}, HuffmanSym {
bits: 22,
code: 0xffff9000,
}, HuffmanSym {
bits: 23,
code: 0xffffe000,
}, HuffmanSym {
bits: 22,
code: 0xffff9400,
}, HuffmanSym {
bits: 22,
code: 0xffff9800,
}, HuffmanSym {
bits: 23,
code: 0xffffe200,
}, HuffmanSym {
bits: 26,
code: 0xfffff800,
}, HuffmanSym {
bits: 26,
code: 0xfffff840,
}, HuffmanSym {
bits: 20,
code: 0xfffeb000,
}, HuffmanSym {
bits: 19,
code: 0xfffe2000,
}, HuffmanSym {
bits: 22,
code: 0xffff9c00,
}, HuffmanSym {
bits: 23,
code: 0xffffe400,
}, HuffmanSym {
bits: 22,
code: 0xffffa000,
}, HuffmanSym {
bits: 25,
code: 0xfffff600,
}, HuffmanSym {
bits: 26,
code: 0xfffff880,
}, HuffmanSym {
bits: 26,
code: 0xfffff8c0,
}, HuffmanSym {
bits: 26,
code: 0xfffff900,
}, HuffmanSym {
bits: 27,
code: 0xfffffbc0,
}, HuffmanSym {
bits: 27,
code: 0xfffffbe0,
}, HuffmanSym {
bits: 26,
code: 0xfffff940,
}, HuffmanSym {
bits: 24,
code: 0xfffff100,
}, HuffmanSym {
bits: 25,
code: 0xfffff680,
}, HuffmanSym {
bits: 19,
code: 0xfffe4000,
}, HuffmanSym {
bits: 21,
code: 0xffff1800,
}, HuffmanSym {
bits: 26,
code: 0xfffff980,
}, HuffmanSym {
bits: 27,
code: 0xfffffc00,
}, HuffmanSym {
bits: 27,
code: 0xfffffc20,
}, HuffmanSym {
bits: 26,
code: 0xfffff9c0,
}, HuffmanSym {
bits: 27,
code: 0xfffffc40,
}, HuffmanSym {
bits: 24,
code: 0xfffff200,
}, HuffmanSym {
bits: 21,
code: 0xffff2000,
}, HuffmanSym {
bits: 21,
code: 0xffff2800,
}, HuffmanSym {
bits: 26,
code: 0xfffffa00,
}, HuffmanSym {
bits: 26,
code: 0xfffffa40,
}, HuffmanSym {
bits: 28,
code: 0xffffffd0,
}, HuffmanSym {
bits: 27,
code: 0xfffffc60,
}, HuffmanSym {
bits: 27,
code: 0xfffffc80,
}, HuffmanSym {
bits: 27,
code: 0xfffffca0,
}, HuffmanSym {
bits: 20,
code: 0xfffec000,
}, HuffmanSym {
bits: 24,
code: 0xfffff300,
}, HuffmanSym {
bits: 20,
code: 0xfffed000,
}, HuffmanSym {
bits: 21,
code: 0xffff3000,
}, HuffmanSym {
bits: 22,
code: 0xffffa400,
}, HuffmanSym {
bits: 21,
code: 0xffff3800,
}, HuffmanSym {
bits: 21,
code: 0xffff4000,
}, HuffmanSym {
bits: 23,
code: 0xffffe600,
}, HuffmanSym {
bits: 22,
code: 0xffffa800,
}, HuffmanSym {
bits: 22,
code: 0xffffac00,
}, HuffmanSym {
bits: 25,
code: 0xfffff700,
}, HuffmanSym {
bits: 25,
code: 0xfffff780,
}, HuffmanSym {
bits: 24,
code: 0xfffff400,
}, HuffmanSym {
bits: 24,
code: 0xfffff500,
}, HuffmanSym {
bits: 26,
code: 0xfffffa80,
}, HuffmanSym {
bits: 23,
code: 0xffffe800,
}, HuffmanSym {
bits: 26,
code: 0xfffffac0,
}, HuffmanSym {
bits: 27,
code: 0xfffffcc0,
}, HuffmanSym {
bits: 26,
code: 0xfffffb00,
}, HuffmanSym {
bits: 26,
code: 0xfffffb40,
}, HuffmanSym {
bits: 27,
code: 0xfffffce0,
}, HuffmanSym {
bits: 27,
code: 0xfffffd00,
}, HuffmanSym {
bits: 27,
code: 0xfffffd20,
}, HuffmanSym {
bits: 27,
code: 0xfffffd40,
}, HuffmanSym {
bits: 27,
code: 0xfffffd60,
}, HuffmanSym {
bits: 28,
code: 0xffffffe0,
}, HuffmanSym {
bits: 27,
code: 0xfffffd80,
}, HuffmanSym {
bits: 27,
code: 0xfffffda0,
}, HuffmanSym {
bits: 27,
code: 0xfffffdc0,
}, HuffmanSym {
bits: 27,
code: 0xfffffde0,
}, HuffmanSym {
bits: 27,
code: 0xfffffe00,
}, HuffmanSym {
bits: 26,
code: 0xfffffb80,
}, HuffmanSym {
bits: 30,
code: 0xfffffffc,
}, ];
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]) -> Option<usize> {
let required = encoded_len(data);
if buf.len() < required {
return None;
}
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 += sym.bits as u32;
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;
}
Some(offset)
}
pub fn decode(data: &[u8]) -> Result<Vec<u8>, QpackError> {
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 sym.bits as u32 <= acc_bits {
let mask = if sym.bits >= 32 {
0xffffffff_u32
} else {
!((1u32 << (32 - sym.bits)) - 1)
};
if (current & mask) == sym.code {
if sym_idx == 256 {
return Err(QpackError::InvalidHuffman);
}
result.push(sym_idx as u8);
acc_bits -= sym.bits as u32;
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(QpackError::InvalidHuffman);
}
if acc_bits > 7 {
return Err(QpackError::InvalidHuffman);
}
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_none());
}
}