// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Functionality for serializing CBOR values into bytes. use super::values::{Constants, Value}; use alloc::vec::Vec; /// Possible errors from a serialization operation. #[derive(Debug, PartialEq)] pub enum EncoderError { TooMuchNesting, DuplicateMapKey, } /// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector. /// Maximum level of nesting supported is 127; more deeply nested structures will fail with /// [`EncoderError::TooMuchNesting`]. pub fn write(value: Value, encoded_cbor: &mut Vec) -> Result<(), EncoderError> { write_nested(value, encoded_cbor, Some(i8::MAX)) } /// Convert a [`Value`] to serialized CBOR data, consuming it along the way and appending to the provided vector. If /// `max_nest` is `Some(max)`, then nested structures are only supported up to the given limit (returning /// [`DecoderError::TooMuchNesting`] if the limit is hit). pub fn write_nested( value: Value, encoded_cbor: &mut Vec, max_nest: Option, ) -> Result<(), EncoderError> { let mut writer = Writer::new(encoded_cbor); writer.encode_cbor(value, max_nest) } struct Writer<'a> { encoded_cbor: &'a mut Vec, } impl<'a> Writer<'a> { pub fn new(encoded_cbor: &mut Vec) -> Writer { Writer { encoded_cbor } } fn encode_cbor( &mut self, value: Value, remaining_depth: Option, ) -> Result<(), EncoderError> { if remaining_depth.map_or(false, |d| d < 0) { return Err(EncoderError::TooMuchNesting); } let type_label = value.type_label(); match value { Value::Unsigned(unsigned) => self.start_item(type_label, unsigned), Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64), Value::ByteString(byte_string) => { self.start_item(type_label, byte_string.len() as u64); self.encoded_cbor.extend(byte_string); } Value::TextString(text_string) => { self.start_item(type_label, text_string.len() as u64); self.encoded_cbor.extend(text_string.into_bytes()); } Value::Array(array) => { self.start_item(type_label, array.len() as u64); for el in array { self.encode_cbor(el, remaining_depth.map(|d| d - 1))?; } } Value::Map(mut map) => { map.sort_by(|a, b| a.0.cmp(&b.0)); let map_len = map.len(); map.dedup_by(|a, b| a.0.eq(&b.0)); if map_len != map.len() { return Err(EncoderError::DuplicateMapKey); } self.start_item(type_label, map_len as u64); for (k, v) in map { self.encode_cbor(k, remaining_depth.map(|d| d - 1))?; self.encode_cbor(v, remaining_depth.map(|d| d - 1))?; } } Value::Tag(tag, inner_value) => { self.start_item(type_label, tag); self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?; } Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64), } Ok(()) } fn start_item(&mut self, type_label: u8, size: u64) { let (mut first_byte, shift) = match size { 0..=23 => (size as u8, 0), 24..=0xFF => (Constants::ADDITIONAL_INFORMATION_1_BYTE, 1), 0x100..=0xFFFF => (Constants::ADDITIONAL_INFORMATION_2_BYTES, 2), 0x10000..=0xFFFF_FFFF => (Constants::ADDITIONAL_INFORMATION_4_BYTES, 4), _ => (Constants::ADDITIONAL_INFORMATION_8_BYTES, 8), }; first_byte |= type_label << Constants::MAJOR_TYPE_BIT_SHIFT; self.encoded_cbor.push(first_byte); for i in (0..shift).rev() { self.encoded_cbor.push((size >> (i * 8)) as u8); } } } #[cfg(test)] mod test { use super::*; use crate::{ cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null, cbor_tagged, cbor_text, cbor_true, cbor_undefined, }; use alloc::vec; fn write_return(value: Value) -> Option> { let mut encoded_cbor = Vec::new(); if write(value, &mut encoded_cbor).is_ok() { Some(encoded_cbor) } else { None } } #[test] fn test_write_unsigned() { let cases = vec![ (0, vec![0x00]), (1, vec![0x01]), (10, vec![0x0A]), (23, vec![0x17]), (24, vec![0x18, 0x18]), (25, vec![0x18, 0x19]), (100, vec![0x18, 0x64]), (1000, vec![0x19, 0x03, 0xE8]), (1000000, vec![0x1A, 0x00, 0x0F, 0x42, 0x40]), (0xFFFFFFFF, vec![0x1A, 0xFF, 0xFF, 0xFF, 0xFF]), ( 0x100000000, vec![0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], ), ( core::i64::MAX, vec![0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], ), ]; for (unsigned, correct_cbor) in cases { assert_eq!(write_return(cbor_int!(unsigned)), Some(correct_cbor)); } } #[test] fn test_write_negative() { let cases = vec![ (-1, vec![0x20]), (-10, vec![0x29]), (-23, vec![0x36]), (-24, vec![0x37]), (-25, vec![0x38, 0x18]), (-100, vec![0x38, 0x63]), (-1000, vec![0x39, 0x03, 0xE7]), (-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]), ( -4294967297, vec![0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00], ), ( core::i64::MIN, vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], ), ]; for (negative, correct_cbor) in cases { assert_eq!(write_return(cbor_int!(negative)), Some(correct_cbor)); } } #[test] fn test_write_byte_string() { let cases = vec![ (vec![], vec![0x40]), ( vec![0x01, 0x02, 0x03, 0x04], vec![0x44, 0x01, 0x02, 0x03, 0x04], ), ]; for (byte_string, correct_cbor) in cases { assert_eq!(write_return(cbor_bytes!(byte_string)), Some(correct_cbor)); } } #[test] fn test_write_text_string() { let unicode_3byte = vec![0xE6, 0xB0, 0xB4]; let cases = vec![ ("", vec![0x60]), ("a", vec![0x61, 0x61]), ("IETF", vec![0x64, 0x49, 0x45, 0x54, 0x46]), ("\"\\", vec![0x62, 0x22, 0x5C]), ("ü", vec![0x62, 0xC3, 0xBC]), ( core::str::from_utf8(&unicode_3byte).unwrap(), vec![0x63, 0xE6, 0xB0, 0xB4], ), ("𐅑", vec![0x64, 0xF0, 0x90, 0x85, 0x91]), ]; for (text_string, correct_cbor) in cases { assert_eq!(write_return(cbor_text!(text_string)), Some(correct_cbor)); } } #[test] fn test_write_array() { let value_vec: Vec<_> = (1..26).collect(); let expected_cbor = vec![ 0x98, 0x19, // array of 25 elements 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, ]; assert_eq!( write_return(cbor_array_vec!(value_vec)), Some(expected_cbor) ); } #[test] fn test_write_map() { let value_map = cbor_map! { 0 => "a", 23 => "b", 24 => "c", core::u8::MAX as i64 => "d", 256 => "e", core::u16::MAX as i64 => "f", 65536 => "g", core::u32::MAX as i64 => "h", 4294967296_i64 => "i", core::i64::MAX => "j", -1 => "k", -24 => "l", -25 => "m", -256 => "n", -257 => "o", -65537 => "p", -4294967296_i64 => "q", -4294967297_i64 => "r", core::i64::MIN => "s", b"a" => 2, b"bar" => 3, b"foo" => 4, "" => ".", "e" => "E", "aa" => "AA", }; let expected_cbor = vec![ 0xb8, 0x19, // map of 25 pairs: 0x00, // key 0 0x61, 0x61, // value "a" 0x17, // key 23 0x61, 0x62, // value "b" 0x18, 0x18, // key 24 0x61, 0x63, // value "c" 0x18, 0xFF, // key 255 0x61, 0x64, // value "d" 0x19, 0x01, 0x00, // key 256 0x61, 0x65, // value "e" 0x19, 0xFF, 0xFF, // key 65535 0x61, 0x66, // value "f" 0x1A, 0x00, 0x01, 0x00, 0x00, // key 65536 0x61, 0x67, // value "g" 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, // key 4294967295 0x61, 0x68, // value "h" // key 4294967296 0x1B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x69, // value "i" // key INT64_MAX 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x6a, // value "j" 0x20, // key -1 0x61, 0x6b, // value "k" 0x37, // key -24 0x61, 0x6c, // value "l" 0x38, 0x18, // key -25 0x61, 0x6d, // value "m" 0x38, 0xFF, // key -256 0x61, 0x6e, // value "n" 0x39, 0x01, 0x00, // key -257 0x61, 0x6f, // value "o" 0x3A, 0x00, 0x01, 0x00, 0x00, // key -65537 0x61, 0x70, // value "p" 0x3A, 0xFF, 0xFF, 0xFF, 0xFF, // key -4294967296 0x61, 0x71, // value "q" // key -4294967297 0x3B, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x61, 0x72, // value "r" // key INT64_MIN 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x61, 0x73, // value "s" 0x41, b'a', // byte string "a" 0x02, 0x43, b'b', b'a', b'r', // byte string "bar" 0x03, 0x43, b'f', b'o', b'o', // byte string "foo" 0x04, 0x60, // key "" 0x61, 0x2e, // value "." 0x61, 0x65, // key "e" 0x61, 0x45, // value "E" 0x62, 0x61, 0x61, // key "aa" 0x62, 0x41, 0x41, // value "AA" ]; assert_eq!(write_return(value_map), Some(expected_cbor)); } #[test] fn test_write_map_sorted() { let sorted_map = cbor_map! { 0 => "a", 1 => "b", -1 => "c", -2 => "d", b"a" => "e", b"b" => "f", "" => "g", "c" => "h", }; let unsorted_map = cbor_map! { 1 => "b", -2 => "d", b"b" => "f", "c" => "h", "" => "g", b"a" => "e", -1 => "c", 0 => "a", }; assert_eq!(write_return(sorted_map), write_return(unsorted_map)); } #[test] fn test_write_map_duplicates() { let duplicate0 = cbor_map! { 0 => "a", -1 => "c", b"a" => "e", "c" => "g", 0 => "b", }; assert_eq!(write_return(duplicate0), None); let duplicate1 = cbor_map! { 0 => "a", -1 => "c", b"a" => "e", "c" => "g", -1 => "d", }; assert_eq!(write_return(duplicate1), None); let duplicate2 = cbor_map! { 0 => "a", -1 => "c", b"a" => "e", "c" => "g", b"a" => "f", }; assert_eq!(write_return(duplicate2), None); let duplicate3 = cbor_map! { 0 => "a", -1 => "c", b"a" => "e", "c" => "g", "c" => "h", }; assert_eq!(write_return(duplicate3), None); } #[test] fn test_write_map_with_array() { let value_map = cbor_map! { "a" => 1, "b" => cbor_array![2, 3], }; let expected_cbor = vec![ 0xa2, // map of 2 pairs 0x61, 0x61, // "a" 0x01, 0x61, 0x62, // "b" 0x82, // array with 2 elements 0x02, 0x03, ]; assert_eq!(write_return(value_map), Some(expected_cbor)); } #[test] fn test_write_nested_map() { let value_map = cbor_map! { "a" => 1, "b" => cbor_map! { "c" => 2, "d" => 3, }, }; let expected_cbor = vec![ 0xa2, // map of 2 pairs 0x61, 0x61, // "a" 0x01, 0x61, 0x62, // "b" 0xa2, // map of 2 pairs 0x61, 0x63, // "c" 0x02, 0x61, 0x64, // "d" 0x03, ]; assert_eq!(write_return(value_map), Some(expected_cbor)); } #[test] fn test_write_tagged() { let cases = vec![ (cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]), (cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]), ( cbor_tagged!( 1000, cbor_map! { "a" => 1, "b" => cbor_array![2, 3], } ), vec![ 0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs 0x61, 0x61, // "a" 0x01, 0x61, 0x62, // "b" 0x82, // array with 2 elements 0x02, 0x03, ], ), ]; for (value, correct_cbor) in cases { assert_eq!(write_return(value), Some(correct_cbor)); } } #[test] fn test_write_simple() { let cases = vec![ (cbor_false!(), vec![0xF4]), (cbor_true!(), vec![0xF5]), (cbor_null!(), vec![0xF6]), (cbor_undefined!(), vec![0xF7]), ]; for (value, correct_cbor) in cases { assert_eq!(write_return(value), Some(correct_cbor)); } } #[test] fn test_write_single_levels() { let simple_array: Value = cbor_array![2]; let simple_map: Value = cbor_map! {"b" => 3}; let positive_cases = vec![ (cbor_int!(1), 0), (cbor_bytes!(vec![0x01, 0x02, 0x03, 0x04]), 0), (cbor_text!("a"), 0), (cbor_array![], 0), (cbor_map! {}, 0), (simple_array.clone(), 1), (simple_map.clone(), 1), ]; let negative_cases = vec![(simple_array.clone(), 0), (simple_map.clone(), 0)]; for (value, level) in positive_cases { let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(writer.encode_cbor(value, Some(level)).is_ok()); } for (value, level) in negative_cases { let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(!writer.encode_cbor(value, Some(level)).is_ok()); } } #[test] fn test_write_nested_map_levels() { let cbor_map: Value = cbor_map! { "a" => 1, "b" => cbor_map! { "c" => 2, "d" => 3, }, }; let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_map.clone(), Some(2)).is_ok()); assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok()); writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_map, Some(1)).is_err()); } #[test] fn test_write_unbalanced_nested_containers() { let cbor_array: Value = cbor_array![ 1, 2, 3, cbor_map! { "a" => 1, "b" => cbor_map! { "c" => 2, "d" => 3, }, }, ]; let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_array.clone(), Some(3)).is_ok()); writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_array, Some(2)).is_err()); } #[test] fn test_write_overly_nested() { let cbor_map: Value = cbor_map! { "a" => 1, "b" => cbor_map! { "c" => 2, "d" => 3, "h" => cbor_map! { "e" => 4, "f" => 5, "g" => cbor_array![ 6, 7, cbor_array![ 8 ] ], }, }, }; let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_map.clone(), Some(5)).is_ok()); assert!(writer.encode_cbor(cbor_map.clone(), None).is_ok()); writer = Writer::new(&mut buf); assert!(writer.encode_cbor(cbor_map, Some(4)).is_err()); } }