Initial commit

This commit is contained in:
Jean-Michel Picod
2020-01-28 15:09:10 +01:00
commit f91d2fd3db
90 changed files with 31123 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
// 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<u8>) -> bool {
let mut writer = Writer::new(encoded_cbor);
writer.encode_cbor(value, Writer::MAX_NESTING_DEPTH)
}
struct Writer<'a> {
encoded_cbor: &'a mut Vec<u8>,
}
impl<'a> Writer<'a> {
const MAX_NESTING_DEPTH: i8 = 4;
pub fn new(encoded_cbor: &mut Vec<u8>) -> 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<Vec<u8>> {
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));
}
}