Skip to content

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

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

Binary values with subtype are mapped to tagged values (0xD8..0xDB) depending on the subtype, followed by a byte string, see "binary" cells in the table above.

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;
using namespace nlohmann::literals;

int main()
{
    // create a JSON value
    json j = R"({"compact": true, "schema": 0})"_json;

    // serialize it to CBOR
    std::vector<std::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. They can be ignored by passing cbor_tag_handler_t::ignore to function from_cbor. They can be stored by passing cbor_tag_handler_t::store to function from_cbor.

Example
#include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    // create byte vector
    std::vector<std::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
}

Last update: August 5, 2022