/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cobs-0.3.0/src/dec.rs
Line | Count | Source |
1 | | /// The [`CobsDecoder`] type is used to decode a stream of bytes to a |
2 | | /// given mutable output slice. This is often useful when heap data |
3 | | /// structures are not available, or when not all message bytes are |
4 | | /// received at a single point in time. |
5 | | #[derive(Debug)] |
6 | | pub struct CobsDecoder<'a> { |
7 | | /// Destination slice for decoded message |
8 | | dest: &'a mut [u8], |
9 | | |
10 | | /// Index of next byte to write in `dest` |
11 | | dest_idx: usize, |
12 | | |
13 | | /// Decoder state as an enum |
14 | | state: DecoderState, |
15 | | } |
16 | | |
17 | | /// The [`DecoderState`] is used to track the current state of a |
18 | | /// streaming decoder. This struct does not contain the output buffer |
19 | | /// (or a reference to one), and can be used when streaming the decoded |
20 | | /// output to a custom data type. |
21 | | #[derive(Debug)] |
22 | | pub enum DecoderState { |
23 | | /// State machine has not received any non-zero bytes |
24 | | Idle, |
25 | | |
26 | | /// 1-254 bytes, can be header or 00 |
27 | | Grab(u8), |
28 | | |
29 | | /// 255 bytes, will be a header next |
30 | | GrabChain(u8), |
31 | | } |
32 | | |
33 | 0 | fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), DecodeError> { |
34 | 0 | *to.get_mut(idx).ok_or(DecodeError::TargetBufTooSmall)? = data; |
35 | 0 | Ok(()) |
36 | 0 | } |
37 | | |
38 | | /// [`DecodeResult`] represents the possible non-error outcomes of |
39 | | /// pushing an encoded data byte into the [`DecoderState`] state machine |
40 | | pub enum DecodeResult { |
41 | | /// The given input byte did not prompt an output byte, either because the |
42 | | /// state machine is still idle, or we have just processed a header byte. |
43 | | /// More data is needed to complete the message. |
44 | | NoData, |
45 | | |
46 | | /// We have received a complete and well-encoded COBS message. The |
47 | | /// contents of the associated output buffer may now be used |
48 | | DataComplete, |
49 | | |
50 | | /// The following byte should be appended to the current end of the decoded |
51 | | /// output buffer. |
52 | | /// More data is needed to complete the message. |
53 | | DataContinue(u8), |
54 | | } |
55 | | |
56 | | #[derive(Debug, PartialEq, Eq, thiserror::Error)] |
57 | | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
58 | | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
59 | | pub enum DecodeError { |
60 | | #[error("empty input frame")] |
61 | | EmptyFrame, |
62 | | #[error("frame with invalid format, written {decoded_bytes:?} to decoded buffer")] |
63 | | InvalidFrame { |
64 | | /// Number of bytes written to the decoded buffer. |
65 | | decoded_bytes: usize, |
66 | | }, |
67 | | #[error("target buffer too small")] |
68 | | TargetBufTooSmall, |
69 | | } |
70 | | |
71 | | impl DecoderState { |
72 | | /// Push a single encoded byte into the state machine. If the input was |
73 | | /// unexpected, such as an early end of a framed message segment, an Error will |
74 | | /// be returned, and the current associated output buffer contents should be discarded. |
75 | | /// |
76 | | /// If a complete message is indicated, the decoding state machine will automatically |
77 | | /// reset itself to the Idle state, and may be used to begin decoding another message. |
78 | | /// |
79 | | /// NOTE: Sentinel value must be included in the input to this function for the |
80 | | /// decoding to complete |
81 | 0 | pub fn feed(&mut self, data: u8) -> Result<DecodeResult, DecodeError> { |
82 | | use DecodeResult::*; |
83 | | use DecoderState::*; |
84 | 0 | let (ret, state) = match (&self, data) { |
85 | | // Currently Idle, received a terminator, ignore, stay idle |
86 | 0 | (Idle, 0x00) => (Ok(NoData), Idle), |
87 | | |
88 | | // Currently Idle, received a byte indicating the |
89 | | // next 255 bytes have no zeroes, so we will have 254 unmodified |
90 | | // data bytes, then an overhead byte |
91 | 0 | (Idle, 0xFF) => (Ok(NoData), GrabChain(0xFE)), |
92 | | |
93 | | // Currently Idle, received a byte indicating there will be a |
94 | | // zero that must be modified in the next 1..=254 bytes |
95 | 0 | (Idle, n) => (Ok(NoData), Grab(n - 1)), |
96 | | |
97 | | // We have reached the end of a data run indicated by an overhead |
98 | | // byte, AND we have recieved the message terminator. This was a |
99 | | // well framed message! |
100 | 0 | (Grab(0), 0x00) => (Ok(DataComplete), Idle), |
101 | | |
102 | | // We have reached the end of a data run indicated by an overhead |
103 | | // byte, and the next segment of 254 bytes will have no modified |
104 | | // sentinel bytes |
105 | 0 | (Grab(0), 0xFF) => (Ok(DataContinue(0)), GrabChain(0xFE)), |
106 | | |
107 | | // We have reached the end of a data run indicated by an overhead |
108 | | // byte, and we will treat this byte as a modified sentinel byte. |
109 | | // place the sentinel byte in the output, and begin processing the |
110 | | // next non-sentinel sequence |
111 | 0 | (Grab(0), n) => (Ok(DataContinue(0)), Grab(n - 1)), |
112 | | |
113 | | // We were not expecting the sequence to terminate, but here we are. |
114 | | // Report an error due to early terminated message |
115 | 0 | (Grab(_), 0) => (Err(DecodeError::InvalidFrame { decoded_bytes: 0 }), Idle), |
116 | | |
117 | | // We have not yet reached the end of a data run, decrement the run |
118 | | // counter, and place the byte into the decoded output |
119 | 0 | (Grab(i), n) => (Ok(DataContinue(n)), Grab(*i - 1)), |
120 | | |
121 | | // We have reached the end of a data run indicated by an overhead |
122 | | // byte, AND we have recieved the message terminator. This was a |
123 | | // well framed message! |
124 | 0 | (GrabChain(0), 0x00) => (Ok(DataComplete), Idle), |
125 | | |
126 | | // We have reached the end of a data run, and we will begin another |
127 | | // data run with an overhead byte expected at the end |
128 | 0 | (GrabChain(0), 0xFF) => (Ok(NoData), GrabChain(0xFE)), |
129 | | |
130 | | // We have reached the end of a data run, and we will expect `n` data |
131 | | // bytes unmodified, followed by a sentinel byte that must be modified |
132 | 0 | (GrabChain(0), n) => (Ok(NoData), Grab(n - 1)), |
133 | | |
134 | | // We were not expecting the sequence to terminate, but here we are. |
135 | | // Report an error due to early terminated message |
136 | 0 | (GrabChain(_), 0) => (Err(DecodeError::InvalidFrame { decoded_bytes: 0 }), Idle), |
137 | | |
138 | | // We have not yet reached the end of a data run, decrement the run |
139 | | // counter, and place the byte into the decoded output |
140 | 0 | (GrabChain(i), n) => (Ok(DataContinue(n)), GrabChain(*i - 1)), |
141 | | }; |
142 | | |
143 | 0 | *self = state; |
144 | 0 | ret |
145 | 0 | } |
146 | | } |
147 | | |
148 | | impl<'a> CobsDecoder<'a> { |
149 | | /// Create a new streaming Cobs Decoder. Provide the output buffer |
150 | | /// for the decoded message to be placed in |
151 | 0 | pub fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> { |
152 | 0 | CobsDecoder { |
153 | 0 | dest, |
154 | 0 | dest_idx: 0, |
155 | 0 | state: DecoderState::Idle, |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | | /// Push a single byte into the streaming CobsDecoder. Return values mean: |
160 | | /// |
161 | | /// * Ok(None) - State machine okay, more data needed |
162 | | /// * Ok(Some(N)) - A message of N bytes was successfully decoded |
163 | | /// * Err([DecodeError]) - Message decoding failed |
164 | | /// |
165 | | /// NOTE: Sentinel value must be included in the input to this function for the |
166 | | /// decoding to complete |
167 | 0 | pub fn feed(&mut self, data: u8) -> Result<Option<usize>, DecodeError> { |
168 | 0 | match self.state.feed(data) { |
169 | 0 | Err(_) => Err(DecodeError::InvalidFrame { |
170 | 0 | decoded_bytes: self.dest_idx, |
171 | 0 | }), |
172 | 0 | Ok(DecodeResult::NoData) => Ok(None), |
173 | 0 | Ok(DecodeResult::DataContinue(n)) => { |
174 | 0 | add(self.dest, self.dest_idx, n)?; |
175 | 0 | self.dest_idx += 1; |
176 | 0 | Ok(None) |
177 | | } |
178 | 0 | Ok(DecodeResult::DataComplete) => Ok(Some(self.dest_idx)), |
179 | | } |
180 | 0 | } |
181 | | |
182 | | /// Push a slice of bytes into the streaming CobsDecoder. Return values mean: |
183 | | /// |
184 | | /// * Ok(None) - State machine okay, more data needed |
185 | | /// * Ok(Some((N, M))) - A message of N bytes was successfully decoded, |
186 | | /// using M bytes from `data` (and earlier data) |
187 | | /// * Err([DecodeError]) - Message decoding failed |
188 | | /// |
189 | | /// NOTE: Sentinel value must be included in the input to this function for the |
190 | | /// decoding to complete |
191 | 0 | pub fn push(&mut self, data: &[u8]) -> Result<Option<(usize, usize)>, DecodeError> { |
192 | 0 | for (consumed_idx, d) in data.iter().enumerate() { |
193 | 0 | let opt_decoded_bytes = self.feed(*d)?; |
194 | 0 | if let Some(decoded_bytes_ct) = opt_decoded_bytes { |
195 | | // convert from index to number of bytes consumed |
196 | 0 | return Ok(Some((decoded_bytes_ct, consumed_idx + 1))); |
197 | 0 | } |
198 | | } |
199 | | |
200 | 0 | Ok(None) |
201 | 0 | } |
202 | | } |
203 | | |
204 | | /// Decodes the `source` buffer into the `dest` buffer. |
205 | | /// |
206 | | /// This function uses the typical sentinel value of 0. |
207 | | /// |
208 | | /// # Failures |
209 | | /// |
210 | | /// This will return `Err(())` if there was a decoding error. Otherwise, |
211 | | /// it will return `Ok(n)` where `n` is the length of the decoded message. |
212 | 0 | pub fn decode(source: &[u8], dest: &mut [u8]) -> Result<usize, DecodeError> { |
213 | 0 | if source.is_empty() { |
214 | 0 | return Err(DecodeError::EmptyFrame); |
215 | 0 | } |
216 | | |
217 | 0 | let mut dec = CobsDecoder::new(dest); |
218 | | |
219 | | // Did we decode a message, using some or all of the buffer? |
220 | 0 | if let Some((d_used, _s_used)) = dec.push(source)? { |
221 | 0 | return Ok(d_used); |
222 | 0 | } |
223 | | |
224 | | // If we consumed the entire buffer, but did NOT get a message, |
225 | | // AND the message did not end with a zero, try providing one to |
226 | | // complete the decoding. |
227 | 0 | if source.last() != Some(&0) { |
228 | | // Explicitly push sentinel of zero |
229 | 0 | if let Some((d_used, _s_used)) = dec.push(&[0])? { |
230 | 0 | return Ok(d_used); |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | // Nope, no early message, no missing terminator, just failed to decode |
235 | 0 | Err(DecodeError::InvalidFrame { |
236 | 0 | decoded_bytes: dec.dest_idx, |
237 | 0 | }) |
238 | 0 | } |
239 | | |
240 | | /// A report of the source and destination bytes used during in-place decoding |
241 | | #[derive(Debug, Copy, Clone)] |
242 | | #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
243 | | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
244 | | pub struct DecodeReport { |
245 | | // The number of source bytes used, NOT INCLUDING the sentinel byte, |
246 | | // if there was one. |
247 | | pub src_used: usize, |
248 | | |
249 | | // The number of bytes of the source buffer that now include the |
250 | | // decoded result |
251 | | pub dst_used: usize, |
252 | | } |
253 | | |
254 | | /// Decodes a message in-place. |
255 | | /// |
256 | | /// This is the same function as [decode_in_place], but provides a report |
257 | | /// of both the number of source bytes consumed as well as the size of the |
258 | | /// destination used. |
259 | 0 | pub fn decode_in_place_report(buf: &mut [u8]) -> Result<DecodeReport, DecodeError> { |
260 | 0 | let mut source_index = 0; |
261 | 0 | let mut dest_index = 0; |
262 | | |
263 | 0 | if buf.is_empty() { |
264 | 0 | return Err(DecodeError::EmptyFrame); |
265 | 0 | } |
266 | | |
267 | | // Stop at the first terminator, if any |
268 | 0 | let src_end = if let Some(end) = buf.iter().position(|b| *b == 0) { |
269 | 0 | end |
270 | | } else { |
271 | 0 | buf.len() |
272 | | }; |
273 | | |
274 | 0 | while source_index < src_end { |
275 | 0 | let code = buf[source_index]; |
276 | | |
277 | 0 | if source_index + code as usize > src_end && code != 1 { |
278 | 0 | return Err(DecodeError::InvalidFrame { |
279 | 0 | decoded_bytes: dest_index, |
280 | 0 | }); |
281 | 0 | } |
282 | | |
283 | 0 | source_index += 1; |
284 | | |
285 | 0 | for _ in 1..code { |
286 | 0 | *buf.get_mut(dest_index) |
287 | 0 | .ok_or(DecodeError::TargetBufTooSmall)? = buf[source_index]; |
288 | 0 | source_index += 1; |
289 | 0 | dest_index += 1; |
290 | | } |
291 | | |
292 | 0 | if 0xFF != code && source_index < src_end { |
293 | 0 | *buf.get_mut(dest_index) |
294 | 0 | .ok_or(DecodeError::TargetBufTooSmall)? = 0; |
295 | 0 | dest_index += 1; |
296 | 0 | } |
297 | | } |
298 | | |
299 | 0 | Ok(DecodeReport { |
300 | 0 | dst_used: dest_index, |
301 | 0 | src_used: source_index, |
302 | 0 | }) |
303 | 0 | } |
304 | | |
305 | | /// Decodes a message in-place. |
306 | | /// |
307 | | /// This is the same function as [decode], but replaces the encoded message |
308 | | /// with the decoded message instead of writing to another buffer. |
309 | | /// |
310 | | /// The returned `usize` is the number of bytes used for the DECODED value, |
311 | | /// NOT the number of source bytes consumed during decoding. |
312 | 0 | pub fn decode_in_place(buff: &mut [u8]) -> Result<usize, DecodeError> { |
313 | 0 | decode_in_place_report(buff).map(|r| r.dst_used) |
314 | 0 | } |
315 | | |
316 | | /// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value. |
317 | | /// |
318 | | /// This is done by XOR-ing each byte of the source message with the chosen sentinel value, |
319 | | /// which transforms the message into the same message encoded with a sentinel value of 0. |
320 | | /// Then the regular decoding transformation is performed. |
321 | | /// |
322 | | /// The returned `usize` is the number of bytes used for the DECODED value, |
323 | | /// NOT the number of source bytes consumed during decoding. |
324 | 0 | pub fn decode_with_sentinel( |
325 | 0 | source: &[u8], |
326 | 0 | dest: &mut [u8], |
327 | 0 | sentinel: u8, |
328 | 0 | ) -> Result<usize, DecodeError> { |
329 | 0 | for (x, y) in source.iter().zip(dest.iter_mut()) { |
330 | 0 | *y = *x ^ sentinel; |
331 | 0 | } |
332 | 0 | decode_in_place(dest) |
333 | 0 | } |
334 | | |
335 | | /// Decodes a message in-place using an arbitrary sentinel value. |
336 | | /// |
337 | | /// The returned `usize` is the number of bytes used for the DECODED value, |
338 | | /// NOT the number of source bytes consumed during decoding. |
339 | 0 | pub fn decode_in_place_with_sentinel(buff: &mut [u8], sentinel: u8) -> Result<usize, DecodeError> { |
340 | 0 | for x in buff.iter_mut() { |
341 | 0 | *x ^= sentinel; |
342 | 0 | } |
343 | 0 | decode_in_place(buff) |
344 | 0 | } |
345 | | |
346 | | #[cfg(feature = "alloc")] |
347 | | /// Decodes the `source` buffer into a vector. |
348 | | pub fn decode_vec(source: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> { |
349 | | let mut decoded = alloc::vec![0; source.len()]; |
350 | | let n = decode(source, &mut decoded[..])?; |
351 | | decoded.truncate(n); |
352 | | Ok(decoded) |
353 | | } |
354 | | |
355 | | #[cfg(feature = "alloc")] |
356 | | /// Decodes the `source` buffer into a vector with an arbitrary sentinel value. |
357 | | pub fn decode_vec_with_sentinel( |
358 | | source: &[u8], |
359 | | sentinel: u8, |
360 | | ) -> Result<alloc::vec::Vec<u8>, DecodeError> { |
361 | | let mut decoded = alloc::vec![0; source.len()]; |
362 | | let n = decode_with_sentinel(source, &mut decoded[..], sentinel)?; |
363 | | decoded.truncate(n); |
364 | | Ok(decoded) |
365 | | } |
366 | | |
367 | | #[cfg(test)] |
368 | | mod tests { |
369 | | |
370 | | use super::*; |
371 | | |
372 | | #[test] |
373 | | fn decode_malforemd() { |
374 | | let malformed_buf: [u8; 32] = [ |
375 | | 68, 69, 65, 68, 66, 69, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
376 | | 0, 0, 0, 0, 0, 0, |
377 | | ]; |
378 | | let mut dest_buf: [u8; 32] = [0; 32]; |
379 | | if let Err(DecodeError::InvalidFrame { decoded_bytes }) = |
380 | | decode(&malformed_buf, &mut dest_buf) |
381 | | { |
382 | | assert_eq!(decoded_bytes, 7); |
383 | | } else { |
384 | | panic!("decoding worked when it should not have"); |
385 | | } |
386 | | } |
387 | | |
388 | | #[test] |
389 | | fn decode_empty() { |
390 | | #[cfg(feature = "alloc")] |
391 | | matches!(decode_vec(&[]).unwrap_err(), DecodeError::EmptyFrame); |
392 | | matches!( |
393 | | decode_in_place(&mut []).unwrap_err(), |
394 | | DecodeError::EmptyFrame |
395 | | ); |
396 | | matches!( |
397 | | decode(&[], &mut [0; 256]).unwrap_err(), |
398 | | DecodeError::EmptyFrame |
399 | | ); |
400 | | } |
401 | | |
402 | | #[test] |
403 | | #[cfg(feature = "alloc")] |
404 | | fn decode_target_buf_too_small() { |
405 | | let encoded = &[3, 10, 11, 2, 12]; |
406 | | let expected_decoded_len = 4; |
407 | | for i in 0..expected_decoded_len - 1 { |
408 | | let mut dest = alloc::vec![0; i]; |
409 | | let result = decode(encoded, &mut dest); |
410 | | assert_eq!(result, Err(DecodeError::TargetBufTooSmall)); |
411 | | } |
412 | | } |
413 | | } |