1use crate::bitstream::{BackwardBits, ForwardBits};
2use crate::DecodeError;
3
4pub(crate) const MAX_TABLE_LOG: u8 = 9;
5pub(crate) const MAX_SYMBOLS: usize = 256;
6
7#[derive(Clone, Copy, Debug, Default)]
9pub struct Entry {
10 pub(crate) baseline: u16,
11 pub(crate) bits: u8,
12 pub(crate) symbol: u8,
13}
14
15impl Entry {
16 pub const fn new() -> Self {
18 Self {
19 baseline: 0,
20 bits: 0,
21 symbol: 0,
22 }
23 }
24}
25
26pub(crate) struct Table<'a> {
27 entries: &'a mut [Entry],
28 len: usize,
29 log: u8,
30 valid: bool,
31}
32
33impl<'a> Table<'a> {
34 pub(crate) fn new(entries: &'a mut [Entry]) -> Self {
35 Self {
36 entries,
37 len: 0,
38 log: 0,
39 valid: false,
40 }
41 }
42
43 pub(crate) fn reset(&mut self) {
44 self.len = 0;
45 self.log = 0;
46 self.valid = false;
47 }
48
49 pub(crate) fn is_valid(&self) -> bool {
50 self.valid
51 }
52
53 pub(crate) fn log(&self) -> u8 {
54 self.log
55 }
56
57 pub(crate) fn symbol(&self, state: u32) -> Result<u8, DecodeError> {
58 self.entry(state).map(|entry| entry.symbol)
59 }
60
61 pub(crate) fn update(
62 &self,
63 state: &mut u32,
64 bits: &mut BackwardBits<'_>,
65 ) -> Result<(), DecodeError> {
66 let entry = self.entry(*state)?;
67 *state = entry.baseline as u32 + bits.read(entry.bits)?;
68 Ok(())
69 }
70
71 pub(crate) fn entry(&self, state: u32) -> Result<Entry, DecodeError> {
72 if !self.valid || state as usize >= self.len {
73 return Err(DecodeError::InvalidEntropyTable);
74 }
75 Ok(self.entries[state as usize])
76 }
77
78 pub(crate) fn build_rle(&mut self, symbol: u8) {
79 self.entries[0] = Entry {
80 baseline: 0,
81 bits: 0,
82 symbol,
83 };
84 self.len = 1;
85 self.log = 0;
86 self.valid = true;
87 }
88
89 pub(crate) fn build(
90 &mut self,
91 probabilities: &[i16],
92 table_log: u8,
93 scratch: &mut [i16],
94 ) -> Result<(), DecodeError> {
95 let workspace = scratch
96 .get_mut(..probabilities.len())
97 .ok_or(DecodeError::InvalidEntropyTable)?;
98 workspace.copy_from_slice(probabilities);
99 self.build_in_place(workspace, table_log)
100 }
101
102 fn build_in_place(
103 &mut self,
104 probabilities: &mut [i16],
105 table_log: u8,
106 ) -> Result<(), DecodeError> {
107 if table_log > MAX_TABLE_LOG
108 || probabilities.is_empty()
109 || probabilities.len() > MAX_SYMBOLS
110 {
111 return Err(DecodeError::InvalidEntropyTable);
112 }
113 if table_log == 0 {
114 let symbol = probabilities
115 .iter()
116 .position(|probability| *probability == 1)
117 .ok_or(DecodeError::InvalidEntropyTable)?;
118 self.build_rle(symbol as u8);
119 return Ok(());
120 }
121
122 let table_size = 1usize << table_log;
123 let mut total = 0usize;
124 for probability in probabilities.iter() {
125 total = total
126 .checked_add(if *probability == -1 {
127 1
128 } else if *probability > 0 {
129 *probability as usize
130 } else {
131 0
132 })
133 .ok_or(DecodeError::ArithmeticOverflow)?;
134 }
135 if total != table_size {
136 return Err(DecodeError::InvalidEntropyTable);
137 }
138
139 self.entries[..table_size].fill(Entry::default());
140 let mut high = table_size;
141 for (symbol, probability) in probabilities.iter().enumerate() {
142 if *probability == -1 {
143 high = high
144 .checked_sub(1)
145 .ok_or(DecodeError::InvalidEntropyTable)?;
146 self.entries[high].symbol = symbol as u8;
147 }
148 }
149
150 let step = (table_size >> 1) + (table_size >> 3) + 3;
151 let mask = table_size - 1;
152 let mut position = 0usize;
153 for (symbol, probability) in probabilities.iter().enumerate() {
154 if *probability <= 0 {
155 continue;
156 }
157 for _ in 0..*probability as usize {
158 if position >= high {
159 return Err(DecodeError::InvalidEntropyTable);
160 }
161 self.entries[position].symbol = symbol as u8;
162 position = (position + step) & mask;
163 while position >= high {
164 position = (position + step) & mask;
165 }
166 }
167 }
168 if position != 0 {
169 return Err(DecodeError::InvalidEntropyTable);
170 }
171
172 for probability in probabilities.iter_mut() {
175 *probability = match *probability {
176 -1 => 1,
177 value if value > 0 => value,
178 _ => 0,
179 };
180 }
181 let next = probabilities;
182 for entry in &mut self.entries[..table_size] {
183 let symbol = entry.symbol as usize;
184 let state =
185 u16::try_from(next[symbol]).map_err(|_| DecodeError::InvalidEntropyTable)?;
186 if state == 0 {
187 return Err(DecodeError::InvalidEntropyTable);
188 }
189 next[symbol] =
190 i16::try_from(state + 1).map_err(|_| DecodeError::InvalidEntropyTable)?;
191 let floor_log = (u16::BITS - 1 - state.leading_zeros()) as u8;
192 let bits = table_log - floor_log;
193 entry.bits = bits;
194 entry.baseline = ((state as u32) << bits)
195 .checked_sub(table_size as u32)
196 .ok_or(DecodeError::InvalidEntropyTable)? as u16;
197 }
198
199 self.len = table_size;
200 self.log = table_log;
201 self.valid = true;
202 Ok(())
203 }
204
205 pub(crate) fn read_description(
206 &mut self,
207 input: &[u8],
208 max_symbol: usize,
209 max_log: u8,
210 scratch: &mut [i16],
211 ) -> Result<usize, DecodeError> {
212 if input.is_empty() || max_symbol >= MAX_SYMBOLS {
213 return Err(DecodeError::InvalidEntropyTable);
214 }
215 let mut bits = ForwardBits::new(input, 0);
216 let table_log = bits.read(4)? as u8 + 5;
217 if table_log > max_log || table_log > MAX_TABLE_LOG {
218 return Err(DecodeError::InvalidEntropyTable);
219 }
220
221 let expected = 1u32 << table_log;
222 let mut accumulated = 0u32;
223 let probabilities = scratch
224 .get_mut(..MAX_SYMBOLS)
225 .ok_or(DecodeError::InvalidEntropyTable)?;
226 probabilities.fill(0);
228 let mut symbols = 0usize;
229 while accumulated < expected {
230 if symbols > max_symbol {
231 return Err(DecodeError::InvalidEntropyTable);
232 }
233 let remaining = expected - accumulated + 1;
234 let width = (32 - remaining.leading_zeros()) as u8;
235 let unchecked = bits.read(width)?;
236 let low_threshold = (1u32 << width) - 1 - remaining;
237 let low_mask = (1u32 << (width - 1)) - 1;
238 let low = unchecked & low_mask;
239 let value = if low < low_threshold {
240 bits.rewind(1)?;
241 low
242 } else if unchecked > low_mask {
243 unchecked - low_threshold
244 } else {
245 unchecked
246 };
247 let probability = value as i32 - 1;
248 probabilities[symbols] = probability as i16;
249 symbols += 1;
250 match probability {
251 -1 => accumulated += 1,
252 value if value > 0 => accumulated += value as u32,
253 0 => loop {
254 let zeros = bits.read(2)? as usize;
255 if symbols + zeros > max_symbol + 1 {
256 return Err(DecodeError::InvalidEntropyTable);
257 }
258 symbols += zeros;
259 if zeros != 3 {
260 break;
261 }
262 },
263 _ => return Err(DecodeError::InvalidEntropyTable),
264 }
265 }
266 if accumulated != expected {
267 return Err(DecodeError::InvalidEntropyTable);
268 }
269 self.build_in_place(&mut probabilities[..symbols], table_log)?;
270 Ok(bits.position().div_ceil(8))
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[test]
279 fn shared_counters_cover_the_largest_table_and_ignore_dirty_storage() {
280 let mut entries = std::vec![Entry::new(); 512];
281 let mut scratch = [i16::MIN; MAX_SYMBOLS];
282 let mut table = Table::new(&mut entries);
283 table.build(&[512], 9, &mut scratch).unwrap();
284 for state in 0..512 {
285 let entry = table.entry(state).unwrap();
286 assert_eq!(
287 (entry.symbol, entry.bits, entry.baseline),
288 (0, 0, state as u16)
289 );
290 }
291 let probabilities = [16, 0, -1, 15];
294 table.build(&probabilities, 5, &mut scratch).unwrap();
295 let mut counts = [0; 4];
296 for state in 0..32 {
297 counts[table.entry(state).unwrap().symbol as usize] += 1;
298 }
299 assert_eq!(counts, [16, 0, 1, 15]);
300 assert_eq!(probabilities, [16, 0, -1, 15]);
301 }
302}