1use crate::bitstream::BackwardBits;
2use crate::fse::Table as FseTable;
3use crate::DecodeError;
4
5const MAX_BITS: u8 = 11;
6
7#[derive(Clone, Copy, Debug, Default)]
9pub struct Entry {
10 symbol: u8,
11 bits: u8,
12}
13
14impl Entry {
15 pub const fn new() -> Self {
17 Self { symbol: 0, bits: 0 }
18 }
19}
20
21pub(crate) struct Table<'a> {
22 entries: &'a mut [Entry],
23 scratch: FseTable<'a>,
24 table_bits: u8,
25 valid: bool,
26}
27
28impl<'a> Table<'a> {
29 pub(crate) fn new(entries: &'a mut [Entry], scratch: FseTable<'a>) -> Self {
30 Self {
31 entries,
32 scratch,
33 table_bits: 0,
34 valid: false,
35 }
36 }
37
38 pub(crate) fn reset(&mut self) {
39 self.table_bits = 0;
40 self.valid = false;
41 self.scratch.reset();
42 }
43
44 pub(crate) fn is_valid(&self) -> bool {
45 self.valid
46 }
47
48 pub(crate) fn read_description(
49 &mut self,
50 input: &[u8],
51 fse_scratch: &mut [i16],
52 ) -> Result<usize, DecodeError> {
53 let header = *input.first().ok_or(DecodeError::InvalidEntropyTable)?;
54 let mut weights = [0u8; 256];
55 let (weight_count, consumed) = if header < 128 {
56 let compressed_size = header as usize;
57 if compressed_size == 0 || input.len() < 1 + compressed_size {
58 return Err(DecodeError::InvalidEntropyTable);
59 }
60 let count = decode_compressed_weights(
61 &input[1..1 + compressed_size],
62 &mut weights,
63 &mut self.scratch,
64 fse_scratch,
65 )?;
66 (count, 1 + compressed_size)
67 } else {
68 let count = header as usize - 127;
69 let bytes = count.div_ceil(2);
70 if input.len() < 1 + bytes {
71 return Err(DecodeError::InvalidEntropyTable);
72 }
73 for (index, weight) in weights[..count].iter_mut().enumerate() {
74 let packed = input[1 + index / 2];
75 *weight = if index % 2 == 0 {
76 packed >> 4
77 } else {
78 packed & 0x0f
79 };
80 }
81 (count, 1 + bytes)
82 };
83 self.build(&weights[..weight_count])?;
84 Ok(consumed)
85 }
86
87 pub(crate) fn decode(
88 &self,
89 input: &[u8],
90 output: &mut [u8],
91 strict: bool,
92 ) -> Result<(), DecodeError> {
93 if !self.valid {
94 return Err(DecodeError::InvalidEntropyTable);
95 }
96 let mut bits = BackwardBits::new(input)?;
97 for byte in output {
98 let index = bits.peek_padded(self.table_bits) as usize;
99 let entry = self.entries[index];
100 if entry.bits == 0 {
101 return Err(DecodeError::InvalidEntropyTable);
102 }
103 let consumed = if strict {
104 entry.bits
109 } else {
110 core::cmp::min(entry.bits as usize, bits.remaining()) as u8
111 };
112 bits.consume(consumed)?;
113 *byte = entry.symbol;
114 }
115 if bits.remaining() != 0 {
116 return Err(DecodeError::InvalidBitstream);
117 }
118 Ok(())
119 }
120
121 pub(crate) fn decode_four(
122 &self,
123 input: &[u8],
124 output: &mut [u8],
125 strict: bool,
126 ) -> Result<(), DecodeError> {
127 if input.len() < 6 {
128 return Err(DecodeError::InvalidBitstream);
129 }
130 let sizes = [
131 u16::from_le_bytes([input[0], input[1]]) as usize,
132 u16::from_le_bytes([input[2], input[3]]) as usize,
133 u16::from_le_bytes([input[4], input[5]]) as usize,
134 ];
135 let mut starts = [6usize; 4];
136 for (stream, size) in sizes.iter().enumerate() {
137 starts[stream + 1] = starts[stream]
138 .checked_add(*size)
139 .ok_or(DecodeError::ArithmeticOverflow)?;
140 }
141 if starts[3] > input.len() {
142 return Err(DecodeError::InvalidBitstream);
143 }
144 let ends = [starts[1], starts[2], starts[3], input.len()];
145 let segment = output.len().div_ceil(4);
146 for stream in 0..4 {
147 let output_start = core::cmp::min(stream * segment, output.len());
148 let output_end = core::cmp::min(output_start + segment, output.len());
149 if output_start != output_end {
150 self.decode(
151 &input[starts[stream]..ends[stream]],
152 &mut output[output_start..output_end],
153 strict,
154 )?;
155 }
156 }
157 Ok(())
158 }
159
160 fn build(&mut self, weights: &[u8]) -> Result<(), DecodeError> {
161 if weights.is_empty() || weights.len() >= 256 {
162 return Err(DecodeError::InvalidEntropyTable);
163 }
164 let mut sum = 0u32;
165 for weight in weights {
166 if *weight > MAX_BITS {
167 return Err(DecodeError::InvalidEntropyTable);
168 }
169 if *weight != 0 {
170 sum = sum
171 .checked_add(1u32 << (*weight - 1))
172 .ok_or(DecodeError::InvalidEntropyTable)?;
173 }
174 }
175 if sum == 0 {
176 return Err(DecodeError::InvalidEntropyTable);
177 }
178 let table_bits = 32 - sum.leading_zeros();
179 if table_bits > MAX_BITS as u32 {
180 return Err(DecodeError::InvalidEntropyTable);
181 }
182 let remainder = (1u32 << table_bits)
183 .checked_sub(sum)
184 .ok_or(DecodeError::InvalidEntropyTable)?;
185 if !remainder.is_power_of_two() {
186 return Err(DecodeError::InvalidEntropyTable);
187 }
188 let implied_weight = 32 - remainder.leading_zeros();
189 let table_bits = table_bits as u8;
190
191 let mut code_bits = [0u8; 256];
192 for (index, weight) in weights.iter().enumerate() {
193 code_bits[index] = if *weight == 0 {
194 0
195 } else {
196 table_bits + 1 - *weight
197 };
198 }
199 code_bits[weights.len()] = table_bits + 1 - implied_weight as u8;
200
201 let mut ranks = [0usize; MAX_BITS as usize + 1];
202 for bits in &code_bits[..=weights.len()] {
203 ranks[*bits as usize] += 1;
204 }
205 let mut starts = [0usize; MAX_BITS as usize + 1];
206 for bits in (1..=table_bits as usize).rev() {
207 starts[bits - 1] =
208 starts[bits] + ranks[bits] * (1usize << (table_bits as usize - bits));
209 }
210 let used = 1usize << table_bits;
211 if starts[0] != used {
212 return Err(DecodeError::InvalidEntropyTable);
213 }
214 self.entries[..used].fill(Entry::default());
215 for (symbol, bits) in code_bits[..=weights.len()].iter().enumerate() {
216 if *bits == 0 {
217 continue;
218 }
219 let width = 1usize << (table_bits - *bits);
220 let start = starts[*bits as usize];
221 let end = start
222 .checked_add(width)
223 .ok_or(DecodeError::InvalidEntropyTable)?;
224 if end > used {
225 return Err(DecodeError::InvalidEntropyTable);
226 }
227 self.entries[start..end].fill(Entry {
228 symbol: symbol as u8,
229 bits: *bits,
230 });
231 starts[*bits as usize] = end;
232 }
233 self.table_bits = table_bits;
234 self.valid = true;
235 Ok(())
236 }
237}
238
239fn decode_compressed_weights(
240 input: &[u8],
241 output: &mut [u8; 256],
242 table: &mut FseTable<'_>,
243 scratch: &mut [i16],
244) -> Result<usize, DecodeError> {
245 table.reset();
246 let description_size = table.read_description(input, 12, 6, scratch)?;
247 if description_size >= input.len() {
248 return Err(DecodeError::InvalidEntropyTable);
249 }
250 let mut bits = BackwardBits::new(&input[description_size..])?;
251 let mut first = bits.read(table.log())?;
252 let mut second = bits.read(table.log())?;
253 let mut count = 0usize;
254 loop {
255 if count >= 255 {
256 return Err(DecodeError::InvalidEntropyTable);
257 }
258 output[count] = table.symbol(first)?;
259 count += 1;
260 let entry = table.entry(first)?;
261 if bits.remaining() < entry.bits as usize {
262 if count >= 255 {
263 return Err(DecodeError::InvalidEntropyTable);
264 }
265 output[count] = table.symbol(second)?;
266 return Ok(count + 1);
267 }
268 table.update(&mut first, &mut bits)?;
269 core::mem::swap(&mut first, &mut second);
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn truncated_literal_symbol_is_rejected() {
279 let mut entries = std::vec![Entry::new(); crate::HUFFMAN_ENTRIES];
280 let mut scratch = std::vec![crate::FseEntry::new(); 512];
281 let mut table = Table::new(&mut entries, FseTable::new(&mut scratch));
282 table.build(&[1]).unwrap();
283 let mut output = [0; 1];
284 assert!(table.decode(&[1], &mut output, true).is_err());
285 assert!(table.decode(&[2], &mut output, true).is_ok());
286 assert_eq!(output, [0]);
287 }
288}