forked from bblanchon/ArduinoJson
Moved nesting decrement logic to class NestingLimit
This commit is contained in:
@ -5,13 +5,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Namespace.hpp>
|
||||
#include <ArduinoJson/Polyfills/assert.hpp>
|
||||
|
||||
namespace ARDUINOJSON_NAMESPACE {
|
||||
|
||||
struct NestingLimit {
|
||||
NestingLimit() : value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
explicit NestingLimit(uint8_t n) : value(n) {}
|
||||
class NestingLimit {
|
||||
public:
|
||||
NestingLimit() : _value(ARDUINOJSON_DEFAULT_NESTING_LIMIT) {}
|
||||
explicit NestingLimit(uint8_t n) : _value(n) {}
|
||||
|
||||
uint8_t value;
|
||||
NestingLimit decrement() const {
|
||||
ARDUINOJSON_ASSERT(_value > 0);
|
||||
return NestingLimit(static_cast<uint8_t>(_value - 1));
|
||||
}
|
||||
|
||||
bool reached() const {
|
||||
return _value == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t _value;
|
||||
};
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
@ -15,9 +15,9 @@ namespace ARDUINOJSON_NAMESPACE {
|
||||
template <template <typename, typename> class TDeserializer, typename TReader,
|
||||
typename TWriter>
|
||||
TDeserializer<TReader, TWriter> makeDeserializer(MemoryPool &pool,
|
||||
TReader reader, TWriter writer,
|
||||
uint8_t nestingLimit) {
|
||||
return TDeserializer<TReader, TWriter>(pool, reader, writer, nestingLimit);
|
||||
TReader reader,
|
||||
TWriter writer) {
|
||||
return TDeserializer<TReader, TWriter>(pool, reader, writer);
|
||||
}
|
||||
|
||||
// deserialize(JsonDocument&, const std::string&, NestingLimit, Filter);
|
||||
@ -34,8 +34,8 @@ deserialize(JsonDocument &doc, const TString &input, NestingLimit nestingLimit,
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), reader,
|
||||
makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
|
||||
.parse(doc.data(), filter);
|
||||
makeStringStorage(doc.memoryPool(), input))
|
||||
.parse(doc.data(), filter, nestingLimit);
|
||||
}
|
||||
//
|
||||
// deserialize(JsonDocument&, char*, size_t, NestingLimit, Filter);
|
||||
@ -50,8 +50,8 @@ DeserializationError deserialize(JsonDocument &doc, TChar *input,
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), reader,
|
||||
makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
|
||||
.parse(doc.data(), filter);
|
||||
makeStringStorage(doc.memoryPool(), input))
|
||||
.parse(doc.data(), filter, nestingLimit);
|
||||
}
|
||||
//
|
||||
// deserialize(JsonDocument&, std::istream&, NestingLimit, Filter);
|
||||
@ -64,8 +64,8 @@ DeserializationError deserialize(JsonDocument &doc, TStream &input,
|
||||
doc.clear();
|
||||
return makeDeserializer<TDeserializer>(
|
||||
doc.memoryPool(), reader,
|
||||
makeStringStorage(doc.memoryPool(), input), nestingLimit.value)
|
||||
.parse(doc.data(), filter);
|
||||
makeStringStorage(doc.memoryPool(), input))
|
||||
.parse(doc.data(), filter, nestingLimit);
|
||||
}
|
||||
|
||||
} // namespace ARDUINOJSON_NAMESPACE
|
||||
|
@ -23,15 +23,13 @@ class JsonDeserializer {
|
||||
|
||||
public:
|
||||
JsonDeserializer(MemoryPool &pool, TReader reader,
|
||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||
: _pool(&pool),
|
||||
_stringStorage(stringStorage),
|
||||
_nestingLimit(nestingLimit),
|
||||
_latch(reader) {}
|
||||
TStringStorage stringStorage)
|
||||
: _pool(&pool), _stringStorage(stringStorage), _latch(reader) {}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parse(VariantData &variant, TFilter filter) {
|
||||
DeserializationError err = parseVariant(variant, filter);
|
||||
DeserializationError parse(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
DeserializationError err = parseVariant(variant, filter, nestingLimit);
|
||||
|
||||
if (!err && _latch.last() != 0 && !variant.isEnclosed()) {
|
||||
// We don't detect trailing characters earlier, so we need to check now
|
||||
@ -59,22 +57,23 @@ class JsonDeserializer {
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parseVariant(VariantData &variant, TFilter filter) {
|
||||
DeserializationError parseVariant(VariantData &variant, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
DeserializationError err = skipSpacesAndComments();
|
||||
if (err) return err;
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
if (filter.allowArray())
|
||||
return parseArray(variant.toArray(), filter);
|
||||
return parseArray(variant.toArray(), filter, nestingLimit);
|
||||
else
|
||||
return skipArray();
|
||||
return skipArray(nestingLimit);
|
||||
|
||||
case '{':
|
||||
if (filter.allowObject())
|
||||
return parseObject(variant.toObject(), filter);
|
||||
return parseObject(variant.toObject(), filter, nestingLimit);
|
||||
else
|
||||
return skipObject();
|
||||
return skipObject(nestingLimit);
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
@ -91,16 +90,16 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError skipVariant() {
|
||||
DeserializationError skipVariant(NestingLimit nestingLimit) {
|
||||
DeserializationError err = skipSpacesAndComments();
|
||||
if (err) return err;
|
||||
|
||||
switch (current()) {
|
||||
case '[':
|
||||
return skipArray();
|
||||
return skipArray(nestingLimit);
|
||||
|
||||
case '{':
|
||||
return skipObject();
|
||||
return skipObject(nestingLimit);
|
||||
|
||||
case '\"':
|
||||
case '\'':
|
||||
@ -112,8 +111,9 @@ class JsonDeserializer {
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parseArray(CollectionData &array, TFilter filter) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
DeserializationError parseArray(CollectionData &array, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
// Check opening braket
|
||||
if (!eat('[')) return DeserializationError::InvalidInput;
|
||||
@ -135,14 +135,10 @@ class JsonDeserializer {
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
// 1 - Parse value
|
||||
_nestingLimit--;
|
||||
err = parseVariant(*value, memberFilter);
|
||||
_nestingLimit++;
|
||||
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
} else {
|
||||
_nestingLimit--;
|
||||
err = skipVariant();
|
||||
_nestingLimit++;
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
}
|
||||
|
||||
@ -156,8 +152,8 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError skipArray() {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
DeserializationError skipArray(NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
// Check opening braket
|
||||
if (!eat('[')) return DeserializationError::InvalidInput;
|
||||
@ -165,9 +161,7 @@ class JsonDeserializer {
|
||||
// Read each value
|
||||
for (;;) {
|
||||
// 1 - Skip value
|
||||
_nestingLimit--;
|
||||
DeserializationError err = skipVariant();
|
||||
_nestingLimit++;
|
||||
DeserializationError err = skipVariant(nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
|
||||
// 2 - Skip spaces
|
||||
@ -181,8 +175,9 @@ class JsonDeserializer {
|
||||
}
|
||||
|
||||
template <typename TFilter>
|
||||
DeserializationError parseObject(CollectionData &object, TFilter filter) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
DeserializationError parseObject(CollectionData &object, TFilter filter,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
// Check opening brace
|
||||
if (!eat('{')) return DeserializationError::InvalidInput;
|
||||
@ -221,15 +216,11 @@ class JsonDeserializer {
|
||||
}
|
||||
|
||||
// Parse value
|
||||
_nestingLimit--;
|
||||
err = parseVariant(*variant, memberFilter);
|
||||
_nestingLimit++;
|
||||
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
} else {
|
||||
_stringStorage.reclaim(key);
|
||||
_nestingLimit--;
|
||||
err = skipVariant();
|
||||
_nestingLimit++;
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
}
|
||||
|
||||
@ -247,8 +238,8 @@ class JsonDeserializer {
|
||||
}
|
||||
}
|
||||
|
||||
DeserializationError skipObject() {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
DeserializationError skipObject(NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
// Check opening brace
|
||||
if (!eat('{')) return DeserializationError::InvalidInput;
|
||||
@ -263,7 +254,7 @@ class JsonDeserializer {
|
||||
// Read each key value pair
|
||||
for (;;) {
|
||||
// Skip key
|
||||
err = skipVariant();
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
|
||||
// Skip spaces
|
||||
@ -272,9 +263,7 @@ class JsonDeserializer {
|
||||
if (!eat(':')) return DeserializationError::InvalidInput;
|
||||
|
||||
// Skip value
|
||||
_nestingLimit--;
|
||||
err = skipVariant();
|
||||
_nestingLimit++;
|
||||
err = skipVariant(nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
|
||||
// Skip spaces
|
||||
@ -538,7 +527,6 @@ class JsonDeserializer {
|
||||
|
||||
MemoryPool *_pool;
|
||||
TStringStorage _stringStorage;
|
||||
uint8_t _nestingLimit;
|
||||
Latch<TReader> _latch;
|
||||
};
|
||||
|
||||
|
@ -20,15 +20,16 @@ class MsgPackDeserializer {
|
||||
|
||||
public:
|
||||
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
||||
TStringStorage stringStorage, uint8_t nestingLimit)
|
||||
: _pool(&pool),
|
||||
_reader(reader),
|
||||
_stringStorage(stringStorage),
|
||||
_nestingLimit(nestingLimit) {}
|
||||
TStringStorage stringStorage)
|
||||
: _pool(&pool), _reader(reader), _stringStorage(stringStorage) {}
|
||||
|
||||
// TODO: add support for filter
|
||||
DeserializationError parse(VariantData &variant,
|
||||
AllowAllFilter = AllowAllFilter()) {
|
||||
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
||||
NestingLimit nestingLimit) {
|
||||
return parse(variant, nestingLimit);
|
||||
}
|
||||
|
||||
DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) {
|
||||
uint8_t code;
|
||||
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
||||
|
||||
@ -48,11 +49,11 @@ class MsgPackDeserializer {
|
||||
}
|
||||
|
||||
if ((code & 0xf0) == 0x90) {
|
||||
return readArray(variant.toArray(), code & 0x0F);
|
||||
return readArray(variant.toArray(), code & 0x0F, nestingLimit);
|
||||
}
|
||||
|
||||
if ((code & 0xf0) == 0x80) {
|
||||
return readObject(variant.toObject(), code & 0x0F);
|
||||
return readObject(variant.toObject(), code & 0x0F, nestingLimit);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
@ -116,16 +117,16 @@ class MsgPackDeserializer {
|
||||
return readString<uint32_t>(variant);
|
||||
|
||||
case 0xdc:
|
||||
return readArray<uint16_t>(variant.toArray());
|
||||
return readArray<uint16_t>(variant.toArray(), nestingLimit);
|
||||
|
||||
case 0xdd:
|
||||
return readArray<uint32_t>(variant.toArray());
|
||||
return readArray<uint32_t>(variant.toArray(), nestingLimit);
|
||||
|
||||
case 0xde:
|
||||
return readObject<uint16_t>(variant.toObject());
|
||||
return readObject<uint16_t>(variant.toObject(), nestingLimit);
|
||||
|
||||
case 0xdf:
|
||||
return readObject<uint32_t>(variant.toObject());
|
||||
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
||||
|
||||
default:
|
||||
return DeserializationError::NotSupported;
|
||||
@ -242,36 +243,40 @@ class MsgPackDeserializer {
|
||||
}
|
||||
|
||||
template <typename TSize>
|
||||
DeserializationError readArray(CollectionData &array) {
|
||||
DeserializationError readArray(CollectionData &array,
|
||||
NestingLimit nestingLimit) {
|
||||
TSize size;
|
||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||
return readArray(array, size);
|
||||
return readArray(array, size, nestingLimit);
|
||||
}
|
||||
|
||||
DeserializationError readArray(CollectionData &array, size_t n) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
--_nestingLimit;
|
||||
DeserializationError readArray(CollectionData &array, size_t n,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
for (; n; --n) {
|
||||
VariantData *value = array.add(_pool);
|
||||
if (!value) return DeserializationError::NoMemory;
|
||||
|
||||
DeserializationError err = parse(*value);
|
||||
DeserializationError err = parse(*value, nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
}
|
||||
++_nestingLimit;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
template <typename TSize>
|
||||
DeserializationError readObject(CollectionData &object) {
|
||||
DeserializationError readObject(CollectionData &object,
|
||||
NestingLimit nestingLimit) {
|
||||
TSize size;
|
||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
||||
return readObject(object, size);
|
||||
return readObject(object, size, nestingLimit);
|
||||
}
|
||||
|
||||
DeserializationError readObject(CollectionData &object, size_t n) {
|
||||
if (_nestingLimit == 0) return DeserializationError::TooDeep;
|
||||
--_nestingLimit;
|
||||
DeserializationError readObject(CollectionData &object, size_t n,
|
||||
NestingLimit nestingLimit) {
|
||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
||||
|
||||
for (; n; --n) {
|
||||
VariantSlot *slot = object.addSlot(_pool);
|
||||
if (!slot) return DeserializationError::NoMemory;
|
||||
@ -281,10 +286,10 @@ class MsgPackDeserializer {
|
||||
if (err) return err;
|
||||
slot->setOwnedKey(make_not_null(key));
|
||||
|
||||
err = parse(*slot->data());
|
||||
err = parse(*slot->data(), nestingLimit.decrement());
|
||||
if (err) return err;
|
||||
}
|
||||
++_nestingLimit;
|
||||
|
||||
return DeserializationError::Ok;
|
||||
}
|
||||
|
||||
@ -312,7 +317,6 @@ class MsgPackDeserializer {
|
||||
MemoryPool *_pool;
|
||||
TReader _reader;
|
||||
TStringStorage _stringStorage;
|
||||
uint8_t _nestingLimit;
|
||||
};
|
||||
|
||||
template <typename TInput>
|
||||
|
Reference in New Issue
Block a user