Skip to main content

zstd_zero/
huffman.rs

1use crate::bitstream::BackwardBits;
2use crate::fse::Table as FseTable;
3use crate::DecodeError;
4
5const MAX_BITS: u8 = 11;
6
7/// An initialized entropy-table slot; the decoder manages its contents.
8#[derive(Clone, Copy, Debug, Default)]
9pub struct Entry {
10    symbol: u8,
11    bits: u8,
12}
13
14impl Entry {
15    /// Create an empty slot, including for statically allocated workspaces.
16    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                // A short read must fail here. Clamping to the bits that remain would
105                // drive `remaining` to exactly 0, making the end-of-stream check below
106                // vacuous, and every remaining literal would then be decoded from an
107                // all-zero peek — silently emitting `entries[0]` instead of erroring.
108                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}