Initial commit
This commit is contained in:
29
libraries/cbor/src/lib.rs
Normal file
29
libraries/cbor/src/lib.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub mod reader;
|
||||
pub mod values;
|
||||
pub mod writer;
|
||||
|
||||
pub use self::reader::read;
|
||||
pub use self::values::{KeyType, SimpleValue, Value};
|
||||
pub use self::writer::write;
|
||||
500
libraries/cbor/src/macros.rs
Normal file
500
libraries/cbor/src/macros.rs
Normal file
@@ -0,0 +1,500 @@
|
||||
// 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.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_map {
|
||||
// trailing comma case
|
||||
( $( $key:expr => $value:expr, )+ ) => {
|
||||
cbor_map! ( $($key => $value),+ )
|
||||
};
|
||||
|
||||
( $( $key:expr => $value:expr ),* ) => {
|
||||
{
|
||||
// The import is unused if the list is empty.
|
||||
#[allow(unused_imports)]
|
||||
use $crate::values::{IntoCborKey, IntoCborValue};
|
||||
let mut _map = ::alloc::collections::BTreeMap::new();
|
||||
$(
|
||||
_map.insert($key.into_cbor_key(), $value.into_cbor_value());
|
||||
)*
|
||||
$crate::values::Value::Map(_map)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_map_options {
|
||||
// trailing comma case
|
||||
( $( $key:expr => $value:expr, )+ ) => {
|
||||
cbor_map_options! ( $($key => $value),+ )
|
||||
};
|
||||
|
||||
( $( $key:expr => $value:expr ),* ) => {
|
||||
{
|
||||
// The import is unused if the list is empty.
|
||||
#[allow(unused_imports)]
|
||||
use $crate::values::{IntoCborKey, IntoCborValueOption};
|
||||
let mut _map = ::alloc::collections::BTreeMap::<_, $crate::values::Value>::new();
|
||||
$(
|
||||
{
|
||||
let opt: Option<$crate::values::Value> = $value.into_cbor_value_option();
|
||||
if let Some(val) = opt {
|
||||
_map.insert($key.into_cbor_key(), val);
|
||||
}
|
||||
}
|
||||
)*
|
||||
$crate::values::Value::Map(_map)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_map_btree {
|
||||
( $tree:expr ) => {
|
||||
$crate::values::Value::Map($tree)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_array {
|
||||
// trailing comma case
|
||||
( $( $value:expr, )+ ) => {
|
||||
cbor_array! ( $($value),+ )
|
||||
};
|
||||
|
||||
( $( $value:expr ),* ) => {
|
||||
{
|
||||
// The import is unused if the list is empty.
|
||||
#[allow(unused_imports)]
|
||||
use $crate::values::IntoCborValue;
|
||||
$crate::values::Value::Array(vec![ $( $value.into_cbor_value(), )* ])
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_array_vec {
|
||||
( $vec:expr ) => {{
|
||||
use $crate::values::IntoCborValue;
|
||||
$crate::values::Value::Array($vec.into_iter().map(|x| x.into_cbor_value()).collect())
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! cbor_true {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::TrueValue)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_false {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::FalseValue)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_null {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::NullValue)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! cbor_undefined {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::Undefined)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_bool {
|
||||
( $x:expr ) => {
|
||||
$crate::values::Value::bool_value($x)
|
||||
};
|
||||
}
|
||||
|
||||
// For key types, we construct a KeyType and call .into(), which will automatically convert it to a
|
||||
// KeyType or a Value depending on the context.
|
||||
#[macro_export]
|
||||
macro_rules! cbor_unsigned {
|
||||
( $x:expr ) => {
|
||||
cbor_key_unsigned!($x).into()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_int {
|
||||
( $x:expr ) => {
|
||||
cbor_key_int!($x).into()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_text {
|
||||
( $x:expr ) => {
|
||||
cbor_key_text!($x).into()
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_bytes {
|
||||
( $x:expr ) => {
|
||||
cbor_key_bytes!($x).into()
|
||||
};
|
||||
}
|
||||
|
||||
// Macro to use with a literal, e.g. cbor_bytes_lit!(b"foo")
|
||||
#[macro_export]
|
||||
macro_rules! cbor_bytes_lit {
|
||||
( $x:expr ) => {
|
||||
cbor_bytes!(($x as &[u8]).to_vec())
|
||||
};
|
||||
}
|
||||
|
||||
// Some explicit macros are also available for contexts where the type is not explicit.
|
||||
#[macro_export]
|
||||
macro_rules! cbor_key_unsigned {
|
||||
( $x:expr ) => {
|
||||
$crate::values::KeyType::Unsigned($x)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_key_int {
|
||||
( $x:expr ) => {
|
||||
$crate::values::KeyType::integer($x)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_key_text {
|
||||
( $x:expr ) => {
|
||||
$crate::values::KeyType::TextString($x.into())
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cbor_key_bytes {
|
||||
( $x:expr ) => {
|
||||
$crate::values::KeyType::ByteString($x)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::values::{KeyType, SimpleValue, Value};
|
||||
use alloc::collections::BTreeMap;
|
||||
|
||||
#[test]
|
||||
fn test_cbor_simple_values() {
|
||||
assert_eq!(cbor_true!(), Value::Simple(SimpleValue::TrueValue));
|
||||
assert_eq!(cbor_false!(), Value::Simple(SimpleValue::FalseValue));
|
||||
assert_eq!(cbor_null!(), Value::Simple(SimpleValue::NullValue));
|
||||
assert_eq!(cbor_undefined!(), Value::Simple(SimpleValue::Undefined));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_bool() {
|
||||
assert_eq!(cbor_bool!(true), Value::Simple(SimpleValue::TrueValue));
|
||||
assert_eq!(cbor_bool!(false), Value::Simple(SimpleValue::FalseValue));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_int_unsigned() {
|
||||
assert_eq!(cbor_key_int!(0), KeyType::Unsigned(0));
|
||||
assert_eq!(cbor_key_int!(1), KeyType::Unsigned(1));
|
||||
assert_eq!(cbor_key_int!(123456), KeyType::Unsigned(123456));
|
||||
assert_eq!(
|
||||
cbor_key_int!(std::i64::MAX),
|
||||
KeyType::Unsigned(std::i64::MAX as u64)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_int_negative() {
|
||||
assert_eq!(cbor_key_int!(-1), KeyType::Negative(-1));
|
||||
assert_eq!(cbor_key_int!(-123456), KeyType::Negative(-123456));
|
||||
assert_eq!(
|
||||
cbor_key_int!(std::i64::MIN),
|
||||
KeyType::Negative(std::i64::MIN)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_int_literals() {
|
||||
let a = cbor_array![
|
||||
std::i64::MIN,
|
||||
std::i32::MIN,
|
||||
-123456,
|
||||
-1,
|
||||
0,
|
||||
1,
|
||||
123456,
|
||||
std::i32::MAX,
|
||||
std::i64::MAX,
|
||||
std::u64::MAX,
|
||||
];
|
||||
let b = Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Negative(std::i64::MIN)),
|
||||
Value::KeyValue(KeyType::Negative(std::i32::MIN as i64)),
|
||||
Value::KeyValue(KeyType::Negative(-123456)),
|
||||
Value::KeyValue(KeyType::Negative(-1)),
|
||||
Value::KeyValue(KeyType::Unsigned(0)),
|
||||
Value::KeyValue(KeyType::Unsigned(1)),
|
||||
Value::KeyValue(KeyType::Unsigned(123456)),
|
||||
Value::KeyValue(KeyType::Unsigned(std::i32::MAX as u64)),
|
||||
Value::KeyValue(KeyType::Unsigned(std::i64::MAX as u64)),
|
||||
Value::KeyValue(KeyType::Unsigned(std::u64::MAX)),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array() {
|
||||
let a = cbor_array![
|
||||
-123,
|
||||
456,
|
||||
true,
|
||||
cbor_null!(),
|
||||
"foo",
|
||||
b"bar",
|
||||
cbor_array![],
|
||||
cbor_array![0, 1],
|
||||
cbor_map! {},
|
||||
cbor_map! {2 => 3},
|
||||
];
|
||||
let b = Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Negative(-123)),
|
||||
Value::KeyValue(KeyType::Unsigned(456)),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
Value::KeyValue(KeyType::TextString(String::from("foo"))),
|
||||
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())),
|
||||
Value::Array(Vec::new()),
|
||||
Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Unsigned(0)),
|
||||
Value::KeyValue(KeyType::Unsigned(1)),
|
||||
]),
|
||||
Value::Map(BTreeMap::new()),
|
||||
Value::Map(
|
||||
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array_vec_empty() {
|
||||
let a = cbor_array_vec!(Vec::<bool>::new());
|
||||
let b = Value::Array(Vec::new());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array_vec_int() {
|
||||
let a = cbor_array_vec!(vec![1, 2, 3, 4]);
|
||||
let b = Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Unsigned(1)),
|
||||
Value::KeyValue(KeyType::Unsigned(2)),
|
||||
Value::KeyValue(KeyType::Unsigned(3)),
|
||||
Value::KeyValue(KeyType::Unsigned(4)),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array_vec_text() {
|
||||
let a = cbor_array_vec!(vec!["a", "b", "c"]);
|
||||
let b = Value::Array(vec![
|
||||
Value::KeyValue(KeyType::TextString(String::from("a"))),
|
||||
Value::KeyValue(KeyType::TextString(String::from("b"))),
|
||||
Value::KeyValue(KeyType::TextString(String::from("c"))),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array_vec_bytes() {
|
||||
let a = cbor_array_vec!(vec![b"a", b"b", b"c"]);
|
||||
let b = Value::Array(vec![
|
||||
Value::KeyValue(KeyType::ByteString(b"a".to_vec())),
|
||||
Value::KeyValue(KeyType::ByteString(b"b".to_vec())),
|
||||
Value::KeyValue(KeyType::ByteString(b"c".to_vec())),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_map() {
|
||||
let a = cbor_map! {
|
||||
-1 => -23,
|
||||
4 => 56,
|
||||
"foo" => true,
|
||||
b"bar" => cbor_null!(),
|
||||
5 => "foo",
|
||||
6 => b"bar",
|
||||
7 => cbor_array![],
|
||||
8 => cbor_array![0, 1],
|
||||
9 => cbor_map!{},
|
||||
10 => cbor_map!{2 => 3},
|
||||
};
|
||||
let b = Value::Map(
|
||||
[
|
||||
(
|
||||
KeyType::Negative(-1),
|
||||
Value::KeyValue(KeyType::Negative(-23)),
|
||||
),
|
||||
(KeyType::Unsigned(4), Value::KeyValue(KeyType::Unsigned(56))),
|
||||
(
|
||||
KeyType::TextString(String::from("foo")),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
),
|
||||
(
|
||||
KeyType::ByteString(b"bar".to_vec()),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
),
|
||||
(
|
||||
KeyType::Unsigned(5),
|
||||
Value::KeyValue(KeyType::TextString(String::from("foo"))),
|
||||
),
|
||||
(
|
||||
KeyType::Unsigned(6),
|
||||
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())),
|
||||
),
|
||||
(KeyType::Unsigned(7), Value::Array(Vec::new())),
|
||||
(
|
||||
KeyType::Unsigned(8),
|
||||
Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Unsigned(0)),
|
||||
Value::KeyValue(KeyType::Unsigned(1)),
|
||||
]),
|
||||
),
|
||||
(KeyType::Unsigned(9), Value::Map(BTreeMap::new())),
|
||||
(
|
||||
KeyType::Unsigned(10),
|
||||
Value::Map(
|
||||
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_map_options() {
|
||||
let a = cbor_map_options! {
|
||||
-1 => -23,
|
||||
4 => Some(56),
|
||||
11 => None::<String>,
|
||||
"foo" => true,
|
||||
12 => None::<&str>,
|
||||
b"bar" => Some(cbor_null!()),
|
||||
13 => None::<Vec<u8>>,
|
||||
5 => "foo",
|
||||
14 => None::<&[u8]>,
|
||||
6 => Some(b"bar" as &[u8]),
|
||||
15 => None::<bool>,
|
||||
7 => cbor_array![],
|
||||
16 => None::<i32>,
|
||||
8 => Some(cbor_array![0, 1]),
|
||||
17 => None::<i64>,
|
||||
9 => cbor_map!{},
|
||||
18 => None::<u64>,
|
||||
10 => Some(cbor_map!{2 => 3}),
|
||||
};
|
||||
let b = Value::Map(
|
||||
[
|
||||
(
|
||||
KeyType::Negative(-1),
|
||||
Value::KeyValue(KeyType::Negative(-23)),
|
||||
),
|
||||
(KeyType::Unsigned(4), Value::KeyValue(KeyType::Unsigned(56))),
|
||||
(
|
||||
KeyType::TextString(String::from("foo")),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
),
|
||||
(
|
||||
KeyType::ByteString(b"bar".to_vec()),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
),
|
||||
(
|
||||
KeyType::Unsigned(5),
|
||||
Value::KeyValue(KeyType::TextString(String::from("foo"))),
|
||||
),
|
||||
(
|
||||
KeyType::Unsigned(6),
|
||||
Value::KeyValue(KeyType::ByteString(b"bar".to_vec())),
|
||||
),
|
||||
(KeyType::Unsigned(7), Value::Array(Vec::new())),
|
||||
(
|
||||
KeyType::Unsigned(8),
|
||||
Value::Array(vec![
|
||||
Value::KeyValue(KeyType::Unsigned(0)),
|
||||
Value::KeyValue(KeyType::Unsigned(1)),
|
||||
]),
|
||||
),
|
||||
(KeyType::Unsigned(9), Value::Map(BTreeMap::new())),
|
||||
(
|
||||
KeyType::Unsigned(10),
|
||||
Value::Map(
|
||||
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_map_btree_empty() {
|
||||
let a = cbor_map_btree!(BTreeMap::new());
|
||||
let b = Value::Map(BTreeMap::new());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_map_btree_foo() {
|
||||
let a = cbor_map_btree!(
|
||||
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
);
|
||||
let b = Value::Map(
|
||||
[(KeyType::Unsigned(2), Value::KeyValue(KeyType::Unsigned(3)))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
811
libraries/cbor/src/reader.rs
Normal file
811
libraries/cbor/src/reader.rs
Normal file
@@ -0,0 +1,811 @@
|
||||
// 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, SimpleValue, Value};
|
||||
use alloc::collections::BTreeMap;
|
||||
use alloc::str;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DecoderError {
|
||||
UnsupportedMajorType,
|
||||
UnknownAdditionalInfo,
|
||||
IncompleteCborData,
|
||||
IncorrectMapKeyType,
|
||||
TooMuchNesting,
|
||||
InvalidUtf8,
|
||||
ExtranousData,
|
||||
OutOfOrderKey,
|
||||
NonMinimalCborEncoding,
|
||||
UnsupportedSimpleValue,
|
||||
UnsupportedFloatingPointValue,
|
||||
OutOfRangeIntegerValue,
|
||||
}
|
||||
|
||||
pub fn read(encoded_cbor: &[u8]) -> Result<Value, DecoderError> {
|
||||
let mut reader = Reader::new(encoded_cbor);
|
||||
let value = reader.decode_complete_data_item(Reader::MAX_NESTING_DEPTH)?;
|
||||
if !reader.remaining_cbor.is_empty() {
|
||||
return Err(DecoderError::ExtranousData);
|
||||
}
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
struct Reader<'a> {
|
||||
remaining_cbor: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
const MAX_NESTING_DEPTH: i8 = 4;
|
||||
|
||||
pub fn new(cbor: &'a [u8]) -> Reader<'a> {
|
||||
Reader {
|
||||
remaining_cbor: cbor,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_complete_data_item(
|
||||
&mut self,
|
||||
remaining_depth: i8,
|
||||
) -> Result<Value, DecoderError> {
|
||||
if remaining_depth < 0 {
|
||||
return Err(DecoderError::TooMuchNesting);
|
||||
}
|
||||
|
||||
match self.read_bytes(1) {
|
||||
Some([first_byte]) => {
|
||||
// Unsigned byte means logical shift, so only zeros get shifted in.
|
||||
let major_type_value = first_byte >> Constants::MAJOR_TYPE_BIT_SHIFT;
|
||||
let additional_info = first_byte & Constants::ADDITIONAL_INFORMATION_MASK;
|
||||
let size_result = self.read_variadic_length_integer(additional_info);
|
||||
match size_result {
|
||||
Ok(size_value) => match major_type_value {
|
||||
0 => self.decode_value_to_unsigned(size_value),
|
||||
1 => self.decode_value_to_negative(size_value),
|
||||
2 => self.read_byte_string_content(size_value),
|
||||
3 => self.read_text_string_content(size_value),
|
||||
4 => self.read_array_content(size_value, remaining_depth),
|
||||
5 => self.read_map_content(size_value, remaining_depth),
|
||||
7 => self.decode_to_simple_value(size_value, additional_info),
|
||||
_ => Err(DecoderError::UnsupportedMajorType),
|
||||
},
|
||||
Err(decode_error) => Err(decode_error),
|
||||
}
|
||||
}
|
||||
_ => Err(DecoderError::IncompleteCborData),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_bytes(&mut self, num_bytes: usize) -> Option<&[u8]> {
|
||||
if num_bytes > self.remaining_cbor.len() {
|
||||
None
|
||||
} else {
|
||||
let (left, right) = self.remaining_cbor.split_at(num_bytes);
|
||||
self.remaining_cbor = right;
|
||||
Some(left)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_variadic_length_integer(&mut self, additional_info: u8) -> Result<u64, DecoderError> {
|
||||
let additional_bytes_num = match additional_info {
|
||||
0..=Constants::ADDITIONAL_INFORMATION_MAX_INT => return Ok(additional_info as u64),
|
||||
Constants::ADDITIONAL_INFORMATION_1_BYTE => 1,
|
||||
Constants::ADDITIONAL_INFORMATION_2_BYTES => 2,
|
||||
Constants::ADDITIONAL_INFORMATION_4_BYTES => 4,
|
||||
Constants::ADDITIONAL_INFORMATION_8_BYTES => 8,
|
||||
_ => return Err(DecoderError::UnknownAdditionalInfo),
|
||||
};
|
||||
match self.read_bytes(additional_bytes_num) {
|
||||
Some(bytes) => {
|
||||
let mut size_value = 0u64;
|
||||
for byte in bytes {
|
||||
size_value <<= 8;
|
||||
size_value += *byte as u64;
|
||||
}
|
||||
if (additional_bytes_num == 1 && size_value < 24)
|
||||
|| size_value < (1u64 << (8 * (additional_bytes_num >> 1)))
|
||||
{
|
||||
Err(DecoderError::NonMinimalCborEncoding)
|
||||
} else {
|
||||
Ok(size_value)
|
||||
}
|
||||
}
|
||||
None => Err(DecoderError::IncompleteCborData),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_value_to_unsigned(&self, size_value: u64) -> Result<Value, DecoderError> {
|
||||
Ok(cbor_unsigned!(size_value))
|
||||
}
|
||||
|
||||
fn decode_value_to_negative(&self, size_value: u64) -> Result<Value, DecoderError> {
|
||||
let signed_size = size_value as i64;
|
||||
if signed_size < 0 {
|
||||
Err(DecoderError::OutOfRangeIntegerValue)
|
||||
} else {
|
||||
Ok(Value::KeyValue(KeyType::Negative(-(size_value as i64) - 1)))
|
||||
}
|
||||
}
|
||||
|
||||
fn read_byte_string_content(&mut self, size_value: u64) -> Result<Value, DecoderError> {
|
||||
match self.read_bytes(size_value as usize) {
|
||||
Some(bytes) => Ok(cbor_bytes_lit!(bytes)),
|
||||
None => Err(DecoderError::IncompleteCborData),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_text_string_content(&mut self, size_value: u64) -> Result<Value, DecoderError> {
|
||||
match self.read_bytes(size_value as usize) {
|
||||
Some(bytes) => match str::from_utf8(bytes) {
|
||||
Ok(s) => Ok(cbor_text!(s)),
|
||||
Err(_) => Err(DecoderError::InvalidUtf8),
|
||||
},
|
||||
None => Err(DecoderError::IncompleteCborData),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_array_content(
|
||||
&mut self,
|
||||
size_value: u64,
|
||||
remaining_depth: i8,
|
||||
) -> Result<Value, DecoderError> {
|
||||
// Don't set the capacity already, it is an unsanitized input.
|
||||
let mut value_array = Vec::new();
|
||||
for _ in 0..size_value {
|
||||
value_array.push(self.decode_complete_data_item(remaining_depth - 1)?);
|
||||
}
|
||||
Ok(cbor_array_vec!(value_array))
|
||||
}
|
||||
|
||||
fn read_map_content(
|
||||
&mut self,
|
||||
size_value: u64,
|
||||
remaining_depth: i8,
|
||||
) -> Result<Value, DecoderError> {
|
||||
let mut value_map = BTreeMap::new();
|
||||
let mut last_key_option = None;
|
||||
for _ in 0..size_value {
|
||||
let key_value = self.decode_complete_data_item(remaining_depth - 1)?;
|
||||
if let Value::KeyValue(key) = key_value {
|
||||
if let Some(last_key) = last_key_option {
|
||||
if last_key >= key {
|
||||
return Err(DecoderError::OutOfOrderKey);
|
||||
}
|
||||
}
|
||||
last_key_option = Some(key.clone());
|
||||
value_map.insert(key, self.decode_complete_data_item(remaining_depth - 1)?);
|
||||
} else {
|
||||
return Err(DecoderError::IncorrectMapKeyType);
|
||||
}
|
||||
}
|
||||
Ok(cbor_map_btree!(value_map))
|
||||
}
|
||||
|
||||
fn decode_to_simple_value(
|
||||
&self,
|
||||
size_value: u64,
|
||||
additional_info: u8,
|
||||
) -> Result<Value, DecoderError> {
|
||||
if additional_info > Constants::ADDITIONAL_INFORMATION_MAX_INT
|
||||
&& additional_info != Constants::ADDITIONAL_INFORMATION_1_BYTE
|
||||
{
|
||||
// TODO(kaczmarczyck) the chromium C++ reference allows equality to 24 here, why?
|
||||
// Also, why not just disallow ANY additional_info != size_value?
|
||||
return Err(DecoderError::UnsupportedFloatingPointValue);
|
||||
}
|
||||
match SimpleValue::from_integer(size_value) {
|
||||
Some(simple_value) => Ok(Value::Simple(simple_value)),
|
||||
None => Err(DecoderError::UnsupportedSimpleValue),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_read_unsigned() {
|
||||
let cases = vec![
|
||||
(0, vec![0x00]),
|
||||
(1, vec![0x01]),
|
||||
(10, vec![0x0A]),
|
||||
(23, vec![0x17]),
|
||||
(24, vec![0x18, 0x18]),
|
||||
(255, vec![0x18, 0xFF]),
|
||||
(256, vec![0x19, 0x01, 0x00]),
|
||||
(65535, vec![0x19, 0xFF, 0xFF]),
|
||||
(65536, vec![0x1A, 0x00, 0x01, 0x00, 0x00]),
|
||||
(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, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor), Ok(cbor_int!(unsigned)));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unsigned_non_minimum_byte_length() {
|
||||
let encodings = vec![
|
||||
// Uint 23 encoded with 1 byte.
|
||||
vec![0x18, 0x17],
|
||||
// Uint 255 encoded with 2 bytes.
|
||||
vec![0x19, 0x00, 0xff],
|
||||
// Uint 65535 encoded with 4 bytes.
|
||||
vec![0x1a, 0x00, 0x00, 0xff, 0xff],
|
||||
// Uint 4294967295 encoded with 8 bytes.
|
||||
vec![0x1b, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff],
|
||||
// When decoding byte has more than one syntax error, the first syntax
|
||||
// error encountered during deserialization is returned as the error code.
|
||||
vec![
|
||||
0xa2, // map with non-minimally encoded key
|
||||
0x17, // key 24
|
||||
0x61, 0x42, // value :"B"
|
||||
0x18, 0x17, // key 23 encoded with extra byte
|
||||
0x61, 0x45, // value "E"
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with out of order and non-minimally encoded key
|
||||
0x18, 0x17, // key 23 encoded with extra byte
|
||||
0x61, 0x45, // value "E"
|
||||
0x17, // key 23
|
||||
0x61, 0x42, // value :"B"
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with duplicate non-minimally encoded key
|
||||
0x18, 0x17, // key 23 encoded with extra byte
|
||||
0x61, 0x45, // value "E"
|
||||
0x18, 0x17, // key 23 encoded with extra byte
|
||||
0x61, 0x42, // value :"B"
|
||||
],
|
||||
];
|
||||
for encoding in encodings {
|
||||
assert_eq!(read(&encoding), Err(DecoderError::NonMinimalCborEncoding));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_negative() {
|
||||
let cases = vec![
|
||||
(-1, vec![0x20]),
|
||||
(-24, vec![0x37]),
|
||||
(-25, vec![0x38, 0x18]),
|
||||
(-256, vec![0x38, 0xFF]),
|
||||
(-1000, vec![0x39, 0x03, 0xE7]),
|
||||
(-1000000, vec![0x3A, 0x00, 0x0F, 0x42, 0x3F]),
|
||||
(-4294967296, vec![0x3A, 0xFF, 0xFF, 0xFF, 0xFF]),
|
||||
(
|
||||
std::i64::MIN,
|
||||
vec![0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
||||
),
|
||||
];
|
||||
for (negative, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor), Ok(cbor_int!(negative)));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_byte_string() {
|
||||
let cases = vec![
|
||||
(Vec::new(), vec![0x40]),
|
||||
(
|
||||
vec![0x01, 0x02, 0x03, 0x04],
|
||||
vec![0x44, 0x01, 0x02, 0x03, 0x04],
|
||||
),
|
||||
];
|
||||
for (byte_string, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor), Ok(cbor_bytes!(byte_string)));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_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, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor), Ok(cbor_text!(text_string)));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_text_string_with_nul() {
|
||||
let cases = vec![
|
||||
(
|
||||
"string_without_nul",
|
||||
vec![
|
||||
0x72, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x5F, 0x77, 0x69, 0x74, 0x68, 0x6F,
|
||||
0x75, 0x74, 0x5F, 0x6E, 0x75, 0x6C,
|
||||
],
|
||||
),
|
||||
(
|
||||
"nul_terminated_string\0",
|
||||
vec![
|
||||
0x76, 0x6E, 0x75, 0x6C, 0x5F, 0x74, 0x65, 0x72, 0x6D, 0x69, 0x6E, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x00,
|
||||
],
|
||||
),
|
||||
(
|
||||
"embedded\0nul",
|
||||
vec![
|
||||
0x6C, 0x65, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x00, 0x6E, 0x75, 0x6C,
|
||||
],
|
||||
),
|
||||
(
|
||||
"trailing_nuls\0\0",
|
||||
vec![
|
||||
0x6F, 0x74, 0x72, 0x61, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0x5F, 0x6E, 0x75, 0x6C,
|
||||
0x73, 0x00, 0x00,
|
||||
],
|
||||
),
|
||||
];
|
||||
for (text_string, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor), Ok(cbor_text!(text_string)));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_text_string_with_invalid_byte_sequence_after_nul() {
|
||||
assert_eq!(
|
||||
read(&vec![0x63, 0x00, 0x00, 0xA6]),
|
||||
Err(DecoderError::InvalidUtf8)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_array() {
|
||||
let value_vec: Vec<_> = (1..26).collect();
|
||||
let mut test_cbor = vec![
|
||||
0x98, 0x19, 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!(read(&test_cbor.clone()), Ok(cbor_array_vec!(value_vec)));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map() {
|
||||
let value_map = cbor_map! {
|
||||
24 => "abc",
|
||||
"" => ".",
|
||||
"b" => "B",
|
||||
"aa" => "AA",
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa4, // map with 4 key value pairs:
|
||||
0x18, 0x18, // 24
|
||||
0x63, 0x61, 0x62, 0x63, // "abc"
|
||||
0x60, // ""
|
||||
0x61, 0x2e, // "."
|
||||
0x61, 0x62, // "b"
|
||||
0x61, 0x42, // "B"
|
||||
0x62, 0x61, 0x61, // "aa"
|
||||
0x62, 0x41, 0x41, // "AA"
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map_with_unsigned_keys() {
|
||||
let value_map = cbor_map! {
|
||||
1 => "a",
|
||||
9 => "b",
|
||||
999 => "c",
|
||||
1111 => "d",
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa4, // map with 4 key value pairs:
|
||||
0x01, // key : 1
|
||||
0x61, 0x61, // value : "a"
|
||||
0x09, // key : 9
|
||||
0x61, 0x62, // value : "b"
|
||||
0x19, 0x03, 0xE7, // key : 999
|
||||
0x61, 0x63, // value "c"
|
||||
0x19, 0x04, 0x57, // key : 1111
|
||||
0x61, 0x64, // value : "d"
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map_with_negative_keys() {
|
||||
let value_map = cbor_map! {
|
||||
-1 => 1,
|
||||
-2 => 2,
|
||||
-100 => 3,
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xA3, // map with 3 key value pairs
|
||||
0x20, // key : -1
|
||||
0x01, // value : 1
|
||||
0x21, // key : -2
|
||||
0x02, // value : 2
|
||||
0x38, 0x63, // key : -100
|
||||
0x03, // value : 3
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map_with_array() {
|
||||
let value_map = cbor_map! {
|
||||
"a" => 1,
|
||||
"b" => cbor_array![2, 3],
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x61, 0x61, // "a"
|
||||
0x01, 0x61, 0x62, // "b"
|
||||
0x82, // array with 2 elements
|
||||
0x02, 0x03,
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map_with_text_string_keys() {
|
||||
let value_map = cbor_map! {
|
||||
"k" => "v",
|
||||
"foo" => "bar",
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x61, b'k', // text string "k"
|
||||
0x61, b'v', 0x63, b'f', b'o', b'o', // text string "foo"
|
||||
0x63, b'b', b'a', b'r',
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_map_with_byte_string_keys() {
|
||||
let value_map = cbor_map! {
|
||||
b"k" => b"v",
|
||||
b"foo" => b"bar",
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x41, b'k', // text string "k"
|
||||
0x41, b'v', 0x43, b'f', b'o', b'o', // text string "foo"
|
||||
0x43, b'b', b'a', b'r',
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_nested_map() {
|
||||
let value_map = cbor_map! {
|
||||
"a" => 1,
|
||||
"b" => cbor_map! {
|
||||
"c" => 2,
|
||||
"d" => 3,
|
||||
},
|
||||
};
|
||||
let mut test_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x61, 0x61, 0x01, // "a"
|
||||
0x61, 0x62, // "b"
|
||||
0xa2, // map of 2 pairs
|
||||
0x61, 0x63, 0x02, // "c"
|
||||
0x61, 0x64, 0x03, // "d"
|
||||
];
|
||||
assert_eq!(read(&test_cbor), Ok(value_map));
|
||||
test_cbor.push(0x01);
|
||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_integer_out_of_range() {
|
||||
let cases = vec![
|
||||
// The positive case is impossible since we support u64.
|
||||
// vec![0x1B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
vec![0x3B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::OutOfRangeIntegerValue));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_simple_value() {
|
||||
let cases = vec![
|
||||
(cbor_false!(), vec![0xF4]),
|
||||
(cbor_true!(), vec![0xF5]),
|
||||
(cbor_null!(), vec![0xF6]),
|
||||
(cbor_undefined!(), vec![0xF7]),
|
||||
];
|
||||
for (simple, mut cbor) in cases {
|
||||
assert_eq!(read(&cbor.clone()), Ok(simple));
|
||||
cbor.push(0x01);
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unsupported_floating_point_numbers() {
|
||||
let cases = vec![
|
||||
vec![0xF9, 0x10, 0x00],
|
||||
vec![0xFA, 0x10, 0x00, 0x00, 0x00],
|
||||
vec![0xFB, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(
|
||||
read(&cbor),
|
||||
Err(DecoderError::UnsupportedFloatingPointValue)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_incomplete_cbor_data_error() {
|
||||
let cases = vec![
|
||||
vec![0x19, 0x03],
|
||||
vec![0x44, 0x01, 0x02, 0x03],
|
||||
vec![0x65, 0x49, 0x45, 0x54, 0x46],
|
||||
vec![0x82, 0x02],
|
||||
vec![0xA2, 0x61, 0x61, 0x01],
|
||||
vec![0x18],
|
||||
vec![0x99],
|
||||
vec![0xBA],
|
||||
vec![0x5B],
|
||||
vec![0x3B],
|
||||
vec![0x99, 0x01],
|
||||
vec![0xBA, 0x01, 0x02, 0x03],
|
||||
vec![0x3B, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unsupported_map_key_format_error() {
|
||||
// While CBOR can handle all types as map keys, we only support a subset.
|
||||
let bad_map_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x82, 0x01, 0x02, // invalid key : [1, 2]
|
||||
0x02, // value : 2
|
||||
0x61, 0x64, // key : "d"
|
||||
0x03, // value : 3
|
||||
];
|
||||
assert_eq!(read(&bad_map_cbor), Err(DecoderError::IncorrectMapKeyType));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unknown_additional_info_error() {
|
||||
let cases = vec![
|
||||
vec![0x7C, 0x49, 0x45, 0x54, 0x46],
|
||||
vec![0x7D, 0x22, 0x5C],
|
||||
vec![0x7E, 0xC3, 0xBC],
|
||||
vec![0x7F, 0xE6, 0xB0, 0xB4],
|
||||
vec![0xFC],
|
||||
vec![0xFD],
|
||||
vec![0xFE],
|
||||
vec![0xFF],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::UnknownAdditionalInfo));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_too_much_nesting_error() {
|
||||
let cases = vec![
|
||||
vec![0x18, 0x64],
|
||||
vec![0x44, 0x01, 0x02, 0x03, 0x04],
|
||||
vec![0x64, 0x49, 0x45, 0x54, 0x46],
|
||||
vec![0x80],
|
||||
vec![0xA0],
|
||||
];
|
||||
for cbor in cases {
|
||||
let mut reader = Reader::new(&cbor);
|
||||
assert!(reader.decode_complete_data_item(0).is_ok());
|
||||
}
|
||||
let map_cbor = vec![
|
||||
0xa2, // map of 2 pairs
|
||||
0x61, 0x61, // "a"
|
||||
0x01, 0x61, 0x62, // "b"
|
||||
0x82, // array with 2 elements
|
||||
0x02, 0x03,
|
||||
];
|
||||
let mut reader = Reader::new(&map_cbor);
|
||||
assert_eq!(
|
||||
reader.decode_complete_data_item(1),
|
||||
Err(DecoderError::TooMuchNesting)
|
||||
);
|
||||
reader = Reader::new(&map_cbor);
|
||||
assert!(reader.decode_complete_data_item(2).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_out_of_order_key_error() {
|
||||
let cases = vec![
|
||||
vec![
|
||||
0xa2, // map with 2 keys with same major type and length
|
||||
0x61, 0x62, // key "b"
|
||||
0x61, 0x42, // value "B"
|
||||
0x61, 0x61, // key "a" (out of order byte-wise lexically)
|
||||
0x61, 0x45, // value "E"
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with 2 keys with different major type
|
||||
0x61, 0x62, // key "b"
|
||||
0x02, // value 2
|
||||
// key 1000 (out of order since lower major type sorts first)
|
||||
0x19, 0x03, 0xe8, 0x61, 0x61, // value a
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with 2 keys with same major type
|
||||
0x19, 0x03, 0xe8, // key 1000 (out of order due to longer length)
|
||||
0x61, 0x61, //value "a"
|
||||
0x0a, // key 10
|
||||
0x61, 0x62, // value "b"
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with 2 text string keys
|
||||
0x62, b'a', b'a', // key text string "aa"
|
||||
// (out of order due to longer length)
|
||||
0x02, 0x61, b'b', // key "b"
|
||||
0x01,
|
||||
],
|
||||
vec![
|
||||
0xa2, // map with 2 byte string keys
|
||||
0x42, b'x', b'x', // key byte string "xx"
|
||||
// (out of order due to longer length)
|
||||
0x02, 0x41, b'y', // key byte string "y"
|
||||
0x01,
|
||||
],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::OutOfOrderKey));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_duplicate_key_error() {
|
||||
let map_with_duplicate_key = vec![
|
||||
0xa6, // map of 6 pairs:
|
||||
0x60, // ""
|
||||
0x61, 0x2e, // "."
|
||||
0x61, 0x62, // "b"
|
||||
0x61, 0x42, // "B"
|
||||
0x61, 0x62, // "b" (Duplicate key)
|
||||
0x61, 0x43, // "C"
|
||||
0x61, 0x64, // "d"
|
||||
0x61, 0x44, // "D"
|
||||
0x61, 0x65, // "e"
|
||||
0x61, 0x44, // "D"
|
||||
0x62, 0x61, 0x61, // "aa"
|
||||
0x62, 0x41, 0x41, // "AA"
|
||||
];
|
||||
assert_eq!(
|
||||
read(&map_with_duplicate_key),
|
||||
Err(DecoderError::OutOfOrderKey)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_incorrect_string_encoding_error() {
|
||||
let cases = vec![
|
||||
vec![0x63, 0xED, 0x9F, 0xBF],
|
||||
vec![0x63, 0xEE, 0x80, 0x80],
|
||||
vec![0x63, 0xEF, 0xBF, 0xBD],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert!(read(&cbor).is_ok());
|
||||
}
|
||||
let impossible_utf_byte = vec![0x64, 0xFE, 0xFE, 0xFF, 0xFF];
|
||||
assert_eq!(read(&impossible_utf_byte), Err(DecoderError::InvalidUtf8));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_extranous_cbor_data_error() {
|
||||
let cases = vec![
|
||||
vec![0x19, 0x03, 0x05, 0x00],
|
||||
vec![0x44, 0x01, 0x02, 0x03, 0x04, 0x00],
|
||||
vec![0x64, 0x49, 0x45, 0x54, 0x46, 0x00],
|
||||
vec![0x82, 0x01, 0x02, 0x00],
|
||||
vec![0xa1, 0x61, 0x63, 0x02, 0x61, 0x64, 0x03],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unsupported_simple_type() {
|
||||
let cases = vec![
|
||||
vec![0xE0],
|
||||
vec![0xF3],
|
||||
vec![0xF8, 0x18],
|
||||
vec![0xF8, 0x1C],
|
||||
vec![0xF8, 0x1D],
|
||||
vec![0xF8, 0x1E],
|
||||
vec![0xF8, 0x1F],
|
||||
vec![0xF8, 0x20],
|
||||
vec![0xF8, 0xFF],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::UnsupportedSimpleValue));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_super_long_content_dont_crash() {
|
||||
let cases = vec![
|
||||
vec![0x9B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
||||
vec![0xBB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_unsupported_major_type() {
|
||||
let cases = vec![
|
||||
vec![0xC0],
|
||||
vec![0xD8, 0xFF],
|
||||
// multi-dimensional array example using tags
|
||||
vec![
|
||||
0x82, 0x82, 0x02, 0x03, 0xd8, 0x41, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
|
||||
0x03, 0x00, 0x04, 0x00, 0x05,
|
||||
],
|
||||
];
|
||||
for cbor in cases {
|
||||
assert_eq!(read(&cbor), Err(DecoderError::UnsupportedMajorType));
|
||||
}
|
||||
}
|
||||
}
|
||||
268
libraries/cbor/src/values.rs
Normal file
268
libraries/cbor/src/values.rs
Normal file
@@ -0,0 +1,268 @@
|
||||
// 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 alloc::collections::BTreeMap;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::Ordering;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Value {
|
||||
KeyValue(KeyType),
|
||||
Array(Vec<Value>),
|
||||
Map(BTreeMap<KeyType, Value>),
|
||||
// TAG is omitted
|
||||
Simple(SimpleValue),
|
||||
}
|
||||
|
||||
// The specification recommends to limit the available keys.
|
||||
// Currently supported are both integer and string types.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum KeyType {
|
||||
Unsigned(u64),
|
||||
// We only use 63 bits of information here.
|
||||
Negative(i64),
|
||||
ByteString(Vec<u8>),
|
||||
TextString(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum SimpleValue {
|
||||
FalseValue = 20,
|
||||
TrueValue = 21,
|
||||
NullValue = 22,
|
||||
Undefined = 23,
|
||||
}
|
||||
|
||||
pub struct Constants {}
|
||||
|
||||
impl Constants {
|
||||
pub const MAJOR_TYPE_BIT_SHIFT: u8 = 5;
|
||||
pub const ADDITIONAL_INFORMATION_MASK: u8 = 0x1F;
|
||||
pub const ADDITIONAL_INFORMATION_MAX_INT: u8 = 23;
|
||||
pub const ADDITIONAL_INFORMATION_1_BYTE: u8 = 24;
|
||||
pub const ADDITIONAL_INFORMATION_2_BYTES: u8 = 25;
|
||||
pub const ADDITIONAL_INFORMATION_4_BYTES: u8 = 26;
|
||||
pub const ADDITIONAL_INFORMATION_8_BYTES: u8 = 27;
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn bool_value(b: bool) -> Value {
|
||||
if b {
|
||||
Value::Simple(SimpleValue::TrueValue)
|
||||
} else {
|
||||
Value::Simple(SimpleValue::FalseValue)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_label(&self) -> u8 {
|
||||
match self {
|
||||
Value::KeyValue(key) => key.type_label(),
|
||||
Value::Array(_) => 4,
|
||||
Value::Map(_) => 5,
|
||||
Value::Simple(_) => 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyType {
|
||||
// For simplicity, this only takes i64. Construct directly for the last bit.
|
||||
pub fn integer(int: i64) -> KeyType {
|
||||
if int >= 0 {
|
||||
KeyType::Unsigned(int as u64)
|
||||
} else {
|
||||
KeyType::Negative(int)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_label(&self) -> u8 {
|
||||
match self {
|
||||
KeyType::Unsigned(_) => 0,
|
||||
KeyType::Negative(_) => 1,
|
||||
KeyType::ByteString(_) => 2,
|
||||
KeyType::TextString(_) => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for KeyType {
|
||||
fn cmp(&self, other: &KeyType) -> Ordering {
|
||||
use super::values::KeyType::{ByteString, Negative, TextString, Unsigned};
|
||||
let self_type_value = self.type_label();
|
||||
let other_type_value = other.type_label();
|
||||
if self_type_value != other_type_value {
|
||||
return self_type_value.cmp(&other_type_value);
|
||||
}
|
||||
match (self, other) {
|
||||
(Unsigned(u1), Unsigned(u2)) => u1.cmp(u2),
|
||||
(Negative(n1), Negative(n2)) => n1.cmp(n2).reverse(),
|
||||
(ByteString(b1), ByteString(b2)) => b1.len().cmp(&b2.len()).then(b1.cmp(b2)),
|
||||
(TextString(t1), TextString(t2)) => t1.len().cmp(&t2.len()).then(t1.cmp(t2)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for KeyType {
|
||||
fn partial_cmp(&self, other: &KeyType) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl SimpleValue {
|
||||
pub fn from_integer(int: u64) -> Option<SimpleValue> {
|
||||
match int {
|
||||
20 => Some(SimpleValue::FalseValue),
|
||||
21 => Some(SimpleValue::TrueValue),
|
||||
22 => Some(SimpleValue::NullValue),
|
||||
23 => Some(SimpleValue::Undefined),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for KeyType {
|
||||
fn from(unsigned: u64) -> Self {
|
||||
KeyType::Unsigned(unsigned)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for KeyType {
|
||||
fn from(i: i64) -> Self {
|
||||
KeyType::integer(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for KeyType {
|
||||
fn from(i: i32) -> Self {
|
||||
KeyType::integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for KeyType {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
KeyType::ByteString(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for KeyType {
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
KeyType::ByteString(bytes.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for KeyType {
|
||||
fn from(text: String) -> Self {
|
||||
KeyType::TextString(text)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for KeyType {
|
||||
fn from(text: &str) -> Self {
|
||||
KeyType::TextString(text.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Value
|
||||
where
|
||||
KeyType: From<T>,
|
||||
{
|
||||
fn from(t: T) -> Self {
|
||||
Value::KeyValue(KeyType::from(t))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Value {
|
||||
fn from(b: bool) -> Self {
|
||||
Value::bool_value(b)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoCborKey {
|
||||
fn into_cbor_key(self) -> KeyType;
|
||||
}
|
||||
|
||||
impl<T> IntoCborKey for T
|
||||
where
|
||||
KeyType: From<T>,
|
||||
{
|
||||
fn into_cbor_key(self) -> KeyType {
|
||||
KeyType::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoCborValue {
|
||||
fn into_cbor_value(self) -> Value;
|
||||
}
|
||||
|
||||
impl<T> IntoCborValue for T
|
||||
where
|
||||
Value: From<T>,
|
||||
{
|
||||
fn into_cbor_value(self) -> Value {
|
||||
Value::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoCborValueOption {
|
||||
fn into_cbor_value_option(self) -> Option<Value>;
|
||||
}
|
||||
|
||||
impl<T> IntoCborValueOption for T
|
||||
where
|
||||
Value: From<T>,
|
||||
{
|
||||
fn into_cbor_value_option(self) -> Option<Value> {
|
||||
Some(Value::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoCborValueOption for Option<T>
|
||||
where
|
||||
Value: From<T>,
|
||||
{
|
||||
fn into_cbor_value_option(self) -> Option<Value> {
|
||||
self.map(Value::from)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_key_type_ordering() {
|
||||
assert!(cbor_key_int!(0) < cbor_key_int!(23));
|
||||
assert!(cbor_key_int!(23) < cbor_key_int!(24));
|
||||
assert!(cbor_key_int!(24) < cbor_key_int!(1000));
|
||||
assert!(cbor_key_int!(1000) < cbor_key_int!(1000000));
|
||||
assert!(cbor_key_int!(1000000) < cbor_key_int!(std::i64::MAX));
|
||||
assert!(cbor_key_int!(std::i64::MAX) < cbor_key_int!(-1));
|
||||
assert!(cbor_key_int!(-1) < cbor_key_int!(-23));
|
||||
assert!(cbor_key_int!(-23) < cbor_key_int!(-24));
|
||||
assert!(cbor_key_int!(-24) < cbor_key_int!(-1000));
|
||||
assert!(cbor_key_int!(-1000) < cbor_key_int!(-1000000));
|
||||
assert!(cbor_key_int!(-1000000) < cbor_key_int!(std::i64::MIN));
|
||||
assert!(cbor_key_int!(std::i64::MIN) < cbor_key_bytes!(vec![]));
|
||||
assert!(cbor_key_bytes!(vec![]) < cbor_key_bytes!(vec![0x00]));
|
||||
assert!(cbor_key_bytes!(vec![0x00]) < cbor_key_bytes!(vec![0x01]));
|
||||
assert!(cbor_key_bytes!(vec![0x01]) < cbor_key_bytes!(vec![0xFF]));
|
||||
assert!(cbor_key_bytes!(vec![0xFF]) < cbor_key_bytes!(vec![0x00, 0x00]));
|
||||
assert!(cbor_key_bytes!(vec![0x00, 0x00]) < cbor_key_text!(""));
|
||||
assert!(cbor_key_text!("") < cbor_key_text!("a"));
|
||||
assert!(cbor_key_text!("a") < cbor_key_text!("b"));
|
||||
assert!(cbor_key_text!("b") < cbor_key_text!("aa"));
|
||||
assert!(cbor_key_int!(1) < cbor_key_bytes!(vec![0x00]));
|
||||
assert!(cbor_key_int!(1) < cbor_key_text!("s"));
|
||||
assert!(cbor_key_int!(-1) < cbor_key_text!("s"));
|
||||
}
|
||||
}
|
||||
429
libraries/cbor/src/writer.rs
Normal file
429
libraries/cbor/src/writer.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user