1use std::io;
2
3use binrw::BinReaderExt;
4use bitstream_io::{BitRead, BitReader, LE};
5use cfor::cfor;
6
7use super::installer::hufftree::HuffTree;
8
9#[derive(Debug, thiserror::Error)]
10pub enum Error {
11 #[error(transparent)]
12 BinRw(#[from] binrw::Error),
13
14 #[error(transparent)]
15 Io(#[from] io::Error),
16
17 #[error(transparent)]
18 Installer(#[from] super::installer::Error),
19
20 #[error("Invalid Reference")]
21 DictionaryOutOfBounds,
22
23 #[error("Too Much Ouptut")]
24 TooMuchOutput,
25}
26
27const fn init_lengths<const N: usize>() -> ([u16; N], [u8; N]) {
28 let mut values = [0u16; N];
29 let mut paths = [0u8; N];
30
31 let mut k = 0;
32 cfor! {let mut i = 0; i < N; i+=1; {
33 let value = (i.saturating_sub(4) >> 2) as u8;
34
35 values[i] = k;
36 paths[i] = value;
37
38 k = k.wrapping_add(1 << (value & 0x3f));
39 }}
40
41 (values, paths)
42}
43
44const fn init_offsets<const N: usize>() -> ([u16; N], [u8; N]) {
46 let mut paths = [0u16; N];
47 let mut values = [0u8; N];
48
49 let mut k = 1;
50 cfor! {let mut i = 0; i < N; i+=1; {
51 let value = (i.saturating_sub(1) >> 1) as u8;
52
53 paths[i] = k;
54 values[i] = value;
55
56 k = k.wrapping_add(1 << (value & 0x3f));
57 }};
58
59 (paths, values)
60}
61
62pub fn decompress(
63 mut reader: impl io::Read + io::Seek,
64 uncompressed_size: usize,
65 dict: &[u8],
66) -> Result<Vec<u8>, Error> {
67 let (offsets, offsets_bits) = init_offsets::<0x1f>();
68 let (lengths, length_bits) = init_lengths::<0x24>();
69
70 let dynamic_code_size: u16 = reader.read_be::<u8>()? as u16 * 2 - 1;
71 assert!(dynamic_code_size <= 0x1f);
72 let mut reader = BitReader::<_, LE>::new(&mut reader);
73 let fixed = HuffTree::read_from(&mut reader, 0x124)?;
74 let dynamic = HuffTree::read_from(&mut reader, dynamic_code_size as usize)?;
75
76 let mut output = vec![0u8; uncompressed_size];
77 let mut output_ptr = 0;
78 while output_ptr < output.len() {
79 let mut sym = fixed.read_code(0, &mut reader)? as usize;
80 if sym < 0x100 {
81 output[output_ptr] = (sym & 0xFF) as u8;
83 output_ptr += 1;
84 continue;
85 }
86 sym -= 0x100;
87
88 let mut length = lengths[sym] as usize + 3;
89 let bits = length_bits[sym] as u32;
90 length += reader.read_var::<u32>(bits)? as usize;
91
92 let sym = dynamic.read_code(0, &mut reader)? as usize;
93 let mut offset = offsets[sym] as usize;
94 let bits = offsets_bits[sym] as u32;
95 offset += reader.read_var::<u32>(bits)? as usize;
96
97 if output_ptr + length > output.len() {
98 return Err(Error::TooMuchOutput);
99 }
100
101 if offset <= output_ptr {
102 for _ in 0..length {
104 output[output_ptr] = output[output_ptr - offset];
105 output_ptr += 1;
106 }
107 } else {
108 if dict.len() <= (offset - output_ptr) {
110 return Err(Error::DictionaryOutOfBounds);
112 }
113
114 let dictionary_offset = dict.len() - (offset - output_ptr);
115 output[output_ptr..(output_ptr + length)]
116 .copy_from_slice(&dict[dictionary_offset..(dictionary_offset + length)]);
117 output_ptr += length;
118 }
119 }
120
121 Ok(output)
122}