// 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. use super::values::{Constants, KeyType, Value}; use alloc::vec::Vec; pub fn write(value: Value, encoded_cbor: &mut Vec) -> bool { let mut writer = Writer::new(encoded_cbor); writer.encode_cbor(value, Writer::MAX_NESTING_DEPTH) } struct Writer<'a> { encoded_cbor: &'a mut Vec, } impl<'a> Writer<'a> { const MAX_NESTING_DEPTH: i8 = 4; pub fn new(encoded_cbor: &mut Vec) -> Writer { Writer { encoded_cbor } } fn encode_cbor(&mut self, value: Value, remaining_depth: i8) -> bool { if remaining_depth < 0 { return false; } match value { Value::KeyValue(KeyType::Unsigned(unsigned)) => self.start_item(0, unsigned as u64), Value::KeyValue(KeyType::Negative(negative)) => { self.start_item(1, -(negative + 1) as u64) } Value::KeyValue(KeyType::ByteString(byte_string)) => { self.start_item(2, byte_string.len() as u64); self.encoded_cbor.extend(byte_string); } Value::KeyValue(KeyType::TextString(text_string)) => { self.start_item(3, text_string.len() as u64); self.encoded_cbor.extend(text_string.into_bytes()); } Value::Array(array) => { self.start_item(4, array.len() as u64); for el in array { if !self.encode_cbor(el, remaining_depth - 1) { return false; } } } Value::Map(map) => { self.start_item(5, map.len() as u64); for (k, v) in map { if !self.encode_cbor(Value::KeyValue(k), remaining_depth - 1) { return false; } if !self.encode_cbor(v, remaining_depth - 1) { return false; } } } Value::Simple(simple_value) => self.start_item(7, simple_value as u64), } true } 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::*; fn write_return(value: Value) -> Option> { let mut encoded_cbor = Vec::new(); if write(value, &mut encoded_cbor) { 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], ), ( std::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], ), ( std::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]), ( std::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! { "aa" => "AA", "e" => "E", "" => ".", -1 => "k", -24 => "l", -25 => "m", -256 => "n", -257 => "o", -65537 => "p", -4294967296_i64 => "q", -4294967297_i64 => "r", std::i64::MIN => "s", b"a" => 2, b"bar" => 3, b"foo" => 4, 0 => "a", 23 => "b", 24 => "c", std::u8::MAX as i64 => "d", 256 => "e", std::u16::MAX as i64 => "f", 65536 => "g", std::u32::MAX as i64 => "h", 4294967296_i64 => "i", std::i64::MAX => "j", }; 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_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_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, level)); } for (value, level) in negative_cases { let mut buf = Vec::new(); let mut writer = Writer::new(&mut buf); assert!(!writer.encode_cbor(value, level)); } } #[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(), 2)); writer = Writer::new(&mut buf); assert!(!writer.encode_cbor(cbor_map, 1)); } #[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(), 3)); writer = Writer::new(&mut buf); assert!(!writer.encode_cbor(cbor_array, 2)); } #[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(), 5)); writer = Writer::new(&mut buf); assert!(!writer.encode_cbor(cbor_map, 4)); } }