1use crate::io::{Error, Read};
2pub const MAGIC_NUM: u32 = 0xFD2F_B528;
3pub const MIN_WINDOW_SIZE: u64 = 1024;
4pub const MAX_WINDOW_SIZE: u64 = (1 << 41) + 7 * (1 << 38);
5
6pub struct Frame {
7 pub header: FrameHeader,
8}
9
10pub struct FrameHeader {
11 pub descriptor: FrameDescriptor,
12 window_descriptor: u8,
13 dict_id: Option<u32>,
14 frame_content_size: u64,
15}
16
17pub struct FrameDescriptor(u8);
18
19#[derive(Debug, derive_more::Display)]
20#[cfg_attr(feature = "std", derive(derive_more::Error))]
21#[non_exhaustive]
22pub 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
27impl 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]
79pub 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
103impl 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]
141pub 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
161pub 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