forked from bblanchon/ArduinoJson
Reduced stack usage when compiled with -Og (issue #1210)
This saves 128 bytes on ESP8266
This commit is contained in:
@ -18,28 +18,34 @@ class MsgPackDeserializer {
|
|||||||
public:
|
public:
|
||||||
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
MsgPackDeserializer(MemoryPool &pool, TReader reader,
|
||||||
TStringStorage stringStorage)
|
TStringStorage stringStorage)
|
||||||
: _pool(&pool), _reader(reader), _stringStorage(stringStorage) {}
|
: _pool(&pool),
|
||||||
|
_reader(reader),
|
||||||
|
_stringStorage(stringStorage),
|
||||||
|
_error(DeserializationError::Ok) {}
|
||||||
|
|
||||||
// TODO: add support for filter
|
// TODO: add support for filter
|
||||||
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
DeserializationError parse(VariantData &variant, AllowAllFilter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
return parse(variant, nestingLimit);
|
parseVariant(variant, nestingLimit);
|
||||||
|
return _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) {
|
private:
|
||||||
|
bool parseVariant(VariantData &variant, NestingLimit nestingLimit) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code))
|
if (!readByte(code)) {
|
||||||
return DeserializationError::IncompleteInput;
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((code & 0x80) == 0) {
|
if ((code & 0x80) == 0) {
|
||||||
variant.setUnsignedInteger(code);
|
variant.setUnsignedInteger(code);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xe0) {
|
if ((code & 0xe0) == 0xe0) {
|
||||||
// TODO: add setNegativeInteger()
|
|
||||||
variant.setSignedInteger(static_cast<int8_t>(code));
|
variant.setSignedInteger(static_cast<int8_t>(code));
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0) {
|
if ((code & 0xe0) == 0xa0) {
|
||||||
@ -57,15 +63,15 @@ class MsgPackDeserializer {
|
|||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xc0:
|
case 0xc0:
|
||||||
// already null
|
// already null
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xc2:
|
case 0xc2:
|
||||||
variant.setBoolean(false);
|
variant.setBoolean(false);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xc3:
|
case 0xc3:
|
||||||
variant.setBoolean(true);
|
variant.setBoolean(true);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
|
|
||||||
case 0xcc:
|
case 0xcc:
|
||||||
return readInteger<uint8_t>(variant);
|
return readInteger<uint8_t>(variant);
|
||||||
@ -76,11 +82,9 @@ class MsgPackDeserializer {
|
|||||||
case 0xce:
|
case 0xce:
|
||||||
return readInteger<uint32_t>(variant);
|
return readInteger<uint32_t>(variant);
|
||||||
|
|
||||||
case 0xcf:
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
case 0xcf:
|
||||||
return readInteger<uint64_t>(variant);
|
return readInteger<uint64_t>(variant);
|
||||||
#else
|
|
||||||
return DeserializationError::NotSupported;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 0xd0:
|
case 0xd0:
|
||||||
@ -92,11 +96,9 @@ class MsgPackDeserializer {
|
|||||||
case 0xd2:
|
case 0xd2:
|
||||||
return readInteger<int32_t>(variant);
|
return readInteger<int32_t>(variant);
|
||||||
|
|
||||||
case 0xd3:
|
|
||||||
#if ARDUINOJSON_USE_LONG_LONG
|
#if ARDUINOJSON_USE_LONG_LONG
|
||||||
|
case 0xd3:
|
||||||
return readInteger<int64_t>(variant);
|
return readInteger<int64_t>(variant);
|
||||||
#else
|
|
||||||
return DeserializationError::NotSupported;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 0xca:
|
case 0xca:
|
||||||
@ -127,7 +129,8 @@ class MsgPackDeserializer {
|
|||||||
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
return readObject<uint32_t>(variant.toObject(), nestingLimit);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::NotSupported;
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,14 +140,19 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
bool readByte(uint8_t &value) {
|
bool readByte(uint8_t &value) {
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
if (c < 0)
|
if (c < 0) {
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
value = static_cast<uint8_t>(c);
|
value = static_cast<uint8_t>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readBytes(uint8_t *p, size_t n) {
|
bool readBytes(uint8_t *p, size_t n) {
|
||||||
return _reader.readBytes(reinterpret_cast<char *>(p), n) == n;
|
if (_reader.readBytes(reinterpret_cast<char *>(p), n) == n)
|
||||||
|
return true;
|
||||||
|
_error = DeserializationError::IncompleteInput;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -152,14 +160,6 @@ class MsgPackDeserializer {
|
|||||||
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T readInteger() {
|
|
||||||
T value;
|
|
||||||
readBytes(value);
|
|
||||||
fixEndianess(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readInteger(T &value) {
|
bool readInteger(T &value) {
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
@ -169,155 +169,159 @@ class MsgPackDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readInteger(VariantData &variant) {
|
bool readInteger(VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readInteger(value))
|
if (!readInteger(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
variant.setInteger(value);
|
variant.setInteger(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
typename enable_if<sizeof(T) == 4, bool>::type readFloat(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 8, bool>::type readDouble(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value))
|
if (!readBytes(value))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 4, bool>::type readDouble(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
uint8_t i[8]; // input is 8 bytes
|
uint8_t i[8]; // input is 8 bytes
|
||||||
T value; // output is 4 bytes
|
T value; // output is 4 bytes
|
||||||
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
|
||||||
if (!readBytes(i, 8))
|
if (!readBytes(i, 8))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
doubleToFloat(i, o);
|
doubleToFloat(i, o);
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(VariantData &variant) {
|
bool readString(VariantData &variant) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readString(variant, size);
|
return readString(variant, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(const char *&str) {
|
bool readString(const char *&str) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readString(str, size);
|
return readString(str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(VariantData &variant, size_t n) {
|
bool readString(VariantData &variant, size_t n) {
|
||||||
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
const char *s = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
||||||
DeserializationError err = readString(s, n);
|
if (!readString(s, n))
|
||||||
if (!err)
|
return false;
|
||||||
variant.setString(make_not_null(s),
|
variant.setString(make_not_null(s),
|
||||||
typename TStringStorage::storage_policy());
|
typename TStringStorage::storage_policy());
|
||||||
return err;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(const char *&result, size_t n) {
|
bool readString(const char *&result, size_t n) {
|
||||||
_stringStorage.startString(_pool);
|
_stringStorage.startString(_pool);
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
if (!readBytes(c))
|
if (!readBytes(c))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
_stringStorage.append(static_cast<char>(c));
|
_stringStorage.append(static_cast<char>(c));
|
||||||
}
|
}
|
||||||
_stringStorage.append('\0');
|
_stringStorage.append('\0');
|
||||||
if (!_stringStorage.isValid())
|
if (!_stringStorage.isValid()) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
result = _stringStorage.save(_pool);
|
result = _stringStorage.save(_pool);
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readArray(CollectionData &array,
|
bool readArray(CollectionData &array, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readArray(array, size, nestingLimit);
|
return readArray(array, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readArray(CollectionData &array, size_t n,
|
bool readArray(CollectionData &array, size_t n, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
if (nestingLimit.reached()) {
|
||||||
if (nestingLimit.reached())
|
_error = DeserializationError::TooDeep;
|
||||||
return DeserializationError::TooDeep;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantData *value = array.addElement(_pool);
|
VariantData *value = array.addElement(_pool);
|
||||||
if (!value)
|
if (!value) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DeserializationError err = parse(*value, nestingLimit.decrement());
|
if (!parseVariant(*value, nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSize>
|
template <typename TSize>
|
||||||
DeserializationError readObject(CollectionData &object,
|
bool readObject(CollectionData &object, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size))
|
if (!readInteger(size))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
return readObject(object, size, nestingLimit);
|
return readObject(object, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readObject(CollectionData &object, size_t n,
|
bool readObject(CollectionData &object, size_t n, NestingLimit nestingLimit) {
|
||||||
NestingLimit nestingLimit) {
|
if (nestingLimit.reached()) {
|
||||||
if (nestingLimit.reached())
|
_error = DeserializationError::TooDeep;
|
||||||
return DeserializationError::TooDeep;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
if (!slot)
|
if (!slot) {
|
||||||
return DeserializationError::NoMemory;
|
_error = DeserializationError::NoMemory;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
const char *key = 0; // <- mute "maybe-uninitialized" (+4 bytes on AVR)
|
||||||
DeserializationError err = parseKey(key);
|
if (!parseKey(key))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
slot->setKey(key, typename TStringStorage::storage_policy());
|
slot->setKey(key, typename TStringStorage::storage_policy());
|
||||||
|
|
||||||
err = parse(*slot->data(), nestingLimit.decrement());
|
if (!parseVariant(*slot->data(), nestingLimit.decrement()))
|
||||||
if (err)
|
return false;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError parseKey(const char *&key) {
|
bool parseKey(const char *&key) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code))
|
if (!readByte(code))
|
||||||
return DeserializationError::IncompleteInput;
|
return false;
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0)
|
if ((code & 0xe0) == 0xa0)
|
||||||
return readString(key, code & 0x1f);
|
return readString(key, code & 0x1f);
|
||||||
@ -333,13 +337,15 @@ class MsgPackDeserializer {
|
|||||||
return readString<uint32_t>(key);
|
return readString<uint32_t>(key);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return DeserializationError::NotSupported;
|
_error = DeserializationError::NotSupported;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryPool *_pool;
|
MemoryPool *_pool;
|
||||||
TReader _reader;
|
TReader _reader;
|
||||||
TStringStorage _stringStorage;
|
TStringStorage _stringStorage;
|
||||||
|
DeserializationError _error;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TInput>
|
template <typename TInput>
|
||||||
|
Reference in New Issue
Block a user