pub(crate) const END_OF_BLOCK: u16 = 256;
pub(crate) const LENGTH_TABLE: [(u8, u8); 29] = [
(0, 0),
(1, 0),
(2, 0),
(3, 0),
(4, 0),
(5, 0),
(6, 0),
(7, 0),
(8, 1),
(10, 1),
(12, 1),
(14, 1),
(16, 2),
(20, 2),
(24, 2),
(28, 2),
(32, 3),
(40, 3),
(48, 3),
(56, 3),
(64, 4),
(80, 4),
(96, 4),
(112, 4),
(128, 5),
(160, 5),
(192, 5),
(224, 5),
(255, 0),
];
pub(crate) const DISTANCE_TABLE: [(u16, u8); 30] = [
(1, 0),
(2, 0),
(3, 0),
(4, 0),
(5, 1),
(7, 1),
(9, 2),
(13, 2),
(17, 3),
(25, 3),
(33, 4),
(49, 4),
(65, 5),
(97, 5),
(129, 6),
(193, 6),
(257, 7),
(385, 7),
(513, 8),
(769, 8),
(1025, 9),
(1537, 9),
(2049, 10),
(3073, 10),
(4097, 11),
(6145, 11),
(8193, 12),
(12_289, 12),
(16_385, 13),
(24_577, 13),
];
#[derive(Debug, Clone, Copy)]
pub enum Code {
EndOfBlock,
Literal(u8),
Pointer { distance: u16, length: u8 },
}
impl Code {
pub fn literal_code(&self) -> u16 {
match *self {
Code::Literal(x) => x as u16,
Code::EndOfBlock => END_OF_BLOCK,
Code::Pointer { length: l, .. } => match l {
0x00..=0x07 => 257 + l as u16,
0x08..=0x0F => 265 + (l as u16 - 0x08) / 0x02,
0x10..=0x1F => 269 + (l as u16 - 0x10) / 0x04,
0x20..=0x3F => 273 + (l as u16 - 0x20) / 0x08,
0x40..=0x7F => 277 + (l as u16 - 0x40) / 0x10,
0x80..=0xFE => 281 + (l as u16 - 0x80) / 0x20,
0xFF => 285,
},
}
}
pub fn extra_length(&self) -> Option<(u8, u16)> {
if let Code::Pointer { length: l, .. } = *self {
match l {
0x00..=0x07 | 0xFF => None,
0x08..=0x0F => Some((1, (l as u16 - 0x08) % 0x02)),
0x10..=0x1F => Some((2, (l as u16 - 0x10) % 0x04)),
0x20..=0x3F => Some((3, (l as u16 - 0x20) % 0x08)),
0x40..=0x7F => Some((4, (l as u16 - 0x40) % 0x10)),
0x80..=0xFE => Some((5, (l as u16 - 0x80) % 0x20)),
}
} else {
None
}
}
pub fn distance_code(&self) -> Option<(u16, u8, u16)> {
if let Code::Pointer { distance: d, .. } = *self {
let d = d - 1;
match d {
0x0000..=0x0003 => Some((d, 0, 0)),
0x0004..=0x0007 => {
let (div, rem) = div_rem(d - 0x0004, 0x0002);
Some((4 + div, 1, rem))
}
0x0008..=0x000F => {
let (div, rem) = div_rem(d - 0x0008, 0x0004);
Some((6 + div, 2, rem))
}
0x0010..=0x001F => {
let (div, rem) = div_rem(d - 0x0010, 0x0008);
Some((8 + div, 3, rem))
}
0x0020..=0x003F => {
let (div, rem) = div_rem(d - 0x0020, 0x0010);
Some((10 + div, 4, rem))
}
0x0040..=0x007F => {
let (div, rem) = div_rem(d - 0x0040, 0x0020);
Some((12 + div, 5, rem))
}
0x0080..=0x00FF => {
let (div, rem) = div_rem(d - 0x0080, 0x0040);
Some((14 + div, 6, rem))
}
0x0100..=0x01FF => {
let (div, rem) = div_rem(d - 0x0100, 0x0080);
Some((16 + div, 7, rem))
}
0x0200..=0x03FF => {
let (div, rem) = div_rem(d - 0x0200, 0x0100);
Some((18 + div, 8, rem))
}
0x0400..=0x07FF => {
let (div, rem) = div_rem(d - 0x0400, 0x0200);
Some((20 + div, 9, rem))
}
0x0800..=0x0FFF => {
let (div, rem) = div_rem(d - 0x0800, 0x0400);
Some((22 + div, 10, rem))
}
0x1000..=0x1FFF => {
let (div, rem) = div_rem(d - 0x1000, 0x0800);
Some((24 + div, 11, rem))
}
0x2000..=0x3FFF => {
let (div, rem) = div_rem(d - 0x2000, 0x1000);
Some((26 + div, 12, rem))
}
0x4000..=0x7FFF => {
let (div, rem) = div_rem(d - 0x4000, 0x2000);
Some((28 + div, 13, rem))
}
_ => unimplemented!(),
}
} else {
None
}
}
}
fn div_rem(a: u16, b: u16) -> (u16, u16) {
(a / b, a % b)
}