11// JsonhCpp (JSON for Humans)
2- // Version: 4.4
2+ // Version: 4.5
33// Link: https://github.com/jsonh-org/JsonhCpp
44// License: MIT
55
@@ -16261,7 +16261,7 @@ class binary_reader
1626116261 success = false;
1626216262 break;
1626316263 }
16264- result.push_back(static_cast<std::uint8_t >(current));
16264+ result.push_back(static_cast<typename binary_t::value_type >(current));
1626516265 }
1626616266 return success;
1626716267 }
@@ -21057,9 +21057,9 @@ class binary_writer
2105721057#pragma GCC diagnostic push
2105821058#pragma GCC diagnostic ignored "-Wfloat-equal"
2105921059#endif
21060- if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
21061- static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
21062- static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
21060+ if (!std::isfinite(n) || (( static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
21061+ static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
21062+ static_cast<double>(static_cast<float>(n)) == static_cast<double>(n)) ))
2106321063 {
2106421064 oa->write_character(format == detail::input_format_t::cbor
2106521065 ? get_cbor_float_prefix(static_cast<float>(n))
@@ -29182,29 +29182,50 @@ class jsonh_number_parser final {
2918229182 /// Output: <c>5200</c>
2918329183 /// </summary>
2918429184 static nonstd::expected<long double, std::string> parse(std::string jsonh_number) noexcept {
29185+ // Remove underscores
29186+ std::erase(jsonh_number, '_');
29187+ std::string_view digits = jsonh_number;
29188+
29189+ // Get sign
29190+ int sign = 1;
29191+ if (digits.starts_with('-')) {
29192+ sign = -1;
29193+ digits = digits.substr(1);
29194+ }
29195+ else if (digits.starts_with('+')) {
29196+ sign = 1;
29197+ digits = digits.substr(1);
29198+ }
29199+
2918529200 // Decimal
2918629201 std::string base_digits = "0123456789";
2918729202 // Hexadecimal
29188- if (jsonh_number .starts_with("0x") || jsonh_number .starts_with("0X")) {
29203+ if (digits .starts_with("0x") || digits .starts_with("0X")) {
2918929204 base_digits = "0123456789abcdef";
29190- jsonh_number.erase(0, 2);
29205+ digits = digits.substr( 2);
2919129206 }
2919229207 // Binary
29193- else if (jsonh_number .starts_with("0b") || jsonh_number .starts_with("0B")) {
29208+ else if (digits .starts_with("0b") || digits .starts_with("0B")) {
2919429209 base_digits = "01";
29195- jsonh_number.erase(0, 2);
29210+ digits = digits.substr( 2);
2919629211 }
2919729212 // Octal
29198- else if (jsonh_number .starts_with("0o") || jsonh_number .starts_with("0O")) {
29213+ else if (digits .starts_with("0o") || digits .starts_with("0O")) {
2919929214 base_digits = "01234567";
29200- jsonh_number.erase(0, 2);
29215+ digits = digits.substr( 2);
2920129216 }
2920229217
29203- // Remove underscores
29204- std::erase(jsonh_number, '_');
29205-
2920629218 // Parse number with base digits
29207- return parse_fractional_number_with_exponent(jsonh_number, base_digits);
29219+ nonstd::expected<long double, std::string> number = parse_fractional_number_with_exponent(digits, base_digits);
29220+ if (!number) {
29221+ return nonstd::unexpected<std::string>(number.error());
29222+ }
29223+
29224+ // Apply sign
29225+ if (sign != 1) {
29226+ number.value() *= sign;
29227+ }
29228+ return number;
2920829229 }
2920929230
2921029231private:
@@ -30496,46 +30517,57 @@ class jsonh_reader : utf8_reader {
3049630517 }
3049730518 }
3049830519 nonstd::expected<jsonh_token, std::string> read_number(std::string& number_builder) noexcept {
30520+ // Read sign
30521+ std::optional<std::string> sign = read_any({ "-", "+" });
30522+ if (sign) {
30523+ number_builder += sign.value();
30524+ }
30525+
3049930526 // Read base
3050030527 std::string base_digits = "0123456789";
30528+ bool has_base_specifier = false;
3050130529 if (read_one("0")) {
3050230530 number_builder += '0';
3050330531
3050430532 std::optional<std::string> hex_base_char = read_any({ "x", "X" });
3050530533 if (hex_base_char) {
3050630534 number_builder += hex_base_char.value();
3050730535 base_digits = "0123456789abcdef";
30536+ has_base_specifier = true;
3050830537 }
3050930538 else {
3051030539 std::optional<std::string> binary_base_char = read_any({ "b", "B" });
30511- if (hex_base_char ) {
30540+ if (binary_base_char ) {
3051230541 number_builder += binary_base_char.value();
3051330542 base_digits = "01";
30543+ has_base_specifier = true;
3051430544 }
3051530545 else {
3051630546 std::optional<std::string> octal_base_char = read_any({ "o", "O" });
3051730547 if (octal_base_char) {
3051830548 number_builder += octal_base_char.value();
3051930549 base_digits = "01234567";
30550+ has_base_specifier = true;
3052030551 }
3052130552 }
3052230553 }
3052330554 }
3052430555
3052530556 // Read main number
30526- nonstd::expected<void, std::string> main_result = read_number_no_exponent(number_builder, base_digits);
30557+ nonstd::expected<void, std::string> main_result = read_number_no_exponent(number_builder, base_digits, has_base_specifier );
3052730558 if (!main_result) {
3052830559 return nonstd::unexpected<std::string>(main_result.error());
3052930560 }
3053030561
3053130562 // Hexadecimal exponent
3053230563 if (number_builder.back() == 'e' || number_builder.back() == 'E') {
30564+ // Read sign
3053330565 std::optional<std::string> exponent_sign = read_any({ "+", "-" });
3053430566 if (exponent_sign) {
3053530567 number_builder += exponent_sign.value();
3053630568
3053730569 // Read exponent number
30538- nonstd::expected<void, std::string> exponent_result = read_number_no_exponent(number_builder, base_digits);
30570+ nonstd::expected<void, std::string> exponent_result = read_number_no_exponent(number_builder, base_digits, has_base_specifier );
3053930571 if (!exponent_result) {
3054030572 return nonstd::unexpected<std::string>(exponent_result.error());
3054130573 }
@@ -30547,8 +30579,14 @@ class jsonh_reader : utf8_reader {
3054730579 if (exponent_char) {
3054830580 number_builder += exponent_char.value();
3054930581
30582+ // Read sign
30583+ std::optional<std::string> exponent_sign = read_any({ "-", "+" });
30584+ if (exponent_sign) {
30585+ number_builder += exponent_sign.value();
30586+ }
30587+
3055030588 // Read exponent number
30551- nonstd::expected<void, std::string> exponent_result = read_number_no_exponent(number_builder, base_digits);
30589+ nonstd::expected<void, std::string> exponent_result = read_number_no_exponent(number_builder, base_digits, has_base_specifier );
3055230590 if (!exponent_result) {
3055330591 return nonstd::unexpected<std::string>(exponent_result.error());
3055430592 }
@@ -30558,12 +30596,9 @@ class jsonh_reader : utf8_reader {
3055830596 // End of number
3055930597 return jsonh_token(json_token_type::number, number_builder);
3056030598 }
30561- nonstd::expected<void, std::string> read_number_no_exponent(std::string& number_builder, std::string_view base_digits) noexcept {
30562- // Read sign
30563- read_any({ "-", "+" });
30564-
30599+ nonstd::expected<void, std::string> read_number_no_exponent(std::string& number_builder, std::string_view base_digits, bool has_base_specifier) noexcept {
3056530600 // Leading underscore
30566- if (read_one( "_") ) {
30601+ if (!has_base_specifier && peek() == "_") {
3056730602 return nonstd::unexpected<std::string>("Leading `_` in number");
3056830603 }
3056930604
@@ -30581,12 +30616,12 @@ class jsonh_reader : utf8_reader {
3058130616 read();
3058230617 number_builder += next.value();
3058330618 }
30584- // Decimal point
30619+ // Dot
3058530620 else if (next.value() == ".") {
3058630621 read();
3058730622 number_builder += next.value();
3058830623
30589- // Duplicate decimal point
30624+ // Duplicate dot
3059030625 if (is_fraction) {
3059130626 return nonstd::unexpected<std::string>("Duplicate `.` in number");
3059230627 }
@@ -30608,6 +30643,11 @@ class jsonh_reader : utf8_reader {
3060830643 return nonstd::unexpected<std::string>("Empty number");
3060930644 }
3061030645
30646+ // Ensure at least one digit
30647+ if (number_builder.find_first_not_of(".-+_") == std::string::npos) {
30648+ return nonstd::unexpected<std::string>("Number must have at least one digit");
30649+ }
30650+
3061130651 // Trailing underscore
3061230652 if (number_builder.ends_with('_')) {
3061330653 return nonstd::unexpected<std::string>("Trailing `_` in number");
0 commit comments