Read MsgPack's 64-bit ints even if ARDUINOJSON_USE_LONG_LONG is 0

This commit is contained in:
Benoit Blanchon
2024-06-18 13:50:50 +02:00
parent e9c87858d1
commit 556785dc1e
3 changed files with 66 additions and 77 deletions

View File

@ -13,6 +13,8 @@ HEAD
Note: works only for reading, not for writing
* Support `ElementProxy` and `MemberProxy` in `JsonDocument`'s constructor
* Don't add partial objects when allocation fails (issue #2081)
* Read MsgPack's 64-bit integers even if `ARDUINOJSON_USE_LONG_LONG` is `0`
(they are set to `null` if they don't fit in a `long`)
v7.0.4 (2024-03-12)
------

View File

@ -3,14 +3,40 @@
#include <catch.hpp>
#include "Literals.hpp"
TEST_CASE("ARDUINOJSON_USE_LONG_LONG == 0") {
JsonDocument doc;
doc["A"] = 42;
doc["B"] = 84;
SECTION("smoke test") {
doc["A"] = 42;
doc["B"] = 84;
std::string json;
serializeJson(doc, json);
std::string json;
serializeJson(doc, json);
REQUIRE(json == "{\"A\":42,\"B\":84}");
REQUIRE(json == "{\"A\":42,\"B\":84}");
}
SECTION("deserializeMsgPack()") {
SECTION("cf 00 00 00 00 ff ff ff ff") {
auto err =
deserializeMsgPack(doc, "\xcf\x00\x00\x00\x00\xff\xff\xff\xff"_s);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.as<uint32_t>() == 0xFFFFFFFF);
}
SECTION("cf 00 00 00 01 00 00 00 00") {
auto err =
deserializeMsgPack(doc, "\xcf\x00\x00\x00\x01\x00\x00\x00\x00"_s);
REQUIRE(err == DeserializationError::Ok);
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
REQUIRE(doc.as<JsonInteger>() == 0x100000000);
#else
REQUIRE(doc.isNull());
#endif
}
}
}

View File

@ -54,6 +54,14 @@ class MsgPackDeserializer {
ARDUINOJSON_ASSERT(variant != 0);
}
if (code >= 0xcc && code <= 0xd3) {
auto width = uint8_t(1U << ((code - 0xcc) % 4));
if (allowValue)
return readInteger(variant, width, code >= 0xd0);
else
return skipBytes(width);
}
switch (code) {
case 0xc0:
// already null
@ -83,62 +91,6 @@ class MsgPackDeserializer {
return readDouble<double>(variant);
else
return skipBytes(8);
case 0xcc:
if (allowValue)
return readInteger<uint8_t>(variant);
else
return skipBytes(1);
case 0xcd:
if (allowValue)
return readInteger<uint16_t>(variant);
else
return skipBytes(2);
case 0xce:
if (allowValue)
return readInteger<uint32_t>(variant);
else
return skipBytes(4);
case 0xcf:
#if ARDUINOJSON_USE_LONG_LONG
if (allowValue)
return readInteger<uint64_t>(variant);
else
return skipBytes(8);
#else
return skipBytes(8); // not supported
#endif
case 0xd0:
if (allowValue)
return readInteger<int8_t>(variant);
else
return skipBytes(1);
case 0xd1:
if (allowValue)
return readInteger<int16_t>(variant);
else
return skipBytes(2);
case 0xd2:
if (allowValue)
return readInteger<int32_t>(variant);
else
return skipBytes(4);
case 0xd3:
#if ARDUINOJSON_USE_LONG_LONG
if (allowValue)
return readInteger<int64_t>(variant);
else
return skipBytes(8);
#else
return skipBytes(8); // not supported
#endif
}
if (code <= 0x7f || code >= 0xe0) { // fixint
@ -259,29 +211,38 @@ class MsgPackDeserializer {
return DeserializationError::Ok;
}
template <typename T>
DeserializationError::Code readInteger(T& value) {
DeserializationError::Code err;
DeserializationError::Code readInteger(VariantData* variant, uint8_t width,
bool isSigned) {
uint8_t buffer[8];
err = readBytes(value);
auto err = readBytes(buffer, width);
if (err)
return err;
fixEndianness(value);
union {
int64_t signedValue;
uint64_t unsignedValue;
};
return DeserializationError::Ok;
}
if (isSigned)
signedValue = static_cast<int8_t>(buffer[0]); // propagate sign bit
else
unsignedValue = static_cast<uint8_t>(buffer[0]);
template <typename T>
DeserializationError::Code readInteger(VariantData* variant) {
DeserializationError::Code err;
T value;
for (uint8_t i = 1; i < width; i++)
unsignedValue = (unsignedValue << 8) | buffer[i];
err = readInteger(value);
if (err)
return err;
variant->setInteger(value);
if (isSigned) {
auto truncatedValue = static_cast<JsonInteger>(signedValue);
if (truncatedValue == signedValue)
variant->setInteger(truncatedValue);
// else set null on overflow
} else {
auto truncatedValue = static_cast<JsonUInt>(unsignedValue);
if (truncatedValue == unsignedValue)
variant->setInteger(truncatedValue);
// else set null on overflow
}
return DeserializationError::Ok;
}