1 | use alloc::vec::Vec; |
2 | use core::convert::TryInto; |
3 | |
4 | use crate::decoding::scratch::FSEScratch; |
5 | use crate::decoding::scratch::HuffmanScratch; |
6 | use crate::fse::FSETableError; |
7 | use crate::huff0::HuffmanTableError; |
8 | |
9 | pub struct Dictionary { |
10 | pub id: u32, |
11 | pub fse: FSEScratch, |
12 | pub huf: HuffmanScratch, |
13 | pub dict_content: Vec<u8>, |
14 | pub offset_hist: [u32; 3], |
15 | } |
16 | |
17 | #[derive (Debug, derive_more::Display, derive_more::From)] |
18 | #[cfg_attr (feature = "std" , derive(derive_more::Error))] |
19 | #[non_exhaustive ] |
20 | pub enum DictionaryDecodeError { |
21 | #[display( |
22 | fmt = "Bad magic_num at start of the dictionary; Got: {got:#04X?}, Expected: {MAGIC_NUM:#04x?}" |
23 | )] |
24 | BadMagicNum { got: [u8; 4] }, |
25 | #[display(fmt = "{_0:?}" )] |
26 | #[from] |
27 | FSETableError(FSETableError), |
28 | #[display(fmt = "{_0:?}" )] |
29 | #[from] |
30 | HuffmanTableError(HuffmanTableError), |
31 | } |
32 | |
33 | pub const MAGIC_NUM: [u8; 4] = [0x37, 0xA4, 0x30, 0xEC]; |
34 | |
35 | impl Dictionary { |
36 | /// parses the dictionary and set the tables |
37 | /// it returns the dict_id for checking with the frame's dict_id |
38 | pub fn decode_dict(raw: &[u8]) -> Result<Dictionary, DictionaryDecodeError> { |
39 | let mut new_dict = Dictionary { |
40 | id: 0, |
41 | fse: FSEScratch::new(), |
42 | huf: HuffmanScratch::new(), |
43 | dict_content: Vec::new(), |
44 | offset_hist: [2, 4, 8], |
45 | }; |
46 | |
47 | let magic_num: [u8; 4] = raw[..4].try_into().expect("optimized away" ); |
48 | if magic_num != MAGIC_NUM { |
49 | return Err(DictionaryDecodeError::BadMagicNum { got: magic_num }); |
50 | } |
51 | |
52 | let dict_id = raw[4..8].try_into().expect("optimized away" ); |
53 | let dict_id = u32::from_le_bytes(dict_id); |
54 | new_dict.id = dict_id; |
55 | |
56 | let raw_tables = &raw[8..]; |
57 | |
58 | let huf_size = new_dict.huf.table.build_decoder(raw_tables)?; |
59 | let raw_tables = &raw_tables[huf_size as usize..]; |
60 | |
61 | let of_size = new_dict.fse.offsets.build_decoder( |
62 | raw_tables, |
63 | crate::decoding::sequence_section_decoder::OF_MAX_LOG, |
64 | )?; |
65 | let raw_tables = &raw_tables[of_size..]; |
66 | |
67 | let ml_size = new_dict.fse.match_lengths.build_decoder( |
68 | raw_tables, |
69 | crate::decoding::sequence_section_decoder::ML_MAX_LOG, |
70 | )?; |
71 | let raw_tables = &raw_tables[ml_size..]; |
72 | |
73 | let ll_size = new_dict.fse.literal_lengths.build_decoder( |
74 | raw_tables, |
75 | crate::decoding::sequence_section_decoder::LL_MAX_LOG, |
76 | )?; |
77 | let raw_tables = &raw_tables[ll_size..]; |
78 | |
79 | let offset1 = raw_tables[0..4].try_into().expect("optimized away" ); |
80 | let offset1 = u32::from_le_bytes(offset1); |
81 | |
82 | let offset2 = raw_tables[4..8].try_into().expect("optimized away" ); |
83 | let offset2 = u32::from_le_bytes(offset2); |
84 | |
85 | let offset3 = raw_tables[8..12].try_into().expect("optimized away" ); |
86 | let offset3 = u32::from_le_bytes(offset3); |
87 | |
88 | new_dict.offset_hist[0] = offset1; |
89 | new_dict.offset_hist[1] = offset2; |
90 | new_dict.offset_hist[2] = offset3; |
91 | |
92 | let raw_content = &raw_tables[12..]; |
93 | new_dict.dict_content.extend(raw_content); |
94 | |
95 | Ok(new_dict) |
96 | } |
97 | } |
98 | |