# CBOR

The Concise Binary Object Representation (CBOR) is a data format whose design goals include the possibility of extremely small code sizes, fairly small message size, and extensibility without the need for version negotiation.

References

- [CBOR Website](http://cbor.io) - the main source on CBOR
- [CBOR Playground](http://cbor.me) - an interactive webpage to translate between JSON and CBOR
- [RFC 7049](https://tools.ietf.org/html/rfc7049) - the CBOR specification

## Serialization

The library uses the following mapping from JSON values types to CBOR types according to the CBOR specification ([RFC 7049](https://www.rfc-editor.org/rfc/rfc7049.html)):

| 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*: 24..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*: 24..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*: 24..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*: 24..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](https://json.nlohmann.me/features/binary_values/#cbor) 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
}
```
