* 📝 Fix documentation gaps for 3.13.0 release (todos 138-142) - Todo 138: Add "Known issues" section to modules.md with compiler-specific troubleshooting (GCC redefinition, MSVC symbol export). Add pointer note to quality_assurance.md. - Todo 139: Document CBOR/MessagePack half-precision float encoding for NaN/Infinity (0xF9/0xCA with exact byte sequences). Explain pre-3.13.0 double-precision bug mechanism without issue citations. - Todo 140: Document CBOR negative-integer-overflow rejection (parse_error.112) for magnitudes exceeding int64_t range (already implemented in rev 1). - Todo 141: Update version history in value.md and operator[].md with behavior-change details, removing issue citations per citation policy (prose is self-contained). - Todo 142: Global sed replace of 3.12.x → 3.13.0 placeholder across all 20 documentation files. Revision 2 incorporates feedback to reduce changelog-like issue citations. Only citations that add unique troubleshooting value are retained (#5103 for GCC workaround, #3970 for MSVC symbol export). "Known issues" section follows PR #5252's visual pattern (info admonition with bold-bullet format). Signed-off-by: Niels Lohmann <mail@nlohmann.me> * 📝 Document integer type selection, type_name() invalid value, and std::optional get() fix - number_handling.md: clarify that positive/negative integers select unsigned/signed storage based on the leading minus sign (todo 143). - type_name.md: document the new "invalid" return value for corrupted JSON values (todo 145). - get.md: note that get<std::optional<T>>() was unreachable in every configuration prior to 3.13.0 due to an internal macro-guard bug, unrelated to JSON_USE_IMPLICIT_CONVERSIONS's actual effect (todo 144). Signed-off-by: Niels Lohmann <mail@nlohmann.me> --------- Signed-off-by: Niels Lohmann <mail@nlohmann.me>
11 KiB
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):
| 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"
```