| # 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. |
| |
| !!! abstract "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. |
| |
| !!! success "Complete mapping" |
| |
| The mapping is **complete** in the sense that any JSON value type can be converted to a CBOR value. |
| |
| !!! info "NaN/infinity handling" |
| |
| `NaN`, `Infinity`, and `-Infinity` are serialized as a CBOR half-precision float (type 0xF9, 3 bytes total): |
| `NaN` as `0xF9 0x7E 0x00`, `Infinity` as `0xF9 0x7C 0x00`, and `-Infinity` as `0xF9 0xFC 0x00`. This behavior |
| differs from the normal JSON serialization which serializes NaN or Infinity to `null`. |
| |
| !!! note |
| |
| Prior to version 3.13.0, NaN and Infinity were instead serialized as a CBOR double-precision float (type 0xFB, |
| 9 bytes total), because the check used to select a smaller encoding compared magnitudes with NaN, which is |
| always `false` and caused the intended half-precision path to be skipped. |
| |
| !!! info "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) |
| |
| !!! info "Tagged items" |
| |
| Binary subtypes will be serialized as tagged items. See [binary values](../binary_values.md#cbor) for an example. |
| |
| ??? example |
| |
| ```cpp |
| --8<-- "examples/to_cbor.cpp" |
| ``` |
| |
| Output: |
| |
| ```c |
| --8<-- "examples/to_cbor.output" |
| ``` |
| |
| ## 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 | |
| |
| !!! warning "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) |
| |
| !!! warning "Negative integer overflow" |
| |
| CBOR negative integers (major type 1) are decoded as `-1 - n`. If the encoded magnitude `n` is too large for the |
| result to fit into `number_integer_t` (`std::int64_t` by default), parsing fails with a |
| [`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112) exception rather than overflowing |
| silently. |
| |
| !!! warning "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. |
| |
| !!! warning "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 |
| |
| ```cpp |
| --8<-- "examples/from_cbor.cpp" |
| ``` |
| |
| Output: |
| |
| ```json |
| --8<-- "examples/from_cbor.output" |
| ``` |