rzcobs/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2
3/// Write trait to use with Encoder
4pub trait Write {
5    type Error;
6
7    /// Write a single byte.
8    fn write(&mut self, byte: u8) -> Result<(), Self::Error>;
9}
10
11/// Streaming encoder
12///
13/// Allows encoding of reverse-COBS messages in a streaming fashion, with almost
14/// no memory usage (internal state is just one single byte!).
15///
16/// To encode a message, call [write](Self::write) for each byte in the message, then call [end](Self::end).
17///
18/// You may use the same Encoder instance to encode multiple messages. In this case, you
19/// will probably want to separate messages with a `0x00`, which you have to write manually
20/// after calling [end](Self::end), for example with `encoder.writer().write(0)`.
21pub struct Encoder<W> {
22    w: W,
23    run: u8,
24    zeros: u8,
25}
26
27// Standard COBS/rCOBS:
28//   00000000 => end of frame
29//   nnnnnnnn => output n-1 bytes from stream, output 0x00
30//   11111111 => output 254 bytes from stream
31//
32// zCOBS/rzCOBS:
33//   00000000 => end of frame
34//   0xxxxxxx => foreach x from LSB to MSB: if x=0 output 1 byte from stream, if x=1 output 0x00
35//   1nnnnnnn => output n+7 bytes from stream, output 0x00
36//   11111111 => output 134 bytes from stream
37
38impl<W> Encoder<W> {
39    /// Create a new encoder with the given writer.
40    pub const fn new(w: W) -> Self {
41        Self {
42            w,
43            run: 0,
44            zeros: 0,
45        }
46    }
47
48    /// Mutably borrow the inner writer.
49    pub fn writer(&mut self) -> &mut W {
50        &mut self.w
51    }
52}
53
54impl<W: Write> Encoder<W> {
55
56    /// Write a message byte.
57    pub fn write(&mut self, byte: u8) -> Result<(), W::Error> {
58        if self.run < 7 {
59            if byte == 0 {
60                self.zeros |= 1 << self.run;
61            } else {
62                self.w.write(byte)?;
63            }
64
65            self.run += 1;
66            if self.run == 7 && self.zeros != 0x00 {
67                self.w.write(self.zeros)?;
68                self.run = 0;
69                self.zeros = 0;
70            }
71        } else if byte == 0 {
72            self.w.write((self.run - 7) | 0x80)?;
73            self.run = 0;
74            self.zeros = 0;
75        } else {
76            self.w.write(byte)?;
77            self.run += 1;
78            if self.run == 134 {
79                self.w.write(0xFF)?;
80                self.run = 0;
81                self.zeros = 0;
82            }
83        }
84        Ok(())
85    }
86
87    /// Finish encoding a message.
88    ///
89    /// This does NOT write a `0x00` separator byte, you must write it yourself
90    /// if you so desire.
91    pub fn end(&mut self) -> Result<(), W::Error> {
92        match self.run {
93            0 => {},
94            1..=6 => self.w.write((self.zeros | (0xFF << self.run)) & 0x7F)?,
95            _ => self.w.write((self.run - 7) | 0x80)?,
96        }
97        self.run = 0;
98        self.zeros = 0;
99        Ok(())
100    }
101}
102
103/// Encode a full message.
104///
105/// Encodes a single message and returns it as a `Vec`. The returned data does
106/// not include any `0x00` separator byte, you have to add it yourself.
107///
108/// This is a convenience function using [Encoder] internally. For streaming encoding, use [Encoder].
109#[cfg(feature = "std")]
110pub fn encode(data: &[u8]) -> Vec<u8> {
111    struct VecWriter<'a>(&'a mut Vec<u8>);
112
113    impl<'a> Write for VecWriter<'a> {
114        type Error = std::convert::Infallible;
115        fn write(&mut self, byte: u8) -> Result<(), Self::Error> {
116            self.0.push(byte);
117            Ok(())
118        }
119    }
120
121    let mut res = Vec::new();
122    let mut enc = Encoder::new(VecWriter(&mut res));
123    for &b in data {
124        enc.write(b).unwrap();
125    }
126    enc.end().unwrap();
127    res
128}
129
130/// Error indicating the decoded data was malformed reverse-COBS.
131#[cfg(feature = "std")]
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub struct MalformedError;
134
135/// Decode a full message.
136///
137/// `data` must be a full rzCOBS encoded message. Decoding partial
138/// messages is not possible. `data` must NOT include any `0x00` separator byte.
139#[cfg(feature = "std")]
140pub fn decode(data: &[u8]) -> Result<Vec<u8>, MalformedError> {
141    let mut res = vec![];
142    let mut data = data.iter().rev().cloned();
143    while let Some(x) = data.next() {
144        match x {
145            0 => return Err(MalformedError),
146            0x01..=0x7f => {
147                for i in 0..7 {
148                    if x & (1 << (6-i)) == 0 {
149                        res.push(data.next().ok_or(MalformedError)?);
150                    } else {
151                        res.push(0);
152                    }
153                }
154            }
155            0x80..=0xfe => {
156                let n = (x & 0x7f) + 7;
157                res.push(0);
158                for _ in 0..n {
159                    res.push(data.next().ok_or(MalformedError)?);
160                }
161            }
162            0xff => {
163                for _ in 0..134 {
164                    res.push(data.next().ok_or(MalformedError)?);
165                }
166            }
167        }
168    }
169
170    res.reverse();
171    Ok(res)
172}
173
174#[cfg(feature = "std")]
175#[cfg(test)]
176mod tests {
177    use super::*;
178    use hex_literal::hex;
179
180    #[test]
181    fn it_works() {
182        let tests: &[(&[u8], &[u8])] = &[
183            (
184                &hex!(""),
185                &hex!(""),
186            ), (
187                &hex!("00"),
188                &hex!("7f"),
189            ), (
190                &hex!("0000"),
191                &hex!("7f"),
192            ), (
193                &hex!("00000000000000"),
194                &hex!("7f"),
195            ), (
196                &hex!("0000000000000000"),
197                &hex!("7f7f"),
198            ), (
199                &hex!("01"),
200                &hex!("017e"),
201            ), (
202                &hex!("0100"),
203                &hex!("017e"),
204            ), (
205                &hex!("0001"),
206                &hex!("017d"),
207            ), (
208                &hex!("0102"),
209                &hex!("01027c"),
210            ), (
211                &hex!("11223344556600"),
212                &hex!("11223344556640"),
213            ), (
214                &hex!("11223344556677"),
215                &hex!("1122334455667780"),
216            ), (
217                &hex!("1122334455667700"),
218                &hex!("1122334455667780"),
219            ), (
220                &hex!("1122334455667788"),
221                &hex!("112233445566778881"),
222            ), (
223                &hex!("00000000000000 000000000000ff"),
224                &hex!("7f ff3f"),
225            ), (
226                &hex!("00000000004400 000000000000ff"),
227                &hex!("445f ff3f"),
228            ), (
229                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485"),
230                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485fe"),
231            ), (
232                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848500"),
233                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485fe"),
234            ), (
235                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586"),
236                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586ff"),
237            ), (
238                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f8081828384858600"),
239                &hex!("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f80818283848586ff7f"),
240            ),
241        ];
242
243        for (dec, enc) in tests {
244            assert_eq!(&encode(dec), enc);
245
246            let got = decode(enc).unwrap();
247            assert_eq!(&got[..dec.len()], *dec);
248            assert!(&got[dec.len()..].iter().all(|&x| x == 0));
249        }
250    }
251}