1use crate::*;
2use crate::util::hex_char;
3
4pub struct PacketReader<'a> {
5 buffer: &'a [u8],
6 position: u16,
7}
8
9impl<'a> PacketReader<'a> {
10 pub fn new(buffer: &'a [u8], size: u16) -> Self {
11 let size = (size as usize).min(buffer.len());
12 PacketReader {
13 buffer: &buffer[..size],
14 position: 0,
15 }
16 }
17
18 pub fn position(&self) -> u16 {
19 self.position
20 }
21
22 pub fn remaining(&self) -> u16 {
23 (self.buffer.len() as u16) - self.position
24 }
25
26 pub fn can_read(&self, bytes: u16) -> bool {
27 (self.position + bytes) <= self.buffer.len() as u16
28 }
29
30 pub fn read_byte(&mut self) -> Result<u8> {
31 if !self.can_read(1) {
32 return Err(SigNetError::BufferTooSmall);
33 }
34 let val = self.buffer[self.position as usize];
35 self.position += 1;
36 Ok(val)
37 }
38
39 pub fn read_u16(&mut self) -> Result<u16> {
40 if !self.can_read(2) {
41 return Err(SigNetError::BufferTooSmall);
42 }
43 let val = u16::from_be_bytes([
44 self.buffer[self.position as usize],
45 self.buffer[(self.position + 1) as usize],
46 ]);
47 self.position += 2;
48 Ok(val)
49 }
50
51 pub fn read_u32(&mut self) -> Result<u32> {
52 if !self.can_read(4) {
53 return Err(SigNetError::BufferTooSmall);
54 }
55 let val = u32::from_be_bytes([
56 self.buffer[self.position as usize],
57 self.buffer[(self.position + 1) as usize],
58 self.buffer[(self.position + 2) as usize],
59 self.buffer[(self.position + 3) as usize],
60 ]);
61 self.position += 4;
62 Ok(val)
63 }
64
65 pub fn read_bytes(&mut self, dest: &mut [u8]) -> Result<()> {
66 let count = dest.len() as u16;
67 if !self.can_read(count) {
68 return Err(SigNetError::BufferTooSmall);
69 }
70 let start = self.position as usize;
71 dest.copy_from_slice(&self.buffer[start..start + count as usize]);
72 self.position += count;
73 Ok(())
74 }
75
76 pub fn skip(&mut self, count: u16) -> Result<()> {
77 if !self.can_read(count) {
78 return Err(SigNetError::BufferTooSmall);
79 }
80 self.position += count;
81 Ok(())
82 }
83
84 pub fn peek_byte(&self) -> Result<u8> {
85 if !self.can_read(1) {
86 return Err(SigNetError::BufferTooSmall);
87 }
88 Ok(self.buffer[self.position as usize])
89 }
90
91 pub fn current_ptr(&self) -> &'a [u8] {
92 &self.buffer[self.position as usize..]
93 }
94
95 pub fn parse_coap_header(&mut self) -> Result<CoAPHeader> {
96 if !self.can_read(CoAPHeader::SIZE as u16) {
97 return Err(SigNetError::BufferTooSmall);
98 }
99 let mut bytes = [0u8; 4];
100 bytes.copy_from_slice(&self.buffer[self.position as usize..self.position as usize + 4]);
101 self.position += 4;
102 Ok(CoAPHeader::from_bytes(&bytes))
103 }
104
105 pub fn skip_token(&mut self, token_length: u8) -> Result<()> {
106 self.skip(token_length as u16)
107 }
108
109 pub fn parse_coap_option(&mut self) -> Result<(u16, u16, &'a [u8])> {
111 let nibble = self.read_byte()?;
112 let delta_nib = nibble >> 4;
113 let len_nib = nibble & 0x0F;
114
115 let delta = match delta_nib {
116 0..=12 => delta_nib as u16,
117 13 => COAP_OPTION_EXT8_BASE + self.read_byte()? as u16,
118 14 => COAP_OPTION_EXT16_BASE + self.read_u16()?,
119 _ => return Err(SigNetError::InvalidOption),
120 };
121
122 let length = match len_nib {
123 0..=12 => len_nib as u16,
124 13 => COAP_OPTION_EXT8_BASE + self.read_byte()? as u16,
125 14 => COAP_OPTION_EXT16_BASE + self.read_u16()?,
126 _ => return Err(SigNetError::InvalidOption),
127 };
128
129 if !self.can_read(length) {
130 return Err(SigNetError::BufferTooSmall);
131 }
132 let start = self.position as usize;
133 self.skip(length)?;
134 let value = &self.buffer[start..start + length as usize];
135
136 Ok((delta, length, value))
137 }
138
139 pub fn parse_signet_options(&mut self) -> Result<SigNetOptions> {
143 let mut options = SigNetOptions::default();
144 let mut prev_option: u16 = 0;
145 let mut seen_hmac = false;
146
147 loop {
148 if !self.can_read(1) {
149 break;
150 }
151 let peek = self.peek_byte()?;
152 if peek == COAP_PAYLOAD_MARKER {
153 self.read_byte()?; break;
155 }
156
157 let (delta, _len, value) = self.parse_coap_option()?;
158 let opt_num = prev_option + delta;
159 prev_option = opt_num;
160
161 if Self::apply_option(&mut options, opt_num, value) {
162 seen_hmac = true;
163 }
164 }
165
166 if !seen_hmac {
167 return Err(SigNetError::InvalidOption);
168 }
169
170 Ok(options)
171 }
172
173 fn apply_option(options: &mut SigNetOptions, opt_num: u16, value: &[u8]) -> bool {
174 match opt_num {
175 SIGNET_OPTION_SECURITY_MODE => {
176 if !value.is_empty() {
177 options.security_mode = value[0];
178 }
179 false
180 }
181 SIGNET_OPTION_SENDER_ID => {
182 let len = value.len().min(SENDER_ID_LENGTH);
183 options.sender_id[..len].copy_from_slice(&value[..len]);
184 false
185 }
186 SIGNET_OPTION_MFG_CODE => {
187 if value.len() >= 2 {
188 options.mfg_code = u16::from_be_bytes([value[0], value[1]]);
189 }
190 false
191 }
192 SIGNET_OPTION_SESSION_ID => {
193 if value.len() >= 4 {
194 options.session_id =
195 u32::from_be_bytes([value[0], value[1], value[2], value[3]]);
196 }
197 false
198 }
199 SIGNET_OPTION_SEQ_NUM => {
200 if value.len() >= 4 {
201 options.seq_num =
202 u32::from_be_bytes([value[0], value[1], value[2], value[3]]);
203 }
204 false
205 }
206 SIGNET_OPTION_HMAC => {
207 let len = value.len().min(HMAC_SHA256_LENGTH);
208 options.hmac[..len].copy_from_slice(&value[..len]);
209 true
210 }
211 _ => false,
212 }
213 }
214
215 pub fn parse_tlv_block(&mut self) -> Result<TLVBlock<'a>> {
216 let type_id = self.read_u16()?;
217 let length = self.read_u16()?;
218 let start = self.position as usize;
219 self.skip(length)?;
220 Ok(TLVBlock {
221 type_id,
222 value: &self.buffer[start..start + length as usize],
223 })
224 }
225
226 pub fn extract_uri_string(&mut self, uri_string: &mut [u8]) -> Result<usize> {
227 let mut prev_option: u16 = 0;
228 let mut pos = 0;
229
230 loop {
231 if !self.can_read(1) {
232 break;
233 }
234 let peek = self.peek_byte()?;
235 if peek == COAP_PAYLOAD_MARKER || peek == 0 {
236 break;
237 }
238
239 let (delta, _len, value) = self.parse_coap_option()?;
240 let opt_num = prev_option + delta;
241 prev_option = opt_num;
242
243 if opt_num == COAP_OPTION_URI_PATH {
244 if pos < uri_string.len() {
245 uri_string[pos] = b'/';
246 pos += 1;
247 }
248 if pos + value.len() <= uri_string.len() {
249 uri_string[pos..pos + value.len()].copy_from_slice(value);
250 pos += value.len();
251 } else {
252 return Err(SigNetError::BufferTooSmall);
253 }
254 }
255 }
256
257 Ok(pos)
258 }
259}
260
261pub fn parse_tid_level(tlv: &TLVBlock, dmx_data: &mut [u8]) -> Result<u16> {
262 if tlv.type_id != TID_LEVEL {
263 return Err(SigNetError::InvalidArgument);
264 }
265 if tlv.value.len() > MAX_DMX_SLOTS as usize {
266 return Err(SigNetError::InvalidPacket);
267 }
268 dmx_data[..tlv.value.len()].copy_from_slice(tlv.value);
269 Ok(tlv.value.len() as u16)
270}
271
272pub fn parse_tid_timecode(tlv: &TLVBlock) -> Result<(u8, u8, u8, u8, u8)> {
274 if tlv.type_id != TID_TIMECODE {
275 return Err(SigNetError::InvalidArgument);
276 }
277 if tlv.value.len() != 5 {
278 return Err(SigNetError::InvalidPacket);
279 }
280 Ok((tlv.value[0], tlv.value[1], tlv.value[2], tlv.value[3], tlv.value[4]))
281}
282
283pub fn parse_tid_universe(tlv: &TLVBlock) -> Result<(u16, u8, [u8; 4])> {
285 if tlv.type_id != TID_UNIVERSE {
286 return Err(SigNetError::InvalidArgument);
287 }
288 if tlv.value.len() != 7 {
289 return Err(SigNetError::InvalidPacket);
290 }
291 let universe = u16::from_be_bytes([tlv.value[0], tlv.value[1]]);
292 let command = tlv.value[2];
293 let mut ip = [0u8; 4];
294 ip.copy_from_slice(&tlv.value[3..7]);
295 Ok((universe, command, ip))
296}
297
298pub fn parse_hex_bytes(text: &[u8], out_bytes: &mut [u8], byte_count: u16) -> Result<()> {
299 let text = if text.starts_with(b"0x") || text.starts_with(b"0X") {
300 &text[2..]
301 } else {
302 text
303 };
304 let mut stack_buf = [0u8; 70];
306 let mut stack_len = 0usize;
307 for &b in text {
308 if !b.is_ascii_whitespace() {
309 if stack_len >= stack_buf.len() {
310 return Err(SigNetError::InvalidArgument);
311 }
312 stack_buf[stack_len] = b;
313 stack_len += 1;
314 }
315 }
316 let text = &stack_buf[..stack_len];
317 let expected = byte_count as usize * 2;
318 if text.len() != expected {
319 return Err(SigNetError::InvalidArgument);
320 }
321 for i in 0..byte_count as usize {
322 out_bytes[i] = (hex_char(text[i * 2])? << 4) | hex_char(text[i * 2 + 1])?;
323 }
324 Ok(())
325}