sk_cbor/
writer.rs

1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Functionality for serializing CBOR values into bytes.
16
17use super::values::{Constants, Value};
18use alloc::vec::Vec;
19
20/// Possible errors from a serialization operation.
21#[derive(Debug, PartialEq)]
22pub enum EncoderError {
23    TooMuchNesting,
24    DuplicateMapKey,
25}
26
27/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.
28/// Supports arbitrarily nested CBOR (so the [`EncoderError::TooMuchNesting`] error is never emitted).
29pub fn write(value: Value, encoded_cbor: &mut Vec<u8>) -> Result<(), EncoderError> {
30    write_nested(value, encoded_cbor, None)
31}
32
33/// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector.  If
34/// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning
35/// [`DecoderError::TooMuchNesting`] if the limit is hit).
36pub fn write_nested(
37    value: Value,
38    encoded_cbor: &mut Vec<u8>,
39    max_nest: Option<i8>,
40) -> Result<(), EncoderError> {
41    let mut writer = Writer::new(encoded_cbor);
42    writer.encode_cbor(value, max_nest)
43}
44
45struct Writer<'a> {
46    encoded_cbor: &'a mut Vec<u8>,
47}
48
49impl<'a> Writer<'a> {
50    pub fn new(encoded_cbor: &mut Vec<u8>) -> Writer {
51        Writer { encoded_cbor }
52    }
53
54    fn encode_cbor(
55        &mut self,
56        value: Value,
57        remaining_depth: Option<i8>,
58    ) -> Result<(), EncoderError> {
59        if remaining_depth.map_or(false, |d| d < 0) {
60            return Err(EncoderError::TooMuchNesting);
61        }
62        let type_label = value.type_label();
63        match value {
64            Value::Unsigned(unsigned) => self.start_item(type_label, unsigned),
65            Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
66            Value::ByteString(byte_string) => {
67                self.start_item(type_label, byte_string.len() as u64);
68                self.encoded_cbor.extend(byte_string);
69            }
70            Value::TextString(text_string) => {
71                self.start_item(type_label, text_string.len() as u64);
72                self.encoded_cbor.extend(text_string.into_bytes());
73            }
74            Value::Array(array) => {
75                self.start_item(type_label, array.len() as u64);
76                for el in array {
77                    self.encode_cbor(el, remaining_depth.map(|d| d - 1))?;
78                }
79            }
80            Value::Map(mut map) => {
81                map.sort_by(|a, b| a.0.cmp(&b.0));
82                let map_len = map.len();
83                map.dedup_by(|a, b| a.0.eq(&b.0));
84                if map_len != map.len() {
85                    return Err(EncoderError::DuplicateMapKey);
86                }
87                self.start_item(type_label, map_len as u64);
88                for (k, v) in map {
89                    self.encode_cbor(k, remaining_depth.map(|d| d - 1))?;
90                    self.encode_cbor(v, remaining_depth.map(|d| d - 1))?;
91                }
92            }
93            Value::Tag(tag, inner_value) => {
94                self.start_item(type_label, tag);
95                self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?;
96            }
97            Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
98        }
99        Ok(())
100    }
101
102    fn start_item(&mut self, type_label: u8, size: u64) {
103        let (mut first_byte, shift) = match size {
104            0..=23 => (size as u8, 0),
105            24..=0xFF => (Constants::ADDITIONAL_INFORMATION_1_BYTE, 1),
106            0x100..=0xFFFF => (Constants::ADDITIONAL_INFORMATION_2_BYTES, 2),
107            0x10000..=0xFFFF_FFFF => (Constants::ADDITIONAL_INFORMATION_4_BYTES, 4),
108            _ => (Constants::ADDITIONAL_INFORMATION_8_BYTES, 8),
109        };
110        first_byte |= type_label << Constants::MAJOR_TYPE_BIT_SHIFT;
111        self.encoded_cbor.push(first_byte);
112
113        for i in (0..shift).rev() {
114            self.encoded_cbor.push((size >> (i * 8)) as u8);
115        }
116    }
117}
118
119#[cfg(test)]
120mod test {
121    use super::*;
122    use crate::{
123        cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null,
124        cbor_tagged, cbor_text, cbor_true, cbor_undefined,
125    };
126    use alloc::vec;
127
128    fn write_return(value: Value) -> Option<Vec<u8>> {
129        let mut encoded_cbor = Vec::new();
130        if write(value, &mut encoded_cbor).is_ok() {
131            Some(encoded_cbor)
132        } else {
133            None
134        }
135    }
136
137    #[test]
138    fn test_write_unsigned() {
139        let cases = vec![
140            (0, vec![0x00]),
141            (1, vec![0x01]),
142            (10, vec![0x0A]),
143            (23, vec![0x17]),
144            (24, vec![0x18, 0x18]),
145            (25, vec![0x18, 0x19]),
146            (100, vec![0x18, 0x64]),
147            (1000, vec![0x19, 0x03, 0xE8]),
148            (1000000, vec![0x1A, 0x00, 0x0F, 0x42, 0x40]),
149            (0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]),
150            (
151                0x100000000,
152                vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
153            ),
154            (
155                core::i64::MAX,
156                vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
157            ),
158        ];
159        for (unsigned, correct_cbor) in cases {
160            assert_eq!(write_return(cbor_int!(unsigned)), Some(correct_cbor));
161        }
162    }
163
164    #[test]
165    fn test_write_negative() {
166        let cases = vec![
167            (-1, vec![0x20]),
168            (-10, vec![0x29]),
169            (-23, vec![0x36]),
170            (-24, vec![0x37]),
171            (-25, vec![0x38, 0x18]),
172            (-100, vec![0x38, 0x63]),
173            (-1000, vec![0x39, 0x03, 0xE7]),
174            (-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]),
175            (
176                -4294967297,
177                vec![0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00],
178            ),
179            (
180                core::i64::MIN,
181                vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
182            ),
183        ];
184        for (negative, correct_cbor) in cases {
185            assert_eq!(write_return(cbor_int!(negative)), Some(correct_cbor));
186        }
187    }
188
189    #[test]
190    fn test_write_byte_string() {
191        let cases = vec![
192            (vec![], vec![0x40]),
193            (
194                vec![0x01, 0x02, 0x03, 0x04],
195                vec![0x44, 0x01, 0x02, 0x03, 0x04],
196            ),
197        ];
198        for (byte_string, correct_cbor) in cases {
199            assert_eq!(write_return(cbor_bytes!(byte_string)), Some(correct_cbor));
200        }
201    }
202
203    #[test]
204    fn test_write_text_string() {
205        let unicode_3byte = vec![0xE6, 0xB0, 0xB4];
206        let cases = vec![
207            ("", vec![0x60]),
208            ("a", vec![0x61, 0x61]),
209            ("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]),
210            ("\"\\", vec![0x62, 0x22, 0x5C]),
211            ("ü", vec![0x62, 0xC3, 0xBC]),
212            (
213                core::str::from_utf8(&unicode_3byte).unwrap(),
214                vec![0x63, 0xE6, 0xB0, 0xB4],
215            ),
216            ("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]),
217        ];
218        for (text_string, correct_cbor) in cases {
219            assert_eq!(write_return(cbor_text!(text_string)), Some(correct_cbor));
220        }
221    }
222
223    #[test]
224    fn test_write_array() {
225        let value_vec: Vec<_> = (1..26).collect();
226        let expected_cbor = vec![
227            0x98, 0x19, // array of 25 elements
228            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
229            0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19,
230        ];
231        assert_eq!(
232            write_return(cbor_array_vec!(value_vec)),
233            Some(expected_cbor)
234        );
235    }
236
237    #[test]
238    fn test_write_map() {
239        let value_map = cbor_map! {
240            0 => "a",
241            23 => "b",
242            24 => "c",
243            core::u8::MAX as i64 => "d",
244            256 => "e",
245            core::u16::MAX as i64 => "f",
246            65536 => "g",
247            core::u32::MAX as i64 => "h",
248            4294967296_i64 => "i",
249            core::i64::MAX => "j",
250            -1 => "k",
251            -24 => "l",
252            -25 => "m",
253            -256 => "n",
254            -257 => "o",
255            -65537 => "p",
256            -4294967296_i64 => "q",
257            -4294967297_i64 => "r",
258            core::i64::MIN => "s",
259            b"a" => 2,
260            b"bar" => 3,
261            b"foo" => 4,
262            "" => ".",
263            "e" => "E",
264            "aa" => "AA",
265        };
266        let expected_cbor = vec![
267            0xb8, 0x19, // map of 25 pairs:
268            0x00, // key 0
269            0x61, 0x61, // value "a"
270            0x17, // key 23
271            0x61, 0x62, // value "b"
272            0x18, 0x18, // key 24
273            0x61, 0x63, // value "c"
274            0x18, 0xFF, // key 255
275            0x61, 0x64, // value "d"
276            0x19, 0x01, 0x00, // key 256
277            0x61, 0x65, // value "e"
278            0x19, 0xFF, 0xFF, // key 65535
279            0x61, 0x66, // value "f"
280            0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536
281            0x61, 0x67, // value "g"
282            0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295
283            0x61, 0x68, // value "h"
284            // key 4294967296
285            0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x69, //  value "i"
286            // key INT64_MAX
287            0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x6a, //  value "j"
288            0x20, // key -1
289            0x61, 0x6b, // value "k"
290            0x37, // key -24
291            0x61, 0x6c, // value "l"
292            0x38, 0x18, // key -25
293            0x61, 0x6d, // value "m"
294            0x38, 0xFF, // key -256
295            0x61, 0x6e, // value "n"
296            0x39, 0x01, 0x00, // key -257
297            0x61, 0x6f, // value "o"
298            0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537
299            0x61, 0x70, // value "p"
300            0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296
301            0x61, 0x71, // value "q"
302            // key -4294967297
303            0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x72, //  value "r"
304            // key INT64_MIN
305            0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x73, //  value "s"
306            0x41, b'a', // byte string "a"
307            0x02, 0x43, b'b', b'a', b'r', // byte string "bar"
308            0x03, 0x43, b'f', b'o', b'o', // byte string "foo"
309            0x04, 0x60, // key ""
310            0x61, 0x2e, // value "."
311            0x61, 0x65, // key "e"
312            0x61, 0x45, // value "E"
313            0x62, 0x61, 0x61, // key "aa"
314            0x62, 0x41, 0x41, // value "AA"
315        ];
316        assert_eq!(write_return(value_map), Some(expected_cbor));
317    }
318
319    #[test]
320    fn test_write_map_sorted() {
321        let sorted_map = cbor_map! {
322            0 => "a",
323            1 => "b",
324            -1 => "c",
325            -2 => "d",
326            b"a" => "e",
327            b"b" => "f",
328            "" => "g",
329            "c" => "h",
330        };
331        let unsorted_map = cbor_map! {
332            1 => "b",
333            -2 => "d",
334            b"b" => "f",
335            "c" => "h",
336            "" => "g",
337            b"a" => "e",
338            -1 => "c",
339            0 => "a",
340        };
341        assert_eq!(write_return(sorted_map), write_return(unsorted_map));
342    }
343
344    #[test]
345    fn test_write_map_duplicates() {
346        let duplicate0 = cbor_map! {
347            0 => "a",
348            -1 => "c",
349            b"a" => "e",
350            "c" => "g",
351            0 => "b",
352        };
353        assert_eq!(write_return(duplicate0), None);
354        let duplicate1 = cbor_map! {
355            0 => "a",
356            -1 => "c",
357            b"a" => "e",
358            "c" => "g",
359            -1 => "d",
360        };
361        assert_eq!(write_return(duplicate1), None);
362        let duplicate2 = cbor_map! {
363            0 => "a",
364            -1 => "c",
365            b"a" => "e",
366            "c" => "g",
367            b"a" => "f",
368        };
369        assert_eq!(write_return(duplicate2), None);
370        let duplicate3 = cbor_map! {
371            0 => "a",
372            -1 => "c",
373            b"a" => "e",
374            "c" => "g",
375            "c" => "h",
376        };
377        assert_eq!(write_return(duplicate3), None);
378    }
379
380    #[test]
381    fn test_write_map_with_array() {
382        let value_map = cbor_map! {
383            "a" => 1,
384            "b" => cbor_array![2, 3],
385        };
386        let expected_cbor = vec![
387            0xa2, // map of 2 pairs
388            0x61, 0x61, // "a"
389            0x01, 0x61, 0x62, // "b"
390            0x82, // array with 2 elements
391            0x02, 0x03,
392        ];
393        assert_eq!(write_return(value_map), Some(expected_cbor));
394    }
395
396    #[test]
397    fn test_write_nested_map() {
398        let value_map = cbor_map! {
399            "a" => 1,
400            "b" => cbor_map! {
401                "c" => 2,
402                "d" => 3,
403            },
404        };
405        let expected_cbor = vec![
406            0xa2, // map of 2 pairs
407            0x61, 0x61, // "a"
408            0x01, 0x61, 0x62, // "b"
409            0xa2, // map of 2 pairs
410            0x61, 0x63, // "c"
411            0x02, 0x61, 0x64, // "d"
412            0x03,
413        ];
414        assert_eq!(write_return(value_map), Some(expected_cbor));
415    }
416
417    #[test]
418    fn test_write_tagged() {
419        let cases = vec![
420            (cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
421            (cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
422            (
423                cbor_tagged!(
424                    1000,
425                    cbor_map! {
426                        "a" => 1,
427                        "b" => cbor_array![2, 3],
428                    }
429                ),
430                vec![
431                    0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
432                    0x61, 0x61, // "a"
433                    0x01, 0x61, 0x62, // "b"
434                    0x82, // array with 2 elements
435                    0x02, 0x03,
436                ],
437            ),
438        ];
439        for (value, correct_cbor) in cases {
440            assert_eq!(write_return(value), Some(correct_cbor));
441        }
442    }
443
444    #[test]
445    fn test_write_simple() {
446        let cases = vec![
447            (cbor_false!(), vec![0xF4]),
448            (cbor_true!(), vec![0xF5]),
449            (cbor_null!(), vec![0xF6]),
450            (cbor_undefined!(), vec![0xF7]),
451        ];
452        for (value, correct_cbor) in cases {
453            assert_eq!(write_return(value), Some(correct_cbor));
454        }
455    }
456
457    #[test]
458    fn test_write_single_levels() {
459        let simple_array: Value = cbor_array![2];
460        let simple_map: Value = cbor_map! {"b" => 3};
461        let positive_cases = vec![
462            (cbor_int!(1), 0),
463            (cbor_bytes!(vec![0x01, 0x02, 0x03, 0x04]), 0),
464            (cbor_text!("a"), 0),
465            (cbor_array![], 0),
466            (cbor_map! {}, 0),
467            (simple_array.clone(), 1),
468            (simple_map.clone(), 1),
469        ];
470        let negative_cases = vec![(simple_array.clone(), 0), (simple_map.clone(), 0)];
471        for (value, level) in positive_cases {
472            let mut buf = Vec::new();
473            let mut writer = Writer::new(&mut buf);
474            assert!(writer.encode_cbor(value, Some(level)).is_ok());
475        }
476        for (value, level) in negative_cases {
477            let mut buf = Vec::new();
478            let mut writer = Writer::new(&mut buf);
479            assert!(!writer.encode_cbor(value, Some(level)).is_ok());
480        }
481    }
482
483    #[test]
484    fn test_write_nested_map_levels() {
485        let cbor_map: Value = cbor_map! {
486            "a" => 1,
487            "b" => cbor_map! {
488                "c" => 2,
489                "d" => 3,
490            },
491        };
492
493        let mut buf = Vec::new();
494        let mut writer = Writer::new(&mut buf);
495        assert!(writer.encode_cbor(cbor_map.clone(), Some(2)).is_ok());
496        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
497        writer = Writer::new(&mut buf);
498        assert!(writer.encode_cbor(cbor_map, Some(1)).is_err());
499    }
500
501    #[test]
502    fn test_write_unbalanced_nested_containers() {
503        let cbor_array: Value = cbor_array![
504            1,
505            2,
506            3,
507            cbor_map! {
508                "a" => 1,
509                "b" => cbor_map! {
510                    "c" => 2,
511                    "d" => 3,
512                },
513            },
514        ];
515
516        let mut buf = Vec::new();
517        let mut writer = Writer::new(&mut buf);
518        assert!(writer.encode_cbor(cbor_array.clone(), Some(3)).is_ok());
519        writer = Writer::new(&mut buf);
520        assert!(writer.encode_cbor(cbor_array, Some(2)).is_err());
521    }
522
523    #[test]
524    fn test_write_overly_nested() {
525        let cbor_map: Value = cbor_map! {
526            "a" => 1,
527            "b" => cbor_map! {
528                "c" => 2,
529                "d" => 3,
530                "h" => cbor_map! {
531                    "e" => 4,
532                    "f" => 5,
533                    "g" => cbor_array![
534                        6,
535                        7,
536                        cbor_array![
537                            8
538                        ]
539                    ],
540                },
541            },
542        };
543
544        let mut buf = Vec::new();
545        let mut writer = Writer::new(&mut buf);
546        assert!(writer.encode_cbor(cbor_map.clone(), Some(5)).is_ok());
547        assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok());
548        writer = Writer::new(&mut buf);
549        assert!(writer.encode_cbor(cbor_map, Some(4)).is_err());
550    }
551}