Skip to content

Commit

Permalink
Read MsgPack's 64-bit ints even if ARDUINOJSON_USE_LONG_LONG is 0
Browse files Browse the repository at this point in the history
  • Loading branch information
bblanchon committed Jun 18, 2024
1 parent e9c8785 commit 556785d
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 77 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
------
Expand Down
36 changes: 31 additions & 5 deletions extras/tests/MixedConfiguration/use_long_long_0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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);
}

std::string json;
serializeJson(doc, json);
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(json == "{\"A\":42,\"B\":84}");
REQUIRE(err == DeserializationError::Ok);
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
REQUIRE(doc.as<JsonInteger>() == 0x100000000);
#else
REQUIRE(doc.isNull());
#endif
}
}
}
105 changes: 33 additions & 72 deletions src/ArduinoJson/MsgPack/MsgPackDeserializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

template <typename T>
DeserializationError::Code readInteger(VariantData* variant) {
DeserializationError::Code err;
T value;
if (isSigned)
signedValue = static_cast<int8_t>(buffer[0]); // propagate sign bit
else
unsignedValue = static_cast<uint8_t>(buffer[0]);

err = readInteger(value);
if (err)
return err;
for (uint8_t i = 1; i < width; i++)
unsignedValue = (unsignedValue << 8) | buffer[i];

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;
}
Expand Down

0 comments on commit 556785d

Please sign in to comment.