Remove member JsonDeserializer::_error

This reduces the code size by 72 bytes on AVR.
This commit is contained in:
Benoit Blanchon
2022-07-29 10:53:23 +02:00
parent e2a29eef24
commit a6da4ad452

View File

@ -25,20 +25,21 @@ class JsonDeserializer {
: _stringStorage(stringStorage),
_foundSomething(false),
_latch(reader),
_pool(&pool),
_error(DeserializationError::Ok) {}
_pool(&pool) {}
template <typename TFilter>
DeserializationError parse(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) {
parseVariant(variant, filter, nestingLimit);
DeserializationError::Code err;
if (!_error && _latch.last() != 0 && !variant.isEnclosed()) {
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
return DeserializationError::InvalidInput;
}
return _error;
return err;
}
private:
@ -58,10 +59,13 @@ class JsonDeserializer {
}
template <typename TFilter>
bool parseVariant(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) {
if (!skipSpacesAndComments())
return false;
DeserializationError::Code parseVariant(VariantData &variant, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) {
case '[':
@ -91,9 +95,12 @@ class JsonDeserializer {
}
}
bool skipVariant(NestingLimit nestingLimit) {
if (!skipSpacesAndComments())
return false;
DeserializationError::Code skipVariant(NestingLimit nestingLimit) {
DeserializationError::Code err;
err = skipSpacesAndComments();
if (err)
return err;
switch (current()) {
case '[':
@ -112,24 +119,25 @@ class JsonDeserializer {
}
template <typename TFilter>
bool parseArray(CollectionData &array, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code parseArray(CollectionData &array, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening braket
ARDUINOJSON_ASSERT(current() == '[');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty array?
if (eat(']'))
return true;
return DeserializationError::Ok;
TFilter memberFilter = filter[0UL];
@ -138,38 +146,37 @@ class JsonDeserializer {
if (memberFilter.allow()) {
// Allocate slot in array
VariantData *value = array.addElement(_pool);
if (!value) {
_error = DeserializationError::NoMemory;
return false;
}
if (!value)
return DeserializationError::NoMemory;
// 1 - Parse value
if (!parseVariant(*value, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
if (err)
return err;
} else {
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
}
// 2 - Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// 3 - More values?
if (eat(']'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
}
}
bool skipArray(NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code skipArray(NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening braket
ARDUINOJSON_ASSERT(current() == '[');
@ -178,58 +185,59 @@ class JsonDeserializer {
// Read each value
for (;;) {
// 1 - Skip value
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
// 2 - Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// 3 - More values?
if (eat(']'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
}
}
template <typename TFilter>
bool parseObject(CollectionData &object, TFilter filter,
NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code parseObject(CollectionData &object, TFilter filter,
NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening brace
ARDUINOJSON_ASSERT(current() == '{');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty object?
if (eat('}'))
return true;
return DeserializationError::Ok;
// Read each key value pair
for (;;) {
// Parse key
if (!parseKey())
return false;
err = parseKey();
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Colon
if (!eat(':')) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!eat(':'))
return DeserializationError::InvalidInput;
String key = _stringStorage.str();
@ -244,10 +252,8 @@ class JsonDeserializer {
// Allocate slot in object
VariantSlot *slot = object.addSlot(_pool);
if (!slot) {
_error = DeserializationError::NoMemory;
return false;
}
if (!slot)
return DeserializationError::NoMemory;
slot->setKey(key);
@ -255,84 +261,87 @@ class JsonDeserializer {
}
// Parse value
if (!parseVariant(*variant, memberFilter, nestingLimit.decrement()))
return false;
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
if (err)
return err;
} else {
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
}
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// More keys/values?
if (eat('}'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
}
}
bool skipObject(NestingLimit nestingLimit) {
if (nestingLimit.reached()) {
_error = DeserializationError::TooDeep;
return false;
}
DeserializationError::Code skipObject(NestingLimit nestingLimit) {
DeserializationError::Code err;
if (nestingLimit.reached())
return DeserializationError::TooDeep;
// Skip opening brace
ARDUINOJSON_ASSERT(current() == '{');
move();
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Empty object?
if (eat('}'))
return true;
return DeserializationError::Ok;
// Read each key value pair
for (;;) {
// Skip key
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// Colon
if (!eat(':')) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!eat(':'))
return DeserializationError::InvalidInput;
// Skip value
if (!skipVariant(nestingLimit.decrement()))
return false;
err = skipVariant(nestingLimit.decrement());
if (err)
return err;
// Skip spaces
if (!skipSpacesAndComments())
return false;
err = skipSpacesAndComments();
if (err)
return err;
// More keys/values?
if (eat('}'))
return true;
if (!eat(',')) {
_error = DeserializationError::InvalidInput;
return false;
}
return DeserializationError::Ok;
if (!eat(','))
return DeserializationError::InvalidInput;
}
}
bool parseKey() {
DeserializationError::Code parseKey() {
_stringStorage.startString();
if (isQuote(current())) {
return parseQuotedString();
@ -341,17 +350,24 @@ class JsonDeserializer {
}
}
bool parseStringValue(VariantData &variant) {
DeserializationError::Code parseStringValue(VariantData &variant) {
DeserializationError::Code err;
_stringStorage.startString();
if (!parseQuotedString())
return false;
err = parseQuotedString();
if (err)
return err;
variant.setString(_stringStorage.save());
return true;
return DeserializationError::Ok;
}
bool parseQuotedString() {
DeserializationError::Code parseQuotedString() {
#if ARDUINOJSON_DECODE_UNICODE
Utf16::Codepoint codepoint;
DeserializationError::Code err;
#endif
const char stopChar = current();
@ -362,25 +378,22 @@ class JsonDeserializer {
if (c == stopChar)
break;
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == 'u') {
#if ARDUINOJSON_DECODE_UNICODE
move();
uint16_t codeunit;
if (!parseHex4(codeunit))
return false;
err = parseHex4(codeunit);
if (err)
return err;
if (codepoint.append(codeunit))
Utf8::encodeCodepoint(codepoint.value(), _stringStorage);
#else
@ -391,25 +404,21 @@ class JsonDeserializer {
// replace char
c = EscapeSequence::unescapeChar(c);
if (c == '\0') {
_error = DeserializationError::InvalidInput;
return false;
}
if (c == '\0')
return DeserializationError::InvalidInput;
move();
}
_stringStorage.append(c);
}
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
}
if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return true;
return DeserializationError::Ok;
}
bool parseNonQuotedString() {
DeserializationError::Code parseNonQuotedString() {
char c = current();
ARDUINOJSON_ASSERT(c);
@ -420,19 +429,16 @@ class JsonDeserializer {
c = current();
} while (canBeInNonQuotedString(c));
} else {
_error = DeserializationError::InvalidInput;
return false;
return DeserializationError::InvalidInput;
}
if (!_stringStorage.isValid()) {
_error = DeserializationError::NoMemory;
return false;
}
if (!_stringStorage.isValid())
return DeserializationError::NoMemory;
return true;
return DeserializationError::Ok;
}
bool skipString() {
DeserializationError::Code skipString() {
const char stopChar = current();
move();
@ -441,20 +447,18 @@ class JsonDeserializer {
move();
if (c == stopChar)
break;
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\\') {
if (current() != '\0')
move();
}
}
return true;
return DeserializationError::Ok;
}
bool parseNumericValue(VariantData &result) {
DeserializationError::Code parseNumericValue(VariantData &result) {
uint8_t n = 0;
char c = current();
@ -468,63 +472,51 @@ class JsonDeserializer {
c = _buffer[0];
if (c == 't') { // true
result.setBoolean(true);
if (n != 4) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
if (n != 4)
return DeserializationError::IncompleteInput;
return DeserializationError::Ok;
}
if (c == 'f') { // false
result.setBoolean(false);
if (n != 5) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
if (n != 5)
return DeserializationError::IncompleteInput;
return DeserializationError::Ok;
}
if (c == 'n') { // null
// the variant is already null
if (n != 4) {
_error = DeserializationError::IncompleteInput;
return false;
}
return true;
if (n != 4)
return DeserializationError::IncompleteInput;
return DeserializationError::Ok;
}
if (!parseNumber(_buffer, result)) {
_error = DeserializationError::InvalidInput;
return false;
}
if (!parseNumber(_buffer, result))
return DeserializationError::InvalidInput;
return true;
return DeserializationError::Ok;
}
bool skipNumericValue() {
DeserializationError::Code skipNumericValue() {
char c = current();
while (canBeInNonQuotedString(c)) {
move();
c = current();
}
return true;
return DeserializationError::Ok;
}
bool parseHex4(uint16_t &result) {
DeserializationError::Code parseHex4(uint16_t &result) {
result = 0;
for (uint8_t i = 0; i < 4; ++i) {
char digit = current();
if (!digit) {
_error = DeserializationError::IncompleteInput;
return false;
}
if (!digit)
return DeserializationError::IncompleteInput;
uint8_t value = decodeHex(digit);
if (value > 0x0F) {
_error = DeserializationError::InvalidInput;
return false;
}
if (value > 0x0F)
return DeserializationError::InvalidInput;
result = uint16_t((result << 4) | value);
move();
}
return true;
return DeserializationError::Ok;
}
static inline bool isBetween(char c, char min, char max) {
@ -547,14 +539,13 @@ class JsonDeserializer {
return uint8_t(c - 'A' + 10);
}
bool skipSpacesAndComments() {
DeserializationError::Code skipSpacesAndComments() {
for (;;) {
switch (current()) {
// end of string
case '\0':
_error = _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
return false;
return _foundSomething ? DeserializationError::IncompleteInput
: DeserializationError::EmptyInput;
// spaces
case ' ':
@ -575,10 +566,8 @@ class JsonDeserializer {
bool wasStar = false;
for (;;) {
char c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '/' && wasStar) {
move();
break;
@ -595,10 +584,8 @@ class JsonDeserializer {
for (;;) {
move();
char c = current();
if (c == '\0') {
_error = DeserializationError::IncompleteInput;
return false;
}
if (c == '\0')
return DeserializationError::IncompleteInput;
if (c == '\n')
break;
}
@ -606,15 +593,14 @@ class JsonDeserializer {
// not a comment, just a '/'
default:
_error = DeserializationError::InvalidInput;
return false;
return DeserializationError::InvalidInput;
}
break;
#endif
default:
_foundSomething = true;
return true;
return DeserializationError::Ok;
}
}
}
@ -626,7 +612,6 @@ class JsonDeserializer {
char _buffer[64]; // using a member instead of a local variable because it
// ended in the recursive path after compiler inlined the
// code
DeserializationError _error;
};
//