1 | use crate::io::{Error, Read}; |
2 | pub const MAGIC_NUM: u32 = 0xFD2F_B528; |
3 | pub const MIN_WINDOW_SIZE: u64 = 1024; |
4 | pub const MAX_WINDOW_SIZE: u64 = (1 << 41) + 7 * (1 << 38); |
5 | |
6 | pub struct Frame { |
7 | pub header: FrameHeader, |
8 | } |
9 | |
10 | pub struct FrameHeader { |
11 | pub descriptor: FrameDescriptor, |
12 | window_descriptor: u8, |
13 | dict_id: Option<u32>, |
14 | frame_content_size: u64, |
15 | } |
16 | |
17 | pub struct FrameDescriptor(u8); |
18 | |
19 | #[derive (Debug, derive_more::Display)] |
20 | #[cfg_attr (feature = "std" , derive(derive_more::Error))] |
21 | #[non_exhaustive ] |
22 | pub enum FrameDescriptorError { |
23 | #[display(fmt = "Invalid Frame_Content_Size_Flag; Is: {got}, Should be one of: 0, 1, 2, 3" )] |
24 | InvalidFrameContentSizeFlag { got: u8 }, |
25 | } |
26 | |
27 | impl FrameDescriptor { |
28 | pub fn frame_content_size_flag(&self) -> u8 { |
29 | self.0 >> 6 |
30 | } |
31 | |
32 | pub fn reserved_flag(&self) -> bool { |
33 | ((self.0 >> 3) & 0x1) == 1 |
34 | } |
35 | |
36 | pub fn single_segment_flag(&self) -> bool { |
37 | ((self.0 >> 5) & 0x1) == 1 |
38 | } |
39 | |
40 | pub fn content_checksum_flag(&self) -> bool { |
41 | ((self.0 >> 2) & 0x1) == 1 |
42 | } |
43 | |
44 | pub fn dict_id_flag(&self) -> u8 { |
45 | self.0 & 0x3 |
46 | } |
47 | |
48 | // Deriving info from the flags |
49 | pub fn frame_content_size_bytes(&self) -> Result<u8, FrameDescriptorError> { |
50 | match self.frame_content_size_flag() { |
51 | 0 => { |
52 | if self.single_segment_flag() { |
53 | Ok(1) |
54 | } else { |
55 | Ok(0) |
56 | } |
57 | } |
58 | 1 => Ok(2), |
59 | 2 => Ok(4), |
60 | 3 => Ok(8), |
61 | other => Err(FrameDescriptorError::InvalidFrameContentSizeFlag { got: other }), |
62 | } |
63 | } |
64 | |
65 | pub fn dictionary_id_bytes(&self) -> Result<u8, FrameDescriptorError> { |
66 | match self.dict_id_flag() { |
67 | 0 => Ok(0), |
68 | 1 => Ok(1), |
69 | 2 => Ok(2), |
70 | 3 => Ok(4), |
71 | other => Err(FrameDescriptorError::InvalidFrameContentSizeFlag { got: other }), |
72 | } |
73 | } |
74 | } |
75 | |
76 | #[derive (Debug, derive_more::Display, derive_more::From)] |
77 | #[cfg_attr (feature = "std" , derive(derive_more::Error))] |
78 | #[non_exhaustive ] |
79 | pub enum FrameHeaderError { |
80 | #[display( |
81 | fmt = "window_size bigger than allowed maximum. Is: {got}, Should be lower than: {MAX_WINDOW_SIZE}" |
82 | )] |
83 | WindowTooBig { got: u64 }, |
84 | #[display( |
85 | fmt = "window_size smaller than allowed minimum. Is: {got}, Should be greater than: {MIN_WINDOW_SIZE}" |
86 | )] |
87 | WindowTooSmall { got: u64 }, |
88 | #[display(fmt = "{_0:?}" )] |
89 | #[from] |
90 | FrameDescriptorError(FrameDescriptorError), |
91 | #[display(fmt = "Not enough bytes in dict_id. Is: {got}, Should be: {expected}" )] |
92 | DictIdTooSmall { got: usize, expected: usize }, |
93 | #[display( |
94 | fmt = "frame_content_size does not have the right length. Is: {got}, Should be: {expected}" |
95 | )] |
96 | MismatchedFrameSize { got: usize, expected: u8 }, |
97 | #[display(fmt = "frame_content_size was zero" )] |
98 | FrameSizeIsZero, |
99 | #[display(fmt = "Invalid frame_content_size. Is: {got}, Should be one of 1, 2, 4, 8 bytes" )] |
100 | InvalidFrameSize { got: u8 }, |
101 | } |
102 | |
103 | impl FrameHeader { |
104 | pub fn window_size(&self) -> Result<u64, FrameHeaderError> { |
105 | if self.descriptor.single_segment_flag() { |
106 | Ok(self.frame_content_size()) |
107 | } else { |
108 | let exp = self.window_descriptor >> 3; |
109 | let mantissa = self.window_descriptor & 0x7; |
110 | |
111 | let window_log = 10 + u64::from(exp); |
112 | let window_base = 1 << window_log; |
113 | let window_add = (window_base / 8) * u64::from(mantissa); |
114 | |
115 | let window_size = window_base + window_add; |
116 | |
117 | if window_size >= MIN_WINDOW_SIZE { |
118 | if window_size < MAX_WINDOW_SIZE { |
119 | Ok(window_size) |
120 | } else { |
121 | Err(FrameHeaderError::WindowTooBig { got: window_size }) |
122 | } |
123 | } else { |
124 | Err(FrameHeaderError::WindowTooSmall { got: window_size }) |
125 | } |
126 | } |
127 | } |
128 | |
129 | pub fn dictionary_id(&self) -> Option<u32> { |
130 | self.dict_id |
131 | } |
132 | |
133 | pub fn frame_content_size(&self) -> u64 { |
134 | self.frame_content_size |
135 | } |
136 | } |
137 | |
138 | #[derive (Debug, derive_more::Display, derive_more::From)] |
139 | #[cfg_attr (feature = "std" , derive(derive_more::Error))] |
140 | #[non_exhaustive ] |
141 | pub enum ReadFrameHeaderError { |
142 | #[display(fmt = "Error while reading magic number: {_0}" )] |
143 | MagicNumberReadError(Error), |
144 | #[display(fmt = "Read wrong magic number: 0x{_0:X}" )] |
145 | BadMagicNumber(#[cfg_attr (feature = "std" , error(ignore))] u32), |
146 | #[display(fmt = "Error while reading frame descriptor: {_0}" )] |
147 | FrameDescriptorReadError(Error), |
148 | #[display(fmt = "{_0:?}" )] |
149 | #[from] |
150 | InvalidFrameDescriptor(FrameDescriptorError), |
151 | #[display(fmt = "Error while reading window descriptor: {_0}" )] |
152 | WindowDescriptorReadError(Error), |
153 | #[display(fmt = "Error while reading dictionary id: {_0}" )] |
154 | DictionaryIdReadError(Error), |
155 | #[display(fmt = "Error while reading frame content size: {_0}" )] |
156 | FrameContentSizeReadError(Error), |
157 | #[display(fmt = "SkippableFrame encountered with MagicNumber 0x{_0:X} and length {_1} bytes" )] |
158 | SkipFrame(u32, u32), |
159 | } |
160 | |
161 | pub fn read_frame_header(mut r: impl Read) -> Result<(Frame, u8), ReadFrameHeaderError> { |
162 | use ReadFrameHeaderError as err; |
163 | let mut buf = [0u8; 4]; |
164 | |
165 | r.read_exact(&mut buf).map_err(err::MagicNumberReadError)?; |
166 | let mut bytes_read = 4; |
167 | let magic_num = u32::from_le_bytes(buf); |
168 | |
169 | // Skippable frames have a magic number in this interval |
170 | if (0x184D2A50..=0x184D2A5F).contains(&magic_num) { |
171 | r.read_exact(&mut buf) |
172 | .map_err(err::FrameDescriptorReadError)?; |
173 | let skip_size = u32::from_le_bytes(buf); |
174 | return Err(ReadFrameHeaderError::SkipFrame(magic_num, skip_size)); |
175 | } |
176 | |
177 | if magic_num != MAGIC_NUM { |
178 | return Err(ReadFrameHeaderError::BadMagicNumber(magic_num)); |
179 | } |
180 | |
181 | r.read_exact(&mut buf[0..1]) |
182 | .map_err(err::FrameDescriptorReadError)?; |
183 | let desc = FrameDescriptor(buf[0]); |
184 | |
185 | bytes_read += 1; |
186 | |
187 | let mut frame_header = FrameHeader { |
188 | descriptor: FrameDescriptor(desc.0), |
189 | dict_id: None, |
190 | frame_content_size: 0, |
191 | window_descriptor: 0, |
192 | }; |
193 | |
194 | if !desc.single_segment_flag() { |
195 | r.read_exact(&mut buf[0..1]) |
196 | .map_err(err::WindowDescriptorReadError)?; |
197 | frame_header.window_descriptor = buf[0]; |
198 | bytes_read += 1; |
199 | } |
200 | |
201 | let dict_id_len = desc.dictionary_id_bytes()? as usize; |
202 | if dict_id_len != 0 { |
203 | let buf = &mut buf[..dict_id_len]; |
204 | r.read_exact(buf).map_err(err::DictionaryIdReadError)?; |
205 | bytes_read += dict_id_len; |
206 | let mut dict_id = 0u32; |
207 | |
208 | #[allow (clippy::needless_range_loop)] |
209 | for i in 0..dict_id_len { |
210 | dict_id += (buf[i] as u32) << (8 * i); |
211 | } |
212 | if dict_id != 0 { |
213 | frame_header.dict_id = Some(dict_id); |
214 | } |
215 | } |
216 | |
217 | let fcs_len = desc.frame_content_size_bytes()? as usize; |
218 | if fcs_len != 0 { |
219 | let mut fcs_buf = [0u8; 8]; |
220 | let fcs_buf = &mut fcs_buf[..fcs_len]; |
221 | r.read_exact(fcs_buf) |
222 | .map_err(err::FrameContentSizeReadError)?; |
223 | bytes_read += fcs_len; |
224 | let mut fcs = 0u64; |
225 | |
226 | #[allow (clippy::needless_range_loop)] |
227 | for i in 0..fcs_len { |
228 | fcs += (fcs_buf[i] as u64) << (8 * i); |
229 | } |
230 | if fcs_len == 2 { |
231 | fcs += 256; |
232 | } |
233 | frame_header.frame_content_size = fcs; |
234 | } |
235 | |
236 | let frame: Frame = Frame { |
237 | header: frame_header, |
238 | }; |
239 | |
240 | Ok((frame, bytes_read as u8)) |
241 | } |
242 | |