diff --git a/docs/mkdocs/docs/api/basic_json/binary_t.md b/docs/mkdocs/docs/api/basic_json/binary_t.md index da13c22a2..2e9517429 100644 --- a/docs/mkdocs/docs/api/basic_json/binary_t.md +++ b/docs/mkdocs/docs/api/basic_json/binary_t.md @@ -90,8 +90,9 @@ type `#!cpp binary_t*` must be dereferenced. - MessagePack - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, or 16 elements, the fixext family (fixext1, - fixext2, fixext4, fixext8) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The subtype is - then added as a signed 8-bit integer. + fixext2, fixext4, fixext8, fixext16) is used. For other sizes, the ext family (ext8, ext16, ext32) is used. The + subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative (reserved) ext + types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255. - If no subtype is given, the bin family (bin8, bin16, bin32) is used. - BSON diff --git a/docs/mkdocs/docs/api/basic_json/to_msgpack.md b/docs/mkdocs/docs/api/basic_json/to_msgpack.md index dca66271d..181948ef1 100644 --- a/docs/mkdocs/docs/api/basic_json/to_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/to_msgpack.md @@ -53,7 +53,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va value, array, or object exceeds 4294967295, the maximum MessagePack can store; example: `"MessagePack length 4294967296 exceeds maximum of 4294967295"` - Throws [`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415) if the subtype of a binary value - exceeds 255, the maximum of the MessagePack ext type; example: + exceeds 255, the largest value the library can store in the one-byte MessagePack ext type; example: `"subtype 70000 is too large for the MessagePack ext type (max 255)"` - Throws [type_error.316](../../home/exceptions.md#jsonexceptiontype_error316) if a string or object key in `j` is not valid UTF-8 and `error_handler` is `strict` diff --git a/docs/mkdocs/docs/features/binary_formats/index.md b/docs/mkdocs/docs/features/binary_formats/index.md index 8024b99cf..9c55a9a52 100644 --- a/docs/mkdocs/docs/features/binary_formats/index.md +++ b/docs/mkdocs/docs/features/binary_formats/index.md @@ -22,7 +22,7 @@ to efficiently encode JSON values to byte vectors and to decode such vectors. | BON8 | incomplete: no unsigned integers above int64 | complete | | BSON | incomplete: top-level value must be an object | incomplete, but all JSON types are supported | | CBOR | complete | incomplete, but all JSON types are supported | -| MessagePack | complete | complete | +| MessagePack | complete | incomplete, but all JSON types are supported | | UBJSON | complete | complete | ### Binary values diff --git a/docs/mkdocs/docs/features/binary_formats/messagepack.md b/docs/mkdocs/docs/features/binary_formats/messagepack.md index 90e4c295e..f752ea2c8 100644 --- a/docs/mkdocs/docs/features/binary_formats/messagepack.md +++ b/docs/mkdocs/docs/features/binary_formats/messagepack.md @@ -11,7 +11,7 @@ extra byte in addition to the strings themselves. ## Byte layout -MessagePack encodes each value as a one-byte *format marker*, optionally followed by a length or the payload. The marker range is partitioned to keep common values small: small non-negative integers (0 to 127) and small negative integers (-32 to -1) are the marker byte itself; short strings, arrays, and maps (up to 31 or 15 elements) hide their length in the marker's lower bits. Larger values use dedicated markers that announce the width (8, 16, 32, or 64 bits) of the length or number that follows, in big-endian byte order. Like CBOR, containers are length-prefixed, so no terminator is needed. +MessagePack encodes each value as a one-byte *format marker*, optionally followed by a length or the payload. The marker range is partitioned to keep common values small: small non-negative integers (0 to 127) and small negative integers (-32 to -1) are the marker byte itself; short strings, arrays, and maps (up to 31 bytes for strings and up to 15 elements for arrays and maps) hide their length in the marker's lower bits. Larger values use dedicated markers that announce the width (8, 16, 32, or 64 bits) of the length or number that follows, in big-endian byte order. Like CBOR, containers are length-prefixed, so no terminator is needed. Consider the following JSON value (shown formatted for readability): @@ -109,8 +109,9 @@ specification: !!! note Prior to version 3.13.0, NaN and Infinity were instead serialized as a MessagePack float 64 (type 0xCB, 9 bytes - total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is - always `false` and caused the float 32 path to be skipped. + total), because the check used to select the smaller float 32 encoding failed for NaN (all comparisons are `false`) + and for Infinity and -Infinity (outside the float range checked against `std::numeric_limits::lowest()` and + `max()`), so the float 32 path was skipped. ??? example "Example: serialize a JSON value to MessagePack" @@ -166,6 +167,29 @@ The library maps MessagePack types to JSON value types as follows: | fixext 8 | binary | 0xD7 | | fixext 16 | binary | 0xD8 | | negative fixint | number_integer | 0xE0-0xFF | +| (never used) | – | 0xC1 | + +The byte 0xC1 is reserved as "never used" by the specification and is rejected with +[`parse_error.112`](../../home/exceptions.md#jsonexceptionparse_error112). + +### Extension types (ext, fixext) + +MessagePack ext and fixext values are read as binary values, and the ext type byte is stored as the binary subtype. +Although the specification defines the type as a signed 8-bit integer (0 to 127 for applications, -128 to -1 reserved, +with -1 being the Timestamp extension), the library reads it as an unsigned byte: a negative ext type `n` becomes +subtype `256+n`, so ext type -1 is read as subtype 255 and -128 as subtype 128. The Timestamp extension is not +interpreted; it is returned as binary with subtype 255. Use +[`has_subtype()`](../../api/byte_container_with_subtype/has_subtype.md) to tell a `bin` value (no subtype) from an ext +value (subtype, even if it is 0). + +When serializing, a binary value with a subtype is always written as fixext (1, 2, 4, 8, or 16 bytes) or ext, even +for subtype 0 (`d6 00 01 02 03 04`); a binary value without a subtype is written as bin. Subtypes 128 to 255 are +written as the reserved negative ext types (255 as -1), so `json::binary({1,2,3,4}, 255)` becomes +`d6 ff 01 02 03 04`, which other MessagePack libraries decode as a 32-bit timestamp. A subtype above 255 throws +[`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415). The payload length is limited to +4294967295 bytes like all other lengths. + +Duplicate keys in a map are accepted; the last value wins. !!! info @@ -177,7 +201,8 @@ The library maps MessagePack types to JSON value types as follows: JSON-compatible [profile](https://github.com/msgpack/msgpack/blob/master/spec.md#profile) sketched in the MessagePack specification, this library restricts map keys to `str` values. Maps with keys of any other type are rejected with a [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113) exception (or, with - `allow_exceptions` set to `false`, a discarded value) naming the type of the key that was found, for instance: + `allow_exceptions` set to `false`, a discarded value). For most key types the message names the type that was + found, for instance: ``` [json.exception.parse_error.113] parse error at byte 2: syntax error while parsing MessagePack object key: only string keys are supported, but found nil; last byte: 0xC0 @@ -189,7 +214,7 @@ The library maps MessagePack types to JSON value types as follows: !!! warning "Ill-formed UTF-8 in string values" The MessagePack specification explicitly allows a `str` value (`fixstr`, `str 8`, `str 16`, `str 32`) to contain - a byte sequence that is not valid UTF-8, and expects a deserializer to hand the original bytes back unchanged. + a byte sequence that is not valid UTF-8, and recommends that a deserializer provide a way to obtain the original bytes. This library follows that by default: with its [`error_handler`](../../api/basic_json/from_msgpack.md) parameter left at `keep` (the default), `from_msgpack()` reads `str` bytes (object keys included) as-is, without validating them, so such a value diff --git a/docs/mkdocs/docs/features/binary_values.md b/docs/mkdocs/docs/features/binary_values.md index dd683f469..f5a87472b 100644 --- a/docs/mkdocs/docs/features/binary_values.md +++ b/docs/mkdocs/docs/features/binary_values.md @@ -324,8 +324,9 @@ representation using the length of the byte array. ### MessagePack [MessagePack](binary_formats/messagepack.md) supports binary values and subtypes. If a subtype is given, the ext family -is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, ext8, ext16, and -ext32. The subtype is then added as a signed 8-bit integer. +is used. The library will choose the smallest representation among fixext1, fixext2, fixext4, fixext8, fixext16, ext8, +ext16, and ext32. The subtype is then written as the signed 8-bit ext type: subtypes 128 to 255 map to the negative +(reserved) ext types, and on reading the ext type is exposed as an unsigned subtype from 0 to 255. If no subtype is given, the bin family (bin8, bin16, bin32) is used. diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md index 4b8f6edd9..fea326698 100644 --- a/docs/mkdocs/docs/home/exceptions.md +++ b/docs/mkdocs/docs/home/exceptions.md @@ -1153,7 +1153,7 @@ A JSON Patch `move` operation's `"from"` location is a proper prefix of its `"pa ### json.exception.out_of_range.415 MessagePack's ext type and BSON's binary subtype are each stored in a single byte. This exception is thrown when serializing a -[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md) whose subtype exceeds 255. +[`byte_container_with_subtype`](../api/byte_container_with_subtype/index.md) whose subtype exceeds 255, the largest value the library can store in that byte. !!! failure "Example message"