forked from bblanchon/ArduinoJson
@ -9,6 +9,7 @@ HEAD
|
|||||||
* Added `DeserializationError::EmptyInput` which tells if the input was empty
|
* Added `DeserializationError::EmptyInput` which tells if the input was empty
|
||||||
* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
|
* Added `DeserializationError::f_str()` which returns a `const __FlashStringHelper*` (issue #846)
|
||||||
* Added `operator|(JsonVariantConst, JsonVariantConst)`
|
* Added `operator|(JsonVariantConst, JsonVariantConst)`
|
||||||
|
* Added filtering for MessagePack (issue #1298, PR #1394 by Luca Passarella)
|
||||||
* Moved float convertion tables to PROGMEM
|
* Moved float convertion tables to PROGMEM
|
||||||
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
|
* Fixed `JsonVariant::set((char*)0)` which returned false instead of true (issue #1368)
|
||||||
* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
|
* Fixed error `No such file or directory #include <WString.h>` (issue #1381)
|
||||||
|
@ -62,6 +62,15 @@ TEST_CASE("Filtering") {
|
|||||||
"null",
|
"null",
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// Member is a string, but filter wants an array
|
||||||
|
"{\"example\":\"example\"}",
|
||||||
|
"{\"example\":[true]}",
|
||||||
|
10,
|
||||||
|
DeserializationError::Ok,
|
||||||
|
"{\"example\":null}",
|
||||||
|
JSON_OBJECT_SIZE(1) + 8
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Input is an array, but filter wants an object
|
// Input is an array, but filter wants an object
|
||||||
"[\"hello\",\"world\"]",
|
"[\"hello\",\"world\"]",
|
||||||
|
@ -8,6 +8,7 @@ add_executable(MsgPackDeserializerTests
|
|||||||
deserializeStaticVariant.cpp
|
deserializeStaticVariant.cpp
|
||||||
deserializeVariant.cpp
|
deserializeVariant.cpp
|
||||||
doubleToFloat.cpp
|
doubleToFloat.cpp
|
||||||
|
filter.cpp
|
||||||
incompleteInput.cpp
|
incompleteInput.cpp
|
||||||
input_types.cpp
|
input_types.cpp
|
||||||
misc.cpp
|
misc.cpp
|
||||||
|
1119
extras/tests/MsgPackDeserializer/filter.cpp
Normal file
1119
extras/tests/MsgPackDeserializer/filter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -637,47 +637,60 @@ class JsonDeserializer {
|
|||||||
DeserializationError _error;
|
DeserializationError _error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
// deserializeJson(JsonDocument&, const std::string&, ...)
|
// deserializeJson(JsonDocument&, const std::string&, ...)
|
||||||
template <typename TInput>
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TString>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, const TInput &input,
|
JsonDocument &doc, const TString &input,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
template <typename TInput>
|
// ... = Filter, NestingLimit
|
||||||
|
template <typename TString>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, const TInput &input, Filter filter,
|
JsonDocument &doc, const TString &input, Filter filter,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
template <typename TInput>
|
// ... = NestingLimit, Filter
|
||||||
DeserializationError deserializeJson(JsonDocument &doc, const TInput &input,
|
template <typename TString>
|
||||||
|
DeserializationError deserializeJson(JsonDocument &doc, const TString &input,
|
||||||
NestingLimit nestingLimit, Filter filter) {
|
NestingLimit nestingLimit, Filter filter) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deserializeJson(JsonDocument&, const std::istream&, ...)
|
//
|
||||||
template <typename TInput>
|
// deserializeJson(JsonDocument&, std::istream&, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TStream>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TInput &input,
|
JsonDocument &doc, TStream &input,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
template <typename TInput>
|
// ... = Filter, NestingLimit
|
||||||
|
template <typename TStream>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TInput &input, Filter filter,
|
JsonDocument &doc, TStream &input, Filter filter,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
template <typename TInput>
|
// ... = NestingLimit, Filter
|
||||||
DeserializationError deserializeJson(JsonDocument &doc, TInput &input,
|
template <typename TStream>
|
||||||
|
DeserializationError deserializeJson(JsonDocument &doc, TStream &input,
|
||||||
NestingLimit nestingLimit, Filter filter) {
|
NestingLimit nestingLimit, Filter filter) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// deserializeJson(JsonDocument&, char*, ...)
|
// deserializeJson(JsonDocument&, char*, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TChar *input,
|
JsonDocument &doc, TChar *input,
|
||||||
@ -685,19 +698,24 @@ DeserializationError deserializeJson(
|
|||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TChar *input, Filter filter,
|
JsonDocument &doc, TChar *input, Filter filter,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
|
DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
|
||||||
NestingLimit nestingLimit, Filter filter) {
|
NestingLimit nestingLimit, Filter filter) {
|
||||||
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
return deserialize<JsonDeserializer>(doc, input, nestingLimit, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// deserializeJson(JsonDocument&, char*, size_t, ...)
|
// deserializeJson(JsonDocument&, char*, size_t, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TChar *input, size_t inputSize,
|
JsonDocument &doc, TChar *input, size_t inputSize,
|
||||||
@ -705,6 +723,7 @@ DeserializationError deserializeJson(
|
|||||||
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
|
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(
|
DeserializationError deserializeJson(
|
||||||
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
|
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
|
||||||
@ -712,6 +731,7 @@ DeserializationError deserializeJson(
|
|||||||
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
|
return deserialize<JsonDeserializer>(doc, input, inputSize, nestingLimit,
|
||||||
filter);
|
filter);
|
||||||
}
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
|
DeserializationError deserializeJson(JsonDocument &doc, TChar *input,
|
||||||
size_t inputSize,
|
size_t inputSize,
|
||||||
|
@ -24,120 +24,241 @@ class MsgPackDeserializer {
|
|||||||
_error(DeserializationError::Ok),
|
_error(DeserializationError::Ok),
|
||||||
_foundSomething(false) {}
|
_foundSomething(false) {}
|
||||||
|
|
||||||
// TODO: add support for filter
|
template <typename TFilter>
|
||||||
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
DeserializationError parse(VariantData &variant, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
parseVariant(variant, nestingLimit);
|
parseVariant(variant, filter, nestingLimit);
|
||||||
return _foundSomething ? _error : DeserializationError::EmptyInput;
|
return _foundSomething ? _error : DeserializationError::EmptyInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parseVariant(VariantData &variant, NestingLimit nestingLimit) {
|
// Prevent VS warning "assignment operator could not be generated"
|
||||||
uint8_t code;
|
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
|
||||||
|
|
||||||
|
bool invalidInput() {
|
||||||
|
_error = DeserializationError::InvalidInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool notSupported() {
|
||||||
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TFilter>
|
||||||
|
bool parseVariant(VariantData &variant, TFilter filter,
|
||||||
|
NestingLimit nestingLimit) {
|
||||||
|
uint8_t code = 0; // TODO: why do we need to initialize this variable?
|
||||||
if (!readByte(code))
|
if (!readByte(code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_foundSomething = true;
|
_foundSomething = true;
|
||||||
|
|
||||||
if ((code & 0x80) == 0) {
|
bool allowValue = filter.allowValue();
|
||||||
variant.setUnsignedInteger(code);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xe0) {
|
|
||||||
variant.setSignedInteger(static_cast<int8_t>(code));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0) {
|
|
||||||
return readString(variant, code & 0x1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((code & 0xf0) == 0x90) {
|
|
||||||
return readArray(variant.toArray(), code & 0x0F, nestingLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((code & 0xf0) == 0x80) {
|
|
||||||
return readObject(variant.toObject(), code & 0x0F, nestingLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
// already null
|
// already null
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
case 0xc1:
|
||||||
|
return invalidInput();
|
||||||
|
|
||||||
case 0xc2:
|
case 0xc2:
|
||||||
variant.setBoolean(false);
|
if (allowValue)
|
||||||
|
variant.setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0xc3:
|
case 0xc3:
|
||||||
variant.setBoolean(true);
|
if (allowValue)
|
||||||
|
variant.setBoolean(true);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0xcc:
|
case 0xc4: // bin 8
|
||||||
return readInteger<uint8_t>(variant);
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipString<uint8_t>();
|
||||||
|
|
||||||
case 0xcd:
|
case 0xc5: // bin 16
|
||||||
return readInteger<uint16_t>(variant);
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipString<uint16_t>();
|
||||||
|
|
||||||
case 0xce:
|
case 0xc6: // bin 32
|
||||||
return readInteger<uint32_t>(variant);
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipString<uint32_t>();
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
case 0xc7: // ext 8
|
||||||
case 0xcf:
|
if (allowValue)
|
||||||
return readInteger<uint64_t>(variant);
|
return notSupported();
|
||||||
#endif
|
else
|
||||||
|
return skipExt<uint8_t>();
|
||||||
|
|
||||||
case 0xd0:
|
case 0xc8: // ext 16
|
||||||
return readInteger<int8_t>(variant);
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipExt<uint16_t>();
|
||||||
|
|
||||||
case 0xd1:
|
case 0xc9: // ext 32
|
||||||
return readInteger<int16_t>(variant);
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
case 0xd2:
|
else
|
||||||
return readInteger<int32_t>(variant);
|
return skipExt<uint32_t>();
|
||||||
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
|
||||||
case 0xd3:
|
|
||||||
return readInteger<int64_t>(variant);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case 0xca:
|
case 0xca:
|
||||||
return readFloat<float>(variant);
|
if (allowValue)
|
||||||
|
return readFloat<float>(variant);
|
||||||
|
else
|
||||||
|
return skipBytes(4);
|
||||||
|
|
||||||
case 0xcb:
|
case 0xcb:
|
||||||
return readDouble<double>(variant);
|
if (allowValue)
|
||||||
|
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 (allowValue)
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
return readInteger<uint64_t>(variant);
|
||||||
|
#else
|
||||||
|
return notSupported();
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return skipBytes(8);
|
||||||
|
|
||||||
|
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 (allowValue)
|
||||||
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
return readInteger<int64_t>(variant);
|
||||||
|
#else
|
||||||
|
return notSupported();
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return skipBytes(8);
|
||||||
|
|
||||||
|
case 0xd4: // fixext 1
|
||||||
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipBytes(2);
|
||||||
|
|
||||||
|
case 0xd5: // fixext 2
|
||||||
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipBytes(3);
|
||||||
|
|
||||||
|
case 0xd6: // fixext 4
|
||||||
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipBytes(5);
|
||||||
|
|
||||||
|
case 0xd7: // fixext 8
|
||||||
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipBytes(9);
|
||||||
|
|
||||||
|
case 0xd8: // fixext 16
|
||||||
|
if (allowValue)
|
||||||
|
return notSupported();
|
||||||
|
else
|
||||||
|
return skipBytes(17);
|
||||||
|
|
||||||
case 0xd9:
|
case 0xd9:
|
||||||
return readString<uint8_t>(variant);
|
if (allowValue)
|
||||||
|
return readString<uint8_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint8_t>();
|
||||||
|
|
||||||
case 0xda:
|
case 0xda:
|
||||||
return readString<uint16_t>(variant);
|
if (allowValue)
|
||||||
|
return readString<uint16_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint16_t>();
|
||||||
|
|
||||||
case 0xdb:
|
case 0xdb:
|
||||||
return readString<uint32_t>(variant);
|
if (allowValue)
|
||||||
|
return readString<uint32_t>(variant);
|
||||||
|
else
|
||||||
|
return skipString<uint32_t>();
|
||||||
|
|
||||||
case 0xdc:
|
case 0xdc:
|
||||||
return readArray<uint16_t>(variant.toArray(), nestingLimit);
|
return readArray<uint16_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
case 0xdd:
|
case 0xdd:
|
||||||
return readArray<uint32_t>(variant.toArray(), nestingLimit);
|
return readArray<uint32_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
case 0xde:
|
case 0xde:
|
||||||
return readObject<uint16_t>(variant.toObject(), nestingLimit);
|
return readObject<uint16_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
case 0xdf:
|
case 0xdf:
|
||||||
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
return readObject<uint32_t>(variant, filter, nestingLimit);
|
||||||
|
|
||||||
default:
|
|
||||||
_error = DeserializationError::NotSupported;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
switch (code & 0xf0) {
|
||||||
// Prevent VS warning "assignment operator could not be generated"
|
case 0x80:
|
||||||
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
|
return readObject(variant, code & 0x0F, filter, nestingLimit);
|
||||||
|
|
||||||
|
case 0x90:
|
||||||
|
return readArray(variant, code & 0x0F, filter, nestingLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((code & 0xe0) == 0xa0) {
|
||||||
|
if (allowValue)
|
||||||
|
return readString(variant, code & 0x1f);
|
||||||
|
else
|
||||||
|
return skipBytes(code & 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowValue)
|
||||||
|
variant.setInteger(static_cast<int8_t>(code));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool readByte(uint8_t &value) {
|
bool readByte(uint8_t &value) {
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
@ -161,6 +282,16 @@ class MsgPackDeserializer {
|
|||||||
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool skipBytes(size_t n) {
|
||||||
|
for (; n; --n) {
|
||||||
|
if (_reader.read() < 0) {
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readInteger(T &value) {
|
bool readInteger(T &value) {
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
@ -223,22 +354,30 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readString(const char *&str) {
|
bool readString() {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return false;
|
return false;
|
||||||
return readString(str, size);
|
return readString(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool skipString() {
|
||||||
|
T size;
|
||||||
|
if (!readInteger(size))
|
||||||
|
return false;
|
||||||
|
return skipBytes(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readString(VariantData &variant, size_t n) {
|
bool readString(VariantData &variant, size_t n) {
|
||||||
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
if (!readString(n))
|
||||||
if (!readString(s, n))
|
|
||||||
return false;
|
return false;
|
||||||
variant.setStringPointer(s, typename TStringStorage::storage_policy());
|
variant.setStringPointer(_stringStorage.save(),
|
||||||
|
typename TStringStorage::storage_policy());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readString(const char *&result, size_t n) {
|
bool readString(size_t n) {
|
||||||
_stringStorage.startString();
|
_stringStorage.startString();
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
@ -252,96 +391,135 @@ class MsgPackDeserializer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = _stringStorage.save();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize, typename TFilter>
|
||||||
bool readArray(CollectionData &array, NestingLimit nestingLimit) {
|
bool readArray(VariantData &variant, TFilter filter,
|
||||||
|
NestingLimit nestingLimit) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return false;
|
return false;
|
||||||
return readArray(array, size, nestingLimit);
|
return readArray(variant, size, filter, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) {
|
template <typename TFilter>
|
||||||
|
bool readArray(VariantData &variant, size_t n, TFilter filter,
|
||||||
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) {
|
if (nestingLimit.reached()) {
|
||||||
_error = DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool allowArray = filter.allowArray();
|
||||||
|
|
||||||
|
CollectionData *array = allowArray ? &variant.toArray() : 0;
|
||||||
|
|
||||||
|
TFilter memberFilter = filter[0U];
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantData *value = array.addElement(_pool);
|
VariantData *value;
|
||||||
if (!value) {
|
|
||||||
_error = DeserializationError::NoMemory;
|
if (memberFilter.allow()) {
|
||||||
return false;
|
value = array->addElement(_pool);
|
||||||
|
if (!value) {
|
||||||
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parseVariant(*value, nestingLimit.decrement()))
|
if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize, typename TFilter>
|
||||||
bool readObject(CollectionData &object, NestingLimit nestingLimit) {
|
bool readObject(VariantData &variant, TFilter filter,
|
||||||
|
NestingLimit nestingLimit) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return false;
|
return false;
|
||||||
return readObject(object, size, nestingLimit);
|
return readObject(variant, size, filter, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) {
|
template <typename TFilter>
|
||||||
|
bool readObject(VariantData &variant, size_t n, TFilter filter,
|
||||||
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) {
|
if (nestingLimit.reached()) {
|
||||||
_error = DeserializationError::TooDeep;
|
_error = DeserializationError::TooDeep;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollectionData *object = filter.allowObject() ? &variant.toObject() : 0;
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
if (!readKey())
|
||||||
if (!slot) {
|
|
||||||
_error = DeserializationError::NoMemory;
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const char *key = _stringStorage.c_str();
|
||||||
|
TFilter memberFilter = filter[key];
|
||||||
|
VariantData *member;
|
||||||
|
|
||||||
|
if (memberFilter.allow()) {
|
||||||
|
// Save key in memory pool.
|
||||||
|
// This MUST be done before adding the slot.
|
||||||
|
key = _stringStorage.save();
|
||||||
|
|
||||||
|
VariantSlot *slot = object->addSlot(_pool);
|
||||||
|
if (!slot) {
|
||||||
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot->setKey(key, typename TStringStorage::storage_policy());
|
||||||
|
|
||||||
|
member = slot->data();
|
||||||
|
} else {
|
||||||
|
member = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
if (!parseVariant(*member, memberFilter, nestingLimit.decrement()))
|
||||||
if (!parseKey(key))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
slot->setKey(key, typename TStringStorage::storage_policy());
|
|
||||||
|
|
||||||
if (!parseVariant(*slot->data(), nestingLimit.decrement()))
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseKey(const char *&key) {
|
bool readKey() {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code))
|
if (!readByte(code))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0)
|
if ((code & 0xe0) == 0xa0)
|
||||||
return readString(key, code & 0x1f);
|
return readString(code & 0x1f);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xd9:
|
case 0xd9:
|
||||||
return readString<uint8_t>(key);
|
return readString<uint8_t>();
|
||||||
|
|
||||||
case 0xda:
|
case 0xda:
|
||||||
return readString<uint16_t>(key);
|
return readString<uint16_t>();
|
||||||
|
|
||||||
case 0xdb:
|
case 0xdb:
|
||||||
return readString<uint32_t>(key);
|
return readString<uint32_t>();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_error = DeserializationError::NotSupported;
|
return notSupported();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool skipExt() {
|
||||||
|
T size;
|
||||||
|
if (!readInteger(size))
|
||||||
|
return false;
|
||||||
|
return skipBytes(size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
MemoryPool *_pool;
|
MemoryPool *_pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
@ -349,35 +527,111 @@ class MsgPackDeserializer {
|
|||||||
bool _foundSomething;
|
bool _foundSomething;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TInput>
|
//
|
||||||
|
// deserializeMsgPack(JsonDocument&, const std::string&, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TString>
|
||||||
DeserializationError deserializeMsgPack(
|
DeserializationError deserializeMsgPack(
|
||||||
JsonDocument &doc, const TInput &input,
|
JsonDocument &doc, const TString &input,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
template <typename TInput>
|
template <typename TString>
|
||||||
DeserializationError deserializeMsgPack(
|
DeserializationError deserializeMsgPack(
|
||||||
JsonDocument &doc, TInput *input,
|
JsonDocument &doc, const TString &input, Filter filter,
|
||||||
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
|
template <typename TString>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument &doc, const TString &input,
|
||||||
|
NestingLimit nestingLimit,
|
||||||
|
Filter filter) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// deserializeMsgPack(JsonDocument&, std::istream&, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TStream>
|
||||||
|
DeserializationError deserializeMsgPack(
|
||||||
|
JsonDocument &doc, TStream &input,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
template <typename TInput>
|
template <typename TStream>
|
||||||
DeserializationError deserializeMsgPack(
|
DeserializationError deserializeMsgPack(
|
||||||
JsonDocument &doc, TInput *input, size_t inputSize,
|
JsonDocument &doc, TStream &input, Filter filter,
|
||||||
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
|
template <typename TStream>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument &doc, TStream &input,
|
||||||
|
NestingLimit nestingLimit,
|
||||||
|
Filter filter) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// deserializeMsgPack(JsonDocument&, char*, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TChar>
|
||||||
|
DeserializationError deserializeMsgPack(
|
||||||
|
JsonDocument &doc, TChar *input,
|
||||||
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
||||||
|
AllowAllFilter());
|
||||||
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
|
template <typename TChar>
|
||||||
|
DeserializationError deserializeMsgPack(
|
||||||
|
JsonDocument &doc, TChar *input, Filter filter,
|
||||||
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
|
template <typename TChar>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
|
||||||
|
NestingLimit nestingLimit,
|
||||||
|
Filter filter) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// deserializeMsgPack(JsonDocument&, char*, size_t, ...)
|
||||||
|
//
|
||||||
|
// ... = NestingLimit
|
||||||
|
template <typename TChar>
|
||||||
|
DeserializationError deserializeMsgPack(
|
||||||
|
JsonDocument &doc, TChar *input, size_t inputSize,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||||
AllowAllFilter());
|
AllowAllFilter());
|
||||||
}
|
}
|
||||||
|
// ... = Filter, NestingLimit
|
||||||
template <typename TInput>
|
template <typename TChar>
|
||||||
DeserializationError deserializeMsgPack(
|
DeserializationError deserializeMsgPack(
|
||||||
JsonDocument &doc, TInput &input,
|
JsonDocument &doc, TChar *input, size_t inputSize, Filter filter,
|
||||||
NestingLimit nestingLimit = NestingLimit()) {
|
NestingLimit nestingLimit = NestingLimit()) {
|
||||||
return deserialize<MsgPackDeserializer>(doc, input, nestingLimit,
|
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||||
AllowAllFilter());
|
filter);
|
||||||
}
|
}
|
||||||
|
// ... = NestingLimit, Filter
|
||||||
|
template <typename TChar>
|
||||||
|
DeserializationError deserializeMsgPack(JsonDocument &doc, TChar *input,
|
||||||
|
size_t inputSize,
|
||||||
|
NestingLimit nestingLimit,
|
||||||
|
Filter filter) {
|
||||||
|
return deserialize<MsgPackDeserializer>(doc, input, inputSize, nestingLimit,
|
||||||
|
filter);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
Reference in New Issue
Block a user