diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 864561cf3..988dffe96 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2072,7 +2072,7 @@ class binary_reader { return false; } - result = static_cast(number); + result = detail::conditional_static_cast(number); return true; } case '[': @@ -2266,17 +2266,20 @@ class binary_reader } case 'h': { - unsigned int byte2 = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "half"))) + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) { return false; } - unsigned int byte1 = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "half"))) + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) { return false; } + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + // code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often @@ -2285,13 +2288,13 @@ class binary_reader // without such support. An example of a small decoder for // half-precision floating-point numbers in the C language // is shown in Fig. 3. - unsigned int half = (byte1 << 8) + byte2; + const auto half = static_cast((byte2 << 8u) + byte1); const double val = [&half] { - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(0 <= mant&& mant <= 1024); + JSON_ASSERT(mant <= 1024); switch (exp) { case 0: @@ -2304,7 +2307,7 @@ class binary_reader return std::ldexp(mant + 1024, exp - 25); } }(); - return sax->number_float((half & 0x8000) != 0 + return sax->number_float((half & 0x8000u) != 0 ? static_cast(-val) : static_cast(val), ""); } diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 66aa7e0d2..29c0c279e 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -1454,14 +1454,6 @@ class binary_writer } write_number(static_cast(n)); } - else if (is_bjdata && ((std::numeric_limits::min)() <= static_cast(n) && static_cast(n) <= (std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('M')); // uint64 - bjdata only - } - write_number(static_cast(n)); - } // LCOV_EXCL_START else { @@ -1523,10 +1515,6 @@ class binary_writer { return 'L'; } - if (is_bjdata && ((std::numeric_limits::min)() <= static_cast(j.m_value.number_integer) && static_cast(j.m_value.number_integer) <= (std::numeric_limits::max)())) - { - return 'M'; - } // anything else is treated as high-precision number return 'H'; // LCOV_EXCL_LINE } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 134713fd3..6b1a7dd41 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -10448,7 +10448,7 @@ class binary_reader { return false; } - result = static_cast(number); + result = detail::conditional_static_cast(number); return true; } case '[': @@ -10642,17 +10642,20 @@ class binary_reader } case 'h': { - unsigned int byte2 = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "half"))) + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) { return false; } - unsigned int byte1 = get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "half"))) + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number"))) { return false; } + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + // code from RFC 7049, Appendix D, Figure 3: // As half-precision floating-point numbers were only added // to IEEE 754 in 2008, today's programming platforms often @@ -10661,13 +10664,13 @@ class binary_reader // without such support. An example of a small decoder for // half-precision floating-point numbers in the C language // is shown in Fig. 3. - unsigned int half = (byte1 << 8) + byte2; + const auto half = static_cast((byte2 << 8u) + byte1); const double val = [&half] { - const int exp = (half >> 10) & 0x1F; - const int mant = half & 0x3FF; + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; JSON_ASSERT(0 <= exp&& exp <= 32); - JSON_ASSERT(0 <= mant&& mant <= 1024); + JSON_ASSERT(mant <= 1024); switch (exp) { case 0: @@ -10680,7 +10683,7 @@ class binary_reader return std::ldexp(mant + 1024, exp - 25); } }(); - return sax->number_float((half & 0x8000) != 0 + return sax->number_float((half & 0x8000u) != 0 ? static_cast(-val) : static_cast(val), ""); } @@ -15238,14 +15241,6 @@ class binary_writer } write_number(static_cast(n)); } - else if (is_bjdata && ((std::numeric_limits::min)() <= static_cast(n) && static_cast(n) <= (std::numeric_limits::max)())) - { - if (add_prefix) - { - oa->write_character(to_char_type('M')); // uint64 - bjdata only - } - write_number(static_cast(n)); - } // LCOV_EXCL_START else { @@ -15307,10 +15302,6 @@ class binary_writer { return 'L'; } - if (is_bjdata && ((std::numeric_limits::min)() <= static_cast(j.m_value.number_integer) && static_cast(j.m_value.number_integer) <= (std::numeric_limits::max)())) - { - return 'M'; - } // anything else is treated as high-precision number return 'H'; // LCOV_EXCL_LINE } diff --git a/test/src/unit-bjdata.cpp b/test/src/unit-bjdata.cpp index a8a1b75c3..f0519c5ca 100644 --- a/test/src/unit-bjdata.cpp +++ b/test/src/unit-bjdata.cpp @@ -1810,7 +1810,7 @@ TEST_CASE("BJData") } } - SECTION("array with uint32_t elements") + SECTION("array with int32_t elements") { SECTION("size=false type=false") { @@ -2588,6 +2588,40 @@ TEST_CASE("BJData") CHECK(json::from_bjdata(v, true, false).is_discarded()); } + SECTION("ndarrays") + { + std::vector vST = {'[', '$', 'i', '#', '[', '$', 'i', '#'}; + json _; + CHECK_THROWS_AS(_ = json::from_bjdata(vST), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(vST), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0xFF"); + CHECK(json::from_bjdata(vST, true, false).is_discarded()); + + std::vector v = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'i', 2, 1, 2}; + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 13: syntax error while parsing BJData number: unexpected end of input"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); + + std::vector vS = {'[', '$', 'i', '#', '[', '#', 'i', 2, 1, 2, 1}; + CHECK_THROWS_AS(_ = json::from_bjdata(vS), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(vS), "[json.exception.parse_error.113] parse error at byte 9: syntax error while parsing BJData size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x01"); + CHECK(json::from_bjdata(vS, true, false).is_discarded()); + + std::vector vT = {'[', '$', 'i', '#', '[', 'i', 2, 'i'}; + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 13: syntax error while parsing BJData number: unexpected end of input"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); + + std::vector vm = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'm', 1, 0, 0, 0}; + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 13: syntax error while parsing BJData number: unexpected end of input"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); + + std::vector vM = {'[', '$', 'i', '#', '[', '$', 'i', '#', 'M', 1, 0, 0, 0, 0, 0, 0, 0}; + CHECK_THROWS_AS(_ = json::from_bjdata(v), json::parse_error&); + CHECK_THROWS_WITH(_ = json::from_bjdata(v), "[json.exception.parse_error.110] parse error at byte 13: syntax error while parsing BJData number: unexpected end of input"); + CHECK(json::from_bjdata(v, true, false).is_discarded()); + } + SECTION("objects") { std::vector vST = {'{', '$', 'i', '#', 'i', 2, 'i', 1, 'a', 1};