diff options
Diffstat (limited to 'third_party/rust/moz_cbor/src/serializer.rs')
-rw-r--r-- | third_party/rust/moz_cbor/src/serializer.rs | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/third_party/rust/moz_cbor/src/serializer.rs b/third_party/rust/moz_cbor/src/serializer.rs new file mode 100644 index 0000000000..b796aaedc7 --- /dev/null +++ b/third_party/rust/moz_cbor/src/serializer.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeMap; +use CborType; + +/// Given a vector of bytes to append to, a tag to use, and an unsigned value to encode, uses the +/// CBOR unsigned integer encoding to represent the given value. +fn common_encode_unsigned(output: &mut Vec<u8>, tag: u8, value: u64) { + assert!(tag < 8); + let shifted_tag = tag << 5; + match value { + 0..=23 => { + output.push(shifted_tag | (value as u8)); + } + 24..=255 => { + output.push(shifted_tag | 24); + output.push(value as u8); + } + 256..=65_535 => { + output.push(shifted_tag | 25); + output.push((value >> 8) as u8); + output.push((value & 255) as u8); + } + 65_536..=4_294_967_295 => { + output.push(shifted_tag | 26); + output.push((value >> 24) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + _ => { + output.push(shifted_tag | 27); + output.push((value >> 56) as u8); + output.push(((value >> 48) & 255) as u8); + output.push(((value >> 40) & 255) as u8); + output.push(((value >> 32) & 255) as u8); + output.push(((value >> 24) & 255) as u8); + output.push(((value >> 16) & 255) as u8); + output.push(((value >> 8) & 255) as u8); + output.push((value & 255) as u8); + } + }; +} + +/// The major type is 0. For values 0 through 23, the 5 bits of additional information is just the +/// value of the unsigned number. For values representable in one byte, the additional information +/// has the value 24. If two bytes are necessary, the value is 25. If four bytes are necessary, the +/// value is 26. If 8 bytes are necessary, the value is 27. The following bytes are the value of the +/// unsigned number in as many bytes were indicated in network byte order (big endian). +fn encode_unsigned(output: &mut Vec<u8>, unsigned: u64) { + common_encode_unsigned(output, 0, unsigned); +} + +/// The major type is 1. The encoding is the same as for positive (i.e. unsigned) integers, except +/// the value encoded is -1 minus the value of the negative number. +fn encode_negative(output: &mut Vec<u8>, negative: i64) { + assert!(negative < 0); + let value_to_encode: u64 = (-1 - negative) as u64; + common_encode_unsigned(output, 1, value_to_encode); +} + +/// The major type is 2. The length of the data is encoded as with positive integers, followed by +/// the actual data. +fn encode_bytes(output: &mut Vec<u8>, bstr: &[u8]) { + common_encode_unsigned(output, 2, bstr.len() as u64); + output.extend_from_slice(bstr); +} + +/// The major type is 3. The length is as with bstr. The UTF-8-encoded bytes of the string follow. +fn encode_string(output: &mut Vec<u8>, tstr: &str) { + let utf8_bytes = tstr.as_bytes(); + common_encode_unsigned(output, 3, utf8_bytes.len() as u64); + output.extend_from_slice(utf8_bytes); +} + +/// The major type is 4. The number of items is encoded as with positive integers. Then follows the +/// encodings of the items themselves. +fn encode_array(output: &mut Vec<u8>, array: &[CborType]) { + common_encode_unsigned(output, 4, array.len() as u64); + for element in array { + output.append(&mut element.serialize()); + } +} + +/// The major type is 5. The number of pairs is encoded as with positive integers. Then follows the +/// encodings of each key, value pair. In Canonical CBOR, the keys must be sorted lowest value to +/// highest. +fn encode_map(output: &mut Vec<u8>, map: &BTreeMap<CborType, CborType>) { + common_encode_unsigned(output, 5, map.len() as u64); + for (key, value) in map { + output.append(&mut key.serialize()); + output.append(&mut value.serialize()); + } +} + +fn encode_tag(output: &mut Vec<u8>, tag: &u64, val: &CborType) { + common_encode_unsigned(output, 6, *tag); + output.append(&mut val.serialize()); +} + +/// The major type is 7. The only supported value for this type is 22, which is Null. +/// This makes the encoded value 246, or 0xf6. +fn encode_null(output: &mut Vec<u8>) { + output.push(0xf6); +} + +impl CborType { + /// Serialize a Cbor object. NB: if the object to be serialized consists of too many nested + /// Cbor objects (for example, Array(Array(Array(...(Array(0))))), it is possible that calling + /// serialize will exhaust the stack. It is considered the caller's responsibility to prevent + /// this. + pub fn serialize(&self) -> Vec<u8> { + let mut bytes: Vec<u8> = Vec::new(); + match *self { + CborType::Integer(ref unsigned) => encode_unsigned(&mut bytes, *unsigned), + CborType::SignedInteger(ref negative) => encode_negative(&mut bytes, *negative), + CborType::Bytes(ref bstr) => encode_bytes(&mut bytes, bstr), + CborType::String(ref tstr) => encode_string(&mut bytes, tstr), + CborType::Array(ref arr) => encode_array(&mut bytes, arr), + CborType::Map(ref map) => encode_map(&mut bytes, map), + CborType::Tag(ref t, ref val) => encode_tag(&mut bytes, t, val), + CborType::Null => encode_null(&mut bytes), + }; + bytes + } +} |