CBOR¶
The Concise Binary Object Representation (CBOR) is a data format whose design goals include the possibility of extremely small code size, fairly small message size, and extensibility without the need for version negotiation.
References
- CBOR Website - the main source on CBOR
- CBOR Playground - an interactive webpage to translate between JSON and CBOR
- RFC 7049 - the CBOR specification
Serialization¶
The library uses the following mapping from JSON values types to CBOR types according to the CBOR specification (RFC 7049):
| JSON value type | value/range | CBOR type | first byte |
|---|---|---|---|
| null | null | Null | 0xF6 |
| boolean | true | True | 0xF5 |
| boolean | false | False | 0xF4 |
| number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B |
| number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A |
| number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 |
| number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 |
| number_integer | -24..-1 | Negative integer | 0x20..0x37 |
| number_integer | 0..23 | Integer | 0x00..0x17 |
| number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
| number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
| number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A |
| number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B |
| number_unsigned | 0..23 | Integer | 0x00..0x17 |
| number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 |
| number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 |
| number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A |
| number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B |
| number_float | any value representable by a float | Single-Precision Float | 0xFA |
| number_float | any value NOT representable by a float | Double-Precision Float | 0xFB |
| string | length: 0..23 | UTF-8 string | 0x60..0x77 |
| string | length: 23..255 | UTF-8 string (1 byte follow) | 0x78 |
| string | length: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 |
| string | length: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A |
| string | length: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B |
| array | size: 0..23 | array | 0x80..0x97 |
| array | size: 23..255 | array (1 byte follow) | 0x98 |
| array | size: 256..65535 | array (2 bytes follow) | 0x99 |
| array | size: 65536..4294967295 | array (4 bytes follow) | 0x9A |
| array | size: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B |
| object | size: 0..23 | map | 0xA0..0xB7 |
| object | size: 23..255 | map (1 byte follow) | 0xB8 |
| object | size: 256..65535 | map (2 bytes follow) | 0xB9 |
| object | size: 65536..4294967295 | map (4 bytes follow) | 0xBA |
| object | size: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB |
| binary | size: 0..23 | byte string | 0x40..0x57 |
| binary | size: 23..255 | byte string (1 byte follow) | 0x58 |
| binary | size: 256..65535 | byte string (2 bytes follow) | 0x59 |
| binary | size: 65536..4294967295 | byte string (4 bytes follow) | 0x5A |
| binary | size: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B |
Complete mapping
The mapping is complete in the sense that any JSON value type can be converted to a CBOR value.
NaN/infinity handling
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the normal JSON serialization which serializes NaN or Infinity to null.
Unused CBOR types
The following CBOR types are not used in the conversion:
- UTF-8 strings terminated by "break" (0x7F)
- arrays terminated by "break" (0x9F)
- maps terminated by "break" (0xBF)
- byte strings terminated by "break" (0x5F)
- date/time (0xC0..0xC1)
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
- bigfloat (0xC5)
- expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
- half-precision floats (0xF9)
- break (0xFF)
Tagged items
Binary subtypes will be serialized as tagged items. See binary values for an example.
Example
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON value
json j = R"({"compact": true, "schema": 0})"_json;
// serialize it to CBOR
std::vector<uint8_t> v = json::to_cbor(j);
// print the vector content
for (auto& byte : v)
{
std::cout << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int)byte << " ";
}
std::cout << std::endl;
}
Output:
0xa2 0x67 0x63 0x6f 0x6d 0x70 0x61 0x63 0x74 0xf5 0x66 0x73 0x63 0x68 0x65 0x6d 0x61 0x00
Deserialization¶
The library maps CBOR types to JSON value types as follows:
| CBOR type | JSON value type | first byte |
|---|---|---|
| Integer | number_unsigned | 0x00..0x17 |
| Unsigned integer | number_unsigned | 0x18 |
| Unsigned integer | number_unsigned | 0x19 |
| Unsigned integer | number_unsigned | 0x1A |
| Unsigned integer | number_unsigned | 0x1B |
| Negative integer | number_integer | 0x20..0x37 |
| Negative integer | number_integer | 0x38 |
| Negative integer | number_integer | 0x39 |
| Negative integer | number_integer | 0x3A |
| Negative integer | number_integer | 0x3B |
| Byte string | binary | 0x40..0x57 |
| Byte string | binary | 0x58 |
| Byte string | binary | 0x59 |
| Byte string | binary | 0x5A |
| Byte string | binary | 0x5B |
| UTF-8 string | string | 0x60..0x77 |
| UTF-8 string | string | 0x78 |
| UTF-8 string | string | 0x79 |
| UTF-8 string | string | 0x7A |
| UTF-8 string | string | 0x7B |
| UTF-8 string | string | 0x7F |
| array | array | 0x80..0x97 |
| array | array | 0x98 |
| array | array | 0x99 |
| array | array | 0x9A |
| array | array | 0x9B |
| array | array | 0x9F |
| map | object | 0xA0..0xB7 |
| map | object | 0xB8 |
| map | object | 0xB9 |
| map | object | 0xBA |
| map | object | 0xBB |
| map | object | 0xBF |
| False | false | 0xF4 |
| True | true | 0xF5 |
| Null | null | 0xF6 |
| Half-Precision Float | number_float | 0xF9 |
| Single-Precision Float | number_float | 0xFA |
| Double-Precision Float | number_float | 0xFB |
Incomplete mapping
The mapping is incomplete in the sense that not all CBOR types can be converted to a JSON value. The following CBOR types are not supported and will yield parse errors:
- date/time (0xC0..0xC1)
- bignum (0xC2..0xC3)
- decimal fraction (0xC4)
- bigfloat (0xC5)
- expected conversions (0xD5..0xD7)
- simple values (0xE0..0xF3, 0xF8)
- undefined (0xF7)
Object keys
CBOR allows map keys of any type, whereas JSON only allows strings as keys in object values. Therefore, CBOR maps with keys other than UTF-8 strings are rejected.
Tagged items
Tagged items will throw a parse error by default. However, they can be ignored by passing cbor_tag_handler_t::ignore to function from_cbor.
Example
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create byte vector
std::vector<uint8_t> v = {0xa2, 0x67, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63,
0x74, 0xf5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6d,
0x61, 0x00
};
// deserialize it with CBOR
json j = json::from_cbor(v);
// print the deserialized JSON value
std::cout << std::setw(2) << j << std::endl;
}
Output:
{
"compact": true,
"schema": 0
}