forked from bblanchon/ArduinoJson
Added a line-break after each "if" to get more accurate coverage report
This commit is contained in:
@ -3,3 +3,6 @@
|
|||||||
BasedOnStyle: Google
|
BasedOnStyle: Google
|
||||||
Standard: Cpp03
|
Standard: Cpp03
|
||||||
AllowShortFunctionsOnASingleLine: Empty
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
|
||||||
|
# Always break after if to get accurate coverage
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
@ -21,9 +21,10 @@ inline void arrayAccept(const CollectionData *arr, Visitor &visitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
inline bool arrayEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
||||||
if (lhs == rhs) return true;
|
if (lhs == rhs)
|
||||||
if (!lhs || !rhs) return false;
|
return true;
|
||||||
|
if (!lhs || !rhs)
|
||||||
|
return false;
|
||||||
return lhs->equalsArray(*rhs);
|
return lhs->equalsArray(*rhs);
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -66,7 +66,8 @@ class ArrayConstRef : public ArrayRefBase<const CollectionData>,
|
|||||||
typedef ArrayConstRefIterator iterator;
|
typedef ArrayConstRefIterator iterator;
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data)
|
||||||
|
return iterator();
|
||||||
return iterator(_data->head());
|
return iterator(_data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,8 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data)
|
||||||
|
return iterator();
|
||||||
return iterator(_pool, _data->head());
|
return iterator(_pool, _data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +128,8 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
|
|||||||
|
|
||||||
// Copy a ArrayRef
|
// Copy a ArrayRef
|
||||||
FORCE_INLINE bool set(ArrayConstRef src) const {
|
FORCE_INLINE bool set(ArrayConstRef src) const {
|
||||||
if (!_data || !src._data) return false;
|
if (!_data || !src._data)
|
||||||
|
return false;
|
||||||
return _data->copyFrom(*src._data, _pool);
|
return _data->copyFrom(*src._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,13 +144,15 @@ class ArrayRef : public ArrayRefBase<CollectionData>,
|
|||||||
|
|
||||||
// Removes element at specified position.
|
// Removes element at specified position.
|
||||||
FORCE_INLINE void remove(iterator it) const {
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
if (!_data) return;
|
if (!_data)
|
||||||
|
return;
|
||||||
_data->remove(it.internal());
|
_data->remove(it.internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes element at specified index.
|
// Removes element at specified index.
|
||||||
FORCE_INLINE void remove(size_t index) const {
|
FORCE_INLINE void remove(size_t index) const {
|
||||||
if (!_data) return;
|
if (!_data)
|
||||||
|
return;
|
||||||
_data->remove(index);
|
_data->remove(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
inline VariantSlot* CollectionData::addSlot(MemoryPool* pool) {
|
||||||
VariantSlot* slot = pool->allocVariant();
|
VariantSlot* slot = pool->allocVariant();
|
||||||
if (!slot) return 0;
|
if (!slot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (_tail) {
|
if (_tail) {
|
||||||
_tail->setNextNotNull(slot);
|
_tail->setNextNotNull(slot);
|
||||||
@ -32,7 +33,8 @@ inline VariantData* CollectionData::add(MemoryPool* pool) {
|
|||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline VariantData* CollectionData::add(TAdaptedString key, MemoryPool* pool) {
|
inline VariantData* CollectionData::add(TAdaptedString key, MemoryPool* pool) {
|
||||||
VariantSlot* slot = addSlot(pool);
|
VariantSlot* slot = addSlot(pool);
|
||||||
if (!slotSetKey(slot, key, pool)) return 0;
|
if (!slotSetKey(slot, key, pool))
|
||||||
|
return 0;
|
||||||
return slot->data();
|
return slot->data();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +61,10 @@ inline bool CollectionData::copyFrom(const CollectionData& src,
|
|||||||
} else {
|
} else {
|
||||||
var = add(pool);
|
var = add(pool);
|
||||||
}
|
}
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
if (!var->copyFrom(*s->data(), pool)) return false;
|
return false;
|
||||||
|
if (!var->copyFrom(*s->data(), pool))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -70,7 +74,8 @@ inline bool CollectionData::equalsObject(const CollectionData& other) const {
|
|||||||
for (VariantSlot* slot = _head; slot; slot = slot->next()) {
|
for (VariantSlot* slot = _head; slot; slot = slot->next()) {
|
||||||
VariantData* v1 = slot->data();
|
VariantData* v1 = slot->data();
|
||||||
VariantData* v2 = other.get(adaptString(slot->key()));
|
VariantData* v2 = other.get(adaptString(slot->key()));
|
||||||
if (!variantEquals(v1, v2)) return false;
|
if (!variantEquals(v1, v2))
|
||||||
|
return false;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return count == other.size();
|
return count == other.size();
|
||||||
@ -80,9 +85,12 @@ inline bool CollectionData::equalsArray(const CollectionData& other) const {
|
|||||||
VariantSlot* s1 = _head;
|
VariantSlot* s1 = _head;
|
||||||
VariantSlot* s2 = other._head;
|
VariantSlot* s2 = other._head;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (s1 == s2) return true;
|
if (s1 == s2)
|
||||||
if (!s1 || !s2) return false;
|
return true;
|
||||||
if (!variantEquals(s1->data(), s2->data())) return false;
|
if (!s1 || !s2)
|
||||||
|
return false;
|
||||||
|
if (!variantEquals(s1->data(), s2->data()))
|
||||||
|
return false;
|
||||||
s1 = s1->next();
|
s1 = s1->next();
|
||||||
s2 = s2->next();
|
s2 = s2->next();
|
||||||
}
|
}
|
||||||
@ -92,7 +100,8 @@ template <typename TAdaptedString>
|
|||||||
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
|
inline VariantSlot* CollectionData::getSlot(TAdaptedString key) const {
|
||||||
VariantSlot* slot = _head;
|
VariantSlot* slot = _head;
|
||||||
while (slot) {
|
while (slot) {
|
||||||
if (key.equals(slot->key())) break;
|
if (key.equals(slot->key()))
|
||||||
|
break;
|
||||||
slot = slot->next();
|
slot = slot->next();
|
||||||
}
|
}
|
||||||
return slot;
|
return slot;
|
||||||
@ -106,7 +115,8 @@ inline VariantSlot* CollectionData::getPreviousSlot(VariantSlot* target) const {
|
|||||||
VariantSlot* current = _head;
|
VariantSlot* current = _head;
|
||||||
while (current) {
|
while (current) {
|
||||||
VariantSlot* next = current->next();
|
VariantSlot* next = current->next();
|
||||||
if (next == target) return current;
|
if (next == target)
|
||||||
|
return current;
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -124,14 +134,16 @@ inline VariantData* CollectionData::get(size_t index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void CollectionData::remove(VariantSlot* slot) {
|
inline void CollectionData::remove(VariantSlot* slot) {
|
||||||
if (!slot) return;
|
if (!slot)
|
||||||
|
return;
|
||||||
VariantSlot* prev = getPreviousSlot(slot);
|
VariantSlot* prev = getPreviousSlot(slot);
|
||||||
VariantSlot* next = slot->next();
|
VariantSlot* next = slot->next();
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->setNext(next);
|
prev->setNext(next);
|
||||||
else
|
else
|
||||||
_head = next;
|
_head = next;
|
||||||
if (!next) _tail = prev;
|
if (!next)
|
||||||
|
_tail = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void CollectionData::remove(size_t index) {
|
inline void CollectionData::remove(size_t index) {
|
||||||
@ -142,7 +154,8 @@ inline size_t CollectionData::memoryUsage() const {
|
|||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
for (VariantSlot* s = _head; s; s = s->next()) {
|
for (VariantSlot* s = _head; s; s = s->next()) {
|
||||||
total += sizeof(VariantSlot) + s->data()->memoryUsage();
|
total += sizeof(VariantSlot) + s->data()->memoryUsage();
|
||||||
if (s->ownsKey()) total += strlen(s->key()) + 1;
|
if (s->ownsKey())
|
||||||
|
total += strlen(s->key()) + 1;
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
@ -151,7 +164,8 @@ inline size_t CollectionData::nesting() const {
|
|||||||
size_t maxChildNesting = 0;
|
size_t maxChildNesting = 0;
|
||||||
for (VariantSlot* s = _head; s; s = s->next()) {
|
for (VariantSlot* s = _head; s; s = s->next()) {
|
||||||
size_t childNesting = s->data()->nesting();
|
size_t childNesting = s->data()->nesting();
|
||||||
if (childNesting > maxChildNesting) maxChildNesting = childNesting;
|
if (childNesting > maxChildNesting)
|
||||||
|
maxChildNesting = childNesting;
|
||||||
}
|
}
|
||||||
return maxChildNesting + 1;
|
return maxChildNesting + 1;
|
||||||
}
|
}
|
||||||
@ -162,7 +176,8 @@ inline size_t CollectionData::size() const {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void movePointer(T*& p, ptrdiff_t offset) {
|
inline void movePointer(T*& p, ptrdiff_t offset) {
|
||||||
if (!p) return;
|
if (!p)
|
||||||
|
return;
|
||||||
p = reinterpret_cast<T*>(
|
p = reinterpret_cast<T*>(
|
||||||
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
reinterpret_cast<void*>(reinterpret_cast<char*>(p) + offset));
|
||||||
ARDUINOJSON_ASSERT(isAligned(p));
|
ARDUINOJSON_ASSERT(isAligned(p));
|
||||||
|
@ -43,7 +43,8 @@ struct BoundedReader<const __FlashStringHelper*, void> {
|
|||||||
|
|
||||||
size_t readBytes(char* buffer, size_t length) {
|
size_t readBytes(char* buffer, size_t length) {
|
||||||
size_t available = static_cast<size_t>(_end - _ptr);
|
size_t available = static_cast<size_t>(_end - _ptr);
|
||||||
if (available < length) length = available;
|
if (available < length)
|
||||||
|
length = available;
|
||||||
memcpy_P(buffer, _ptr, length);
|
memcpy_P(buffer, _ptr, length);
|
||||||
_ptr += length;
|
_ptr += length;
|
||||||
return length;
|
return length;
|
||||||
|
@ -77,7 +77,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
|
|||||||
|
|
||||||
void shrinkToFit() {
|
void shrinkToFit() {
|
||||||
ptrdiff_t bytes_reclaimed = _pool.squash();
|
ptrdiff_t bytes_reclaimed = _pool.squash();
|
||||||
if (bytes_reclaimed == 0) return;
|
if (bytes_reclaimed == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
void* old_ptr = _pool.buffer();
|
void* old_ptr = _pool.buffer();
|
||||||
void* new_ptr = this->reallocate(old_ptr, _pool.capacity());
|
void* new_ptr = this->reallocate(old_ptr, _pool.capacity());
|
||||||
@ -96,7 +97,8 @@ class BasicJsonDocument : AllocatorOwner<TAllocator>, public JsonDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reallocPoolIfTooSmall(size_t requiredSize) {
|
void reallocPoolIfTooSmall(size_t requiredSize) {
|
||||||
if (requiredSize <= capacity()) return;
|
if (requiredSize <= capacity())
|
||||||
|
return;
|
||||||
freePool();
|
freePool();
|
||||||
replacePool(allocPool(addPadding(requiredSize)));
|
replacePool(allocPool(addPadding(requiredSize)));
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@ class EscapeSequence {
|
|||||||
static char unescapeChar(char c) {
|
static char unescapeChar(char c) {
|
||||||
const char *p = escapeTable(true);
|
const char *p = escapeTable(true);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (p[0] == '\0') return c;
|
if (p[0] == '\0')
|
||||||
if (p[0] == c) return p[1];
|
return c;
|
||||||
|
if (p[0] == c)
|
||||||
|
return p[1];
|
||||||
p += 2;
|
p += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool eat(char charToSkip) {
|
bool eat(char charToSkip) {
|
||||||
if (current() != charToSkip) return false;
|
if (current() != charToSkip)
|
||||||
|
return false;
|
||||||
move();
|
move();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -61,7 +62,8 @@ class JsonDeserializer {
|
|||||||
DeserializationError parseVariant(VariantData &variant, TFilter filter,
|
DeserializationError parseVariant(VariantData &variant, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
@ -93,7 +95,8 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
DeserializationError skipVariant(NestingLimit nestingLimit) {
|
DeserializationError skipVariant(NestingLimit nestingLimit) {
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
switch (current()) {
|
switch (current()) {
|
||||||
case '[':
|
case '[':
|
||||||
@ -114,7 +117,8 @@ class JsonDeserializer {
|
|||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parseArray(CollectionData &array, TFilter filter,
|
DeserializationError parseArray(CollectionData &array, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
// Skip opening braket
|
// Skip opening braket
|
||||||
ARDUINOJSON_ASSERT(current() == '[');
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
@ -122,10 +126,12 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Empty array?
|
// Empty array?
|
||||||
if (eat(']')) return DeserializationError::Ok;
|
if (eat(']'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
TFilter memberFilter = filter[0UL];
|
TFilter memberFilter = filter[0UL];
|
||||||
|
|
||||||
@ -134,28 +140,35 @@ class JsonDeserializer {
|
|||||||
if (memberFilter.allow()) {
|
if (memberFilter.allow()) {
|
||||||
// Allocate slot in array
|
// Allocate slot in array
|
||||||
VariantData *value = array.add(_pool);
|
VariantData *value = array.add(_pool);
|
||||||
if (!value) return DeserializationError::NoMemory;
|
if (!value)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
// 1 - Parse value
|
// 1 - Parse value
|
||||||
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
err = parseVariant(*value, memberFilter, nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
} else {
|
} else {
|
||||||
err = skipVariant(nestingLimit.decrement());
|
err = skipVariant(nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 - Skip spaces
|
// 2 - Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// 3 - More values?
|
// 3 - More values?
|
||||||
if (eat(']')) return DeserializationError::Ok;
|
if (eat(']'))
|
||||||
if (!eat(',')) return DeserializationError::InvalidInput;
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipArray(NestingLimit nestingLimit) {
|
DeserializationError skipArray(NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
// Skip opening braket
|
// Skip opening braket
|
||||||
ARDUINOJSON_ASSERT(current() == '[');
|
ARDUINOJSON_ASSERT(current() == '[');
|
||||||
@ -165,22 +178,27 @@ class JsonDeserializer {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
// 1 - Skip value
|
// 1 - Skip value
|
||||||
DeserializationError err = skipVariant(nestingLimit.decrement());
|
DeserializationError err = skipVariant(nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// 2 - Skip spaces
|
// 2 - Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// 3 - More values?
|
// 3 - More values?
|
||||||
if (eat(']')) return DeserializationError::Ok;
|
if (eat(']'))
|
||||||
if (!eat(',')) return DeserializationError::InvalidInput;
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TFilter>
|
template <typename TFilter>
|
||||||
DeserializationError parseObject(CollectionData &object, TFilter filter,
|
DeserializationError parseObject(CollectionData &object, TFilter filter,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
// Skip opening brace
|
// Skip opening brace
|
||||||
ARDUINOJSON_ASSERT(current() == '{');
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
@ -188,22 +206,27 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Empty object?
|
// Empty object?
|
||||||
if (eat('}')) return DeserializationError::Ok;
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
// Read each key value pair
|
// Read each key value pair
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Parse key
|
// Parse key
|
||||||
const char *key;
|
const char *key;
|
||||||
err = parseKey(key);
|
err = parseKey(key);
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err; // Colon
|
if (err)
|
||||||
if (!eat(':')) return DeserializationError::InvalidInput;
|
return err; // Colon
|
||||||
|
if (!eat(':'))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
TFilter memberFilter = filter[key];
|
TFilter memberFilter = filter[key];
|
||||||
|
|
||||||
@ -212,7 +235,8 @@ class JsonDeserializer {
|
|||||||
if (!variant) {
|
if (!variant) {
|
||||||
// Allocate slot in object
|
// Allocate slot in object
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
if (!slot) return DeserializationError::NoMemory;
|
if (!slot)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
slot->setOwnedKey(make_not_null(key));
|
slot->setOwnedKey(make_not_null(key));
|
||||||
|
|
||||||
@ -221,29 +245,36 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// Parse value
|
// Parse value
|
||||||
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
err = parseVariant(*variant, memberFilter, nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
} else {
|
} else {
|
||||||
_stringStorage.reclaim(key);
|
_stringStorage.reclaim(key);
|
||||||
err = skipVariant(nestingLimit.decrement());
|
err = skipVariant(nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// More keys/values?
|
// More keys/values?
|
||||||
if (eat('}')) return DeserializationError::Ok;
|
if (eat('}'))
|
||||||
if (!eat(',')) return DeserializationError::InvalidInput;
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError skipObject(NestingLimit nestingLimit) {
|
DeserializationError skipObject(NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
// Skip opening brace
|
// Skip opening brace
|
||||||
ARDUINOJSON_ASSERT(current() == '{');
|
ARDUINOJSON_ASSERT(current() == '{');
|
||||||
@ -251,33 +282,42 @@ class JsonDeserializer {
|
|||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
DeserializationError err = skipSpacesAndComments();
|
DeserializationError err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Empty object?
|
// Empty object?
|
||||||
if (eat('}')) return DeserializationError::Ok;
|
if (eat('}'))
|
||||||
|
return DeserializationError::Ok;
|
||||||
|
|
||||||
// Read each key value pair
|
// Read each key value pair
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Skip key
|
// Skip key
|
||||||
err = skipVariant(nestingLimit.decrement());
|
err = skipVariant(nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err; // Colon
|
if (err)
|
||||||
if (!eat(':')) return DeserializationError::InvalidInput;
|
return err; // Colon
|
||||||
|
if (!eat(':'))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
|
|
||||||
// Skip value
|
// Skip value
|
||||||
err = skipVariant(nestingLimit.decrement());
|
err = skipVariant(nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// Skip spaces
|
// Skip spaces
|
||||||
err = skipSpacesAndComments();
|
err = skipSpacesAndComments();
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
// More keys/values?
|
// More keys/values?
|
||||||
if (eat('}')) return DeserializationError::Ok;
|
if (eat('}'))
|
||||||
if (!eat(',')) return DeserializationError::InvalidInput;
|
return DeserializationError::Ok;
|
||||||
|
if (!eat(','))
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +332,8 @@ class JsonDeserializer {
|
|||||||
DeserializationError parseStringValue(VariantData &variant) {
|
DeserializationError parseStringValue(VariantData &variant) {
|
||||||
const char *value;
|
const char *value;
|
||||||
DeserializationError err = parseQuotedString(value);
|
DeserializationError err = parseQuotedString(value);
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
variant.setOwnedString(make_not_null(value));
|
variant.setOwnedString(make_not_null(value));
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -308,19 +349,23 @@ class JsonDeserializer {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
char c = current();
|
char c = current();
|
||||||
move();
|
move();
|
||||||
if (c == stopChar) break;
|
if (c == stopChar)
|
||||||
|
break;
|
||||||
|
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
c = current();
|
c = current();
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
if (c == 'u') {
|
if (c == 'u') {
|
||||||
#if ARDUINOJSON_DECODE_UNICODE
|
#if ARDUINOJSON_DECODE_UNICODE
|
||||||
move();
|
move();
|
||||||
uint16_t codeunit;
|
uint16_t codeunit;
|
||||||
DeserializationError err = parseHex4(codeunit);
|
DeserializationError err = parseHex4(codeunit);
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
if (codepoint.append(codeunit))
|
if (codepoint.append(codeunit))
|
||||||
Utf8::encodeCodepoint(codepoint.value(), builder);
|
Utf8::encodeCodepoint(codepoint.value(), builder);
|
||||||
continue;
|
continue;
|
||||||
@ -330,7 +375,8 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
// replace char
|
// replace char
|
||||||
c = EscapeSequence::unescapeChar(c);
|
c = EscapeSequence::unescapeChar(c);
|
||||||
if (c == '\0') return DeserializationError::InvalidInput;
|
if (c == '\0')
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +384,8 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = builder.complete();
|
result = builder.complete();
|
||||||
if (!result) return DeserializationError::NoMemory;
|
if (!result)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +393,8 @@ class JsonDeserializer {
|
|||||||
StringBuilder builder = _stringStorage.startString();
|
StringBuilder builder = _stringStorage.startString();
|
||||||
|
|
||||||
char c = current();
|
char c = current();
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
if (canBeInNonQuotedString(c)) { // no quotes
|
if (canBeInNonQuotedString(c)) { // no quotes
|
||||||
do {
|
do {
|
||||||
@ -359,7 +407,8 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = builder.complete();
|
result = builder.complete();
|
||||||
if (!result) return DeserializationError::NoMemory;
|
if (!result)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,10 +419,13 @@ class JsonDeserializer {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
char c = current();
|
char c = current();
|
||||||
move();
|
move();
|
||||||
if (c == stopChar) break;
|
if (c == stopChar)
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
break;
|
||||||
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
if (current() != '\0') move();
|
if (current() != '\0')
|
||||||
|
move();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,9 +493,11 @@ class JsonDeserializer {
|
|||||||
result = 0;
|
result = 0;
|
||||||
for (uint8_t i = 0; i < 4; ++i) {
|
for (uint8_t i = 0; i < 4; ++i) {
|
||||||
char digit = current();
|
char digit = current();
|
||||||
if (!digit) return DeserializationError::IncompleteInput;
|
if (!digit)
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
uint8_t value = decodeHex(digit);
|
uint8_t value = decodeHex(digit);
|
||||||
if (value > 0x0F) return DeserializationError::InvalidInput;
|
if (value > 0x0F)
|
||||||
|
return DeserializationError::InvalidInput;
|
||||||
result = uint16_t((result << 4) | value);
|
result = uint16_t((result << 4) | value);
|
||||||
move();
|
move();
|
||||||
}
|
}
|
||||||
@ -464,7 +518,8 @@ class JsonDeserializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t decodeHex(char c) {
|
static inline uint8_t decodeHex(char c) {
|
||||||
if (c < 'A') return uint8_t(c - '0');
|
if (c < 'A')
|
||||||
|
return uint8_t(c - '0');
|
||||||
c = char(c & ~0x20); // uppercase
|
c = char(c & ~0x20); // uppercase
|
||||||
return uint8_t(c - 'A' + 10);
|
return uint8_t(c - 'A' + 10);
|
||||||
}
|
}
|
||||||
@ -495,7 +550,8 @@ class JsonDeserializer {
|
|||||||
bool wasStar = false;
|
bool wasStar = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c = current();
|
char c = current();
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
if (c == '\0')
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
if (c == '/' && wasStar) {
|
if (c == '/' && wasStar) {
|
||||||
move();
|
move();
|
||||||
break;
|
break;
|
||||||
@ -512,8 +568,10 @@ class JsonDeserializer {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
move();
|
move();
|
||||||
char c = current();
|
char c = current();
|
||||||
if (c == '\0') return DeserializationError::IncompleteInput;
|
if (c == '\0')
|
||||||
if (c == '\n') break;
|
return DeserializationError::IncompleteInput;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ class JsonSerializer {
|
|||||||
slot->data()->accept(*this);
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
slot = slot->next();
|
slot = slot->next();
|
||||||
if (slot == 0) break;
|
if (slot == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
write(',');
|
write(',');
|
||||||
}
|
}
|
||||||
@ -44,7 +45,8 @@ class JsonSerializer {
|
|||||||
slot->data()->accept(*this);
|
slot->data()->accept(*this);
|
||||||
|
|
||||||
slot = slot->next();
|
slot = slot->next();
|
||||||
if (slot == 0) break;
|
if (slot == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
write(',');
|
write(',');
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,8 @@ class Latch {
|
|||||||
ARDUINOJSON_ASSERT(!_ended);
|
ARDUINOJSON_ASSERT(!_ended);
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
#ifdef ARDUINOJSON_DEBUG
|
#ifdef ARDUINOJSON_DEBUG
|
||||||
if (c <= 0) _ended = true;
|
if (c <= 0)
|
||||||
|
_ended = true;
|
||||||
#endif
|
#endif
|
||||||
_current = static_cast<char>(c > 0 ? c : 0);
|
_current = static_cast<char>(c > 0 ? c : 0);
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
|
@ -20,7 +20,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
|
|
||||||
void visitArray(const CollectionData &array) {
|
void visitArray(const CollectionData &array) {
|
||||||
VariantSlot *slot = array.head();
|
VariantSlot *slot = array.head();
|
||||||
if (!slot) return base::write("[]");
|
if (!slot)
|
||||||
|
return base::write("[]");
|
||||||
|
|
||||||
base::write("[\r\n");
|
base::write("[\r\n");
|
||||||
_nesting++;
|
_nesting++;
|
||||||
@ -38,7 +39,8 @@ class PrettyJsonSerializer : public JsonSerializer<TWriter> {
|
|||||||
|
|
||||||
void visitObject(const CollectionData &object) {
|
void visitObject(const CollectionData &object) {
|
||||||
VariantSlot *slot = object.head();
|
VariantSlot *slot = object.head();
|
||||||
if (!slot) return base::write("{}");
|
if (!slot)
|
||||||
|
return base::write("{}");
|
||||||
|
|
||||||
base::write("{\r\n");
|
base::write("{\r\n");
|
||||||
_nesting++;
|
_nesting++;
|
||||||
|
@ -53,7 +53,8 @@ class TextFormatter {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void writeFloat(T value) {
|
void writeFloat(T value) {
|
||||||
if (isnan(value)) return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
if (isnan(value))
|
||||||
|
return writeRaw(ARDUINOJSON_ENABLE_NAN ? "NaN" : "null");
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_INFINITY
|
#if ARDUINOJSON_ENABLE_INFINITY
|
||||||
if (value < 0.0) {
|
if (value < 0.0) {
|
||||||
@ -61,9 +62,11 @@ class TextFormatter {
|
|||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isinf(value)) return writeRaw("Infinity");
|
if (isinf(value))
|
||||||
|
return writeRaw("Infinity");
|
||||||
#else
|
#else
|
||||||
if (isinf(value)) return writeRaw("null");
|
if (isinf(value))
|
||||||
|
return writeRaw("null");
|
||||||
|
|
||||||
if (value < 0.0) {
|
if (value < 0.0) {
|
||||||
writeRaw('-');
|
writeRaw('-');
|
||||||
@ -74,7 +77,8 @@ class TextFormatter {
|
|||||||
FloatParts<T> parts(value);
|
FloatParts<T> parts(value);
|
||||||
|
|
||||||
writePositiveInteger(parts.integral);
|
writePositiveInteger(parts.integral);
|
||||||
if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces);
|
if (parts.decimalPlaces)
|
||||||
|
writeDecimals(parts.decimal, parts.decimalPlaces);
|
||||||
|
|
||||||
if (parts.exponent < 0) {
|
if (parts.exponent < 0) {
|
||||||
writeRaw("e-");
|
writeRaw("e-");
|
||||||
|
@ -52,7 +52,8 @@ class MemoryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* allocFrozenString(size_t n) {
|
char* allocFrozenString(size_t n) {
|
||||||
if (!canAlloc(n)) return 0;
|
if (!canAlloc(n))
|
||||||
|
return 0;
|
||||||
char* s = _left;
|
char* s = _left;
|
||||||
_left += n;
|
_left += n;
|
||||||
checkInvariants();
|
checkInvariants();
|
||||||
@ -97,7 +98,8 @@ class MemoryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* allocRight(size_t bytes) {
|
void* allocRight(size_t bytes) {
|
||||||
if (!canAlloc(bytes)) return 0;
|
if (!canAlloc(bytes))
|
||||||
|
return 0;
|
||||||
_right -= bytes;
|
_right -= bytes;
|
||||||
return _right;
|
return _right;
|
||||||
}
|
}
|
||||||
@ -120,7 +122,8 @@ class MemoryPool {
|
|||||||
// This funcion is called before a realloc.
|
// This funcion is called before a realloc.
|
||||||
ptrdiff_t squash() {
|
ptrdiff_t squash() {
|
||||||
char* new_right = addPadding(_left);
|
char* new_right = addPadding(_left);
|
||||||
if (new_right >= _right) return 0;
|
if (new_right >= _right)
|
||||||
|
return 0;
|
||||||
|
|
||||||
size_t right_size = static_cast<size_t>(_end - _right);
|
size_t right_size = static_cast<size_t>(_end - _right);
|
||||||
memmove(new_right, _right, right_size);
|
memmove(new_right, _right, right_size);
|
||||||
|
@ -23,7 +23,8 @@ class StringBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void append(char c) {
|
void append(char c) {
|
||||||
if (!_slot.value) return;
|
if (!_slot.value)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_size >= _slot.size) {
|
if (_size >= _slot.size) {
|
||||||
_slot.value = 0;
|
_slot.value = 0;
|
||||||
|
@ -31,7 +31,8 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) {
|
DeserializationError parse(VariantData &variant, NestingLimit nestingLimit) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
if (!readByte(code))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
if ((code & 0x80) == 0) {
|
if ((code & 0x80) == 0) {
|
||||||
variant.setUnsignedInteger(code);
|
variant.setUnsignedInteger(code);
|
||||||
@ -139,7 +140,8 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
bool readByte(uint8_t &value) {
|
bool readByte(uint8_t &value) {
|
||||||
int c = _reader.read();
|
int c = _reader.read();
|
||||||
if (c < 0) return false;
|
if (c < 0)
|
||||||
|
return false;
|
||||||
value = static_cast<uint8_t>(c);
|
value = static_cast<uint8_t>(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -163,7 +165,8 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool readInteger(T &value) {
|
bool readInteger(T &value) {
|
||||||
if (!readBytes(value)) return false;
|
if (!readBytes(value))
|
||||||
|
return false;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -171,7 +174,8 @@ class MsgPackDeserializer {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readInteger(VariantData &variant) {
|
DeserializationError readInteger(VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readInteger(value)) return DeserializationError::IncompleteInput;
|
if (!readInteger(value))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
variant.setInteger(value);
|
variant.setInteger(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
@ -180,7 +184,8 @@ class MsgPackDeserializer {
|
|||||||
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
typename enable_if<sizeof(T) == 4, DeserializationError>::type readFloat(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
if (!readBytes(value))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -190,7 +195,8 @@ class MsgPackDeserializer {
|
|||||||
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
typename enable_if<sizeof(T) == 8, DeserializationError>::type readDouble(
|
||||||
VariantData &variant) {
|
VariantData &variant) {
|
||||||
T value;
|
T value;
|
||||||
if (!readBytes(value)) return DeserializationError::IncompleteInput;
|
if (!readBytes(value))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -202,7 +208,8 @@ class MsgPackDeserializer {
|
|||||||
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)) return DeserializationError::IncompleteInput;
|
if (!readBytes(i, 8))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
doubleToFloat(i, o);
|
doubleToFloat(i, o);
|
||||||
fixEndianess(value);
|
fixEndianess(value);
|
||||||
variant.setFloat(value);
|
variant.setFloat(value);
|
||||||
@ -212,21 +219,24 @@ class MsgPackDeserializer {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(VariantData &variant) {
|
DeserializationError readString(VariantData &variant) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
return readString(variant, size);
|
return readString(variant, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DeserializationError readString(const char *&str) {
|
DeserializationError readString(const char *&str) {
|
||||||
T size;
|
T size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
return readString(str, size);
|
return readString(str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readString(VariantData &variant, size_t n) {
|
DeserializationError readString(VariantData &variant, size_t n) {
|
||||||
const char *s;
|
const char *s;
|
||||||
DeserializationError err = readString(s, n);
|
DeserializationError err = readString(s, n);
|
||||||
if (!err) variant.setOwnedString(make_not_null(s));
|
if (!err)
|
||||||
|
variant.setOwnedString(make_not_null(s));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,11 +244,13 @@ class MsgPackDeserializer {
|
|||||||
StringBuilder builder = _stringStorage.startString();
|
StringBuilder builder = _stringStorage.startString();
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
if (!readBytes(c)) return DeserializationError::IncompleteInput;
|
if (!readBytes(c))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
builder.append(static_cast<char>(c));
|
builder.append(static_cast<char>(c));
|
||||||
}
|
}
|
||||||
result = builder.complete();
|
result = builder.complete();
|
||||||
if (!result) return DeserializationError::NoMemory;
|
if (!result)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,20 +258,24 @@ class MsgPackDeserializer {
|
|||||||
DeserializationError readArray(CollectionData &array,
|
DeserializationError readArray(CollectionData &array,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
return readArray(array, size, nestingLimit);
|
return readArray(array, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readArray(CollectionData &array, size_t n,
|
DeserializationError readArray(CollectionData &array, size_t n,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantData *value = array.add(_pool);
|
VariantData *value = array.add(_pool);
|
||||||
if (!value) return DeserializationError::NoMemory;
|
if (!value)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
DeserializationError err = parse(*value, nestingLimit.decrement());
|
DeserializationError err = parse(*value, nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -269,25 +285,30 @@ class MsgPackDeserializer {
|
|||||||
DeserializationError readObject(CollectionData &object,
|
DeserializationError readObject(CollectionData &object,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
TSize size;
|
TSize size;
|
||||||
if (!readInteger(size)) return DeserializationError::IncompleteInput;
|
if (!readInteger(size))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
return readObject(object, size, nestingLimit);
|
return readObject(object, size, nestingLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeserializationError readObject(CollectionData &object, size_t n,
|
DeserializationError readObject(CollectionData &object, size_t n,
|
||||||
NestingLimit nestingLimit) {
|
NestingLimit nestingLimit) {
|
||||||
if (nestingLimit.reached()) return DeserializationError::TooDeep;
|
if (nestingLimit.reached())
|
||||||
|
return DeserializationError::TooDeep;
|
||||||
|
|
||||||
for (; n; --n) {
|
for (; n; --n) {
|
||||||
VariantSlot *slot = object.addSlot(_pool);
|
VariantSlot *slot = object.addSlot(_pool);
|
||||||
if (!slot) return DeserializationError::NoMemory;
|
if (!slot)
|
||||||
|
return DeserializationError::NoMemory;
|
||||||
|
|
||||||
const char *key;
|
const char *key;
|
||||||
DeserializationError err = parseKey(key);
|
DeserializationError err = parseKey(key);
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
slot->setOwnedKey(make_not_null(key));
|
slot->setOwnedKey(make_not_null(key));
|
||||||
|
|
||||||
err = parse(*slot->data(), nestingLimit.decrement());
|
err = parse(*slot->data(), nestingLimit.decrement());
|
||||||
if (err) return err;
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeserializationError::Ok;
|
return DeserializationError::Ok;
|
||||||
@ -295,9 +316,11 @@ class MsgPackDeserializer {
|
|||||||
|
|
||||||
DeserializationError parseKey(const char *&key) {
|
DeserializationError parseKey(const char *&key) {
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
if (!readByte(code)) return DeserializationError::IncompleteInput;
|
if (!readByte(code))
|
||||||
|
return DeserializationError::IncompleteInput;
|
||||||
|
|
||||||
if ((code & 0xe0) == 0xa0) return readString(key, code & 0x1f);
|
if ((code & 0xe0) == 0xa0)
|
||||||
|
return readString(key, code & 0x1f);
|
||||||
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 0xd9:
|
case 0xd9:
|
||||||
|
@ -70,7 +70,8 @@ class MsgPackSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void visitString(const char* value) {
|
void visitString(const char* value) {
|
||||||
if (!value) return writeByte(0xC0); // nil
|
if (!value)
|
||||||
|
return writeByte(0xC0); // nil
|
||||||
|
|
||||||
size_t n = strlen(value);
|
size_t n = strlen(value);
|
||||||
|
|
||||||
|
@ -30,13 +30,15 @@ struct FloatTraits<T, 8 /*64bits*/> {
|
|||||||
static T make_float(T m, TExponent e) {
|
static T make_float(T m, TExponent e) {
|
||||||
if (e > 0) {
|
if (e > 0) {
|
||||||
for (uint8_t index = 0; e != 0; index++) {
|
for (uint8_t index = 0; e != 0; index++) {
|
||||||
if (e & 1) m *= positiveBinaryPowerOfTen(index);
|
if (e & 1)
|
||||||
|
m *= positiveBinaryPowerOfTen(index);
|
||||||
e >>= 1;
|
e >>= 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e = TExponent(-e);
|
e = TExponent(-e);
|
||||||
for (uint8_t index = 0; e != 0; index++) {
|
for (uint8_t index = 0; e != 0; index++) {
|
||||||
if (e & 1) m *= negativeBinaryPowerOfTen(index);
|
if (e & 1)
|
||||||
|
m *= negativeBinaryPowerOfTen(index);
|
||||||
e >>= 1;
|
e >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,13 +128,15 @@ struct FloatTraits<T, 4 /*32bits*/> {
|
|||||||
static T make_float(T m, TExponent e) {
|
static T make_float(T m, TExponent e) {
|
||||||
if (e > 0) {
|
if (e > 0) {
|
||||||
for (uint8_t index = 0; e != 0; index++) {
|
for (uint8_t index = 0; e != 0; index++) {
|
||||||
if (e & 1) m *= positiveBinaryPowerOfTen(index);
|
if (e & 1)
|
||||||
|
m *= positiveBinaryPowerOfTen(index);
|
||||||
e >>= 1;
|
e >>= 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
e = -e;
|
e = -e;
|
||||||
for (uint8_t index = 0; e != 0; index++) {
|
for (uint8_t index = 0; e != 0; index++) {
|
||||||
if (e & 1) m *= negativeBinaryPowerOfTen(index);
|
if (e & 1)
|
||||||
|
m *= negativeBinaryPowerOfTen(index);
|
||||||
e >>= 1;
|
e >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,8 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_NAN
|
#if ARDUINOJSON_ENABLE_NAN
|
||||||
if (*s == 'n' || *s == 'N') return traits::nan();
|
if (*s == 'n' || *s == 'N')
|
||||||
|
return traits::nan();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ARDUINOJSON_ENABLE_INFINITY
|
#if ARDUINOJSON_ENABLE_INFINITY
|
||||||
@ -81,7 +82,8 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
return is_negative ? -traits::inf() : traits::inf();
|
return is_negative ? -traits::inf() : traits::inf();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!isdigit(*s) && *s != '.') return return_type();
|
if (!isdigit(*s) && *s != '.')
|
||||||
|
return return_type();
|
||||||
|
|
||||||
mantissa_t mantissa = 0;
|
mantissa_t mantissa = 0;
|
||||||
exponent_t exponent_offset = 0;
|
exponent_t exponent_offset = 0;
|
||||||
@ -89,14 +91,17 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
|
|
||||||
while (isdigit(*s)) {
|
while (isdigit(*s)) {
|
||||||
uint8_t digit = uint8_t(*s - '0');
|
uint8_t digit = uint8_t(*s - '0');
|
||||||
if (mantissa > maxUint / 10) break;
|
if (mantissa > maxUint / 10)
|
||||||
|
break;
|
||||||
mantissa *= 10;
|
mantissa *= 10;
|
||||||
if (mantissa > maxUint - digit) break;
|
if (mantissa > maxUint - digit)
|
||||||
|
break;
|
||||||
mantissa += digit;
|
mantissa += digit;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*s == '\0') return return_type(TUInt(mantissa), is_negative);
|
if (*s == '\0')
|
||||||
|
return return_type(TUInt(mantissa), is_negative);
|
||||||
|
|
||||||
// avoid mantissa overflow
|
// avoid mantissa overflow
|
||||||
while (mantissa > traits::mantissa_max) {
|
while (mantissa > traits::mantissa_max) {
|
||||||
@ -142,12 +147,14 @@ inline ParsedNumber<TFloat, TUInt> parseNumber(const char *s) {
|
|||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
if (negative_exponent) exponent = -exponent;
|
if (negative_exponent)
|
||||||
|
exponent = -exponent;
|
||||||
}
|
}
|
||||||
exponent += exponent_offset;
|
exponent += exponent_offset;
|
||||||
|
|
||||||
// we should be at the end of the string, otherwise it's an error
|
// we should be at the end of the string, otherwise it's an error
|
||||||
if (*s != '\0') return return_type();
|
if (*s != '\0')
|
||||||
|
return return_type();
|
||||||
|
|
||||||
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
TFloat result = traits::make_float(static_cast<TFloat>(mantissa), exponent);
|
||||||
|
|
||||||
|
@ -17,34 +17,41 @@ void objectAccept(const CollectionData *obj, Visitor &visitor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
inline bool objectEquals(const CollectionData *lhs, const CollectionData *rhs) {
|
||||||
if (lhs == rhs) return true;
|
if (lhs == rhs)
|
||||||
if (!lhs || !rhs) return false;
|
return true;
|
||||||
|
if (!lhs || !rhs)
|
||||||
|
return false;
|
||||||
return lhs->equalsObject(*rhs);
|
return lhs->equalsObject(*rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline VariantData *objectGet(const CollectionData *obj, TAdaptedString key) {
|
inline VariantData *objectGet(const CollectionData *obj, TAdaptedString key) {
|
||||||
if (!obj) return 0;
|
if (!obj)
|
||||||
|
return 0;
|
||||||
return obj->get(key);
|
return obj->get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
void objectRemove(CollectionData *obj, TAdaptedString key) {
|
void objectRemove(CollectionData *obj, TAdaptedString key) {
|
||||||
if (!obj) return;
|
if (!obj)
|
||||||
|
return;
|
||||||
obj->remove(key);
|
obj->remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline VariantData *objectGetOrCreate(CollectionData *obj, TAdaptedString key,
|
inline VariantData *objectGetOrCreate(CollectionData *obj, TAdaptedString key,
|
||||||
MemoryPool *pool) {
|
MemoryPool *pool) {
|
||||||
if (!obj) return 0;
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// ignore null key
|
// ignore null key
|
||||||
if (key.isNull()) return 0;
|
if (key.isNull())
|
||||||
|
return 0;
|
||||||
|
|
||||||
// search a matching key
|
// search a matching key
|
||||||
VariantData *var = obj->get(key);
|
VariantData *var = obj->get(key);
|
||||||
if (var) return var;
|
if (var)
|
||||||
|
return var;
|
||||||
|
|
||||||
return obj->add(key, pool);
|
return obj->add(key, pool);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ class ObjectConstRef : public ObjectRefBase<const CollectionData>,
|
|||||||
ObjectConstRef(const CollectionData* data) : base_type(data) {}
|
ObjectConstRef(const CollectionData* data) : base_type(data) {}
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data)
|
||||||
|
return iterator();
|
||||||
return iterator(_data->head());
|
return iterator(_data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +155,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE iterator begin() const {
|
FORCE_INLINE iterator begin() const {
|
||||||
if (!_data) return iterator();
|
if (!_data)
|
||||||
|
return iterator();
|
||||||
return iterator(_pool, _data->head());
|
return iterator(_pool, _data->head());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,12 +165,14 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() const {
|
void clear() const {
|
||||||
if (!_data) return;
|
if (!_data)
|
||||||
|
return;
|
||||||
_data->clear();
|
_data->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE bool set(ObjectConstRef src) {
|
FORCE_INLINE bool set(ObjectConstRef src) {
|
||||||
if (!_data || !src._data) return false;
|
if (!_data || !src._data)
|
||||||
|
return false;
|
||||||
return _data->copyFrom(*src._data, _pool);
|
return _data->copyFrom(*src._data, _pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +211,8 @@ class ObjectRef : public ObjectRefBase<CollectionData>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
FORCE_INLINE void remove(iterator it) const {
|
FORCE_INLINE void remove(iterator it) const {
|
||||||
if (!_data) return;
|
if (!_data)
|
||||||
|
return;
|
||||||
_data->remove(it.internal());
|
_data->remove(it.internal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,9 +30,12 @@ inline int strncmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b, size_t n) {
|
|||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
char c1 = *s1++;
|
char c1 = *s1++;
|
||||||
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
if (c1 < c2) return -1;
|
if (c1 < c2)
|
||||||
if (c1 > c2) return 1;
|
return -1;
|
||||||
if (c1 == 0 /* and c2 as well */) return 0;
|
if (c1 > c2)
|
||||||
|
return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -45,9 +48,12 @@ inline int strcmp_P(const char* a, ARDUINOJSON_NAMESPACE::pgm_p b) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
char c1 = *s1++;
|
char c1 = *s1++;
|
||||||
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
char c2 = static_cast<char>(pgm_read_byte(s2++));
|
||||||
if (c1 < c2) return -1;
|
if (c1 < c2)
|
||||||
if (c1 > c2) return 1;
|
return -1;
|
||||||
if (c1 == 0 /* and c2 as well */) return 0;
|
if (c1 > c2)
|
||||||
|
return 1;
|
||||||
|
if (c1 == 0 /* and c2 as well */)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,16 +9,22 @@
|
|||||||
namespace ARDUINOJSON_NAMESPACE {
|
namespace ARDUINOJSON_NAMESPACE {
|
||||||
|
|
||||||
inline int8_t safe_strcmp(const char* a, const char* b) {
|
inline int8_t safe_strcmp(const char* a, const char* b) {
|
||||||
if (a == b) return 0;
|
if (a == b)
|
||||||
if (!a) return -1;
|
return 0;
|
||||||
if (!b) return 1;
|
if (!a)
|
||||||
|
return -1;
|
||||||
|
if (!b)
|
||||||
|
return 1;
|
||||||
return static_cast<int8_t>(strcmp(a, b));
|
return static_cast<int8_t>(strcmp(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int8_t safe_strncmp(const char* a, const char* b, size_t n) {
|
inline int8_t safe_strncmp(const char* a, const char* b, size_t n) {
|
||||||
if (a == b) return 0;
|
if (a == b)
|
||||||
if (!a) return -1;
|
return 0;
|
||||||
if (!b) return 1;
|
if (!a)
|
||||||
|
return -1;
|
||||||
|
if (!b)
|
||||||
|
return 1;
|
||||||
return static_cast<int8_t>(strncmp(a, b, n));
|
return static_cast<int8_t>(strncmp(a, b, n));
|
||||||
}
|
}
|
||||||
} // namespace ARDUINOJSON_NAMESPACE
|
} // namespace ARDUINOJSON_NAMESPACE
|
||||||
|
@ -24,7 +24,8 @@ class Writer< ::String, void> {
|
|||||||
size_t write(uint8_t c) {
|
size_t write(uint8_t c) {
|
||||||
ARDUINOJSON_ASSERT(_size < bufferCapacity);
|
ARDUINOJSON_ASSERT(_size < bufferCapacity);
|
||||||
_buffer[_size++] = static_cast<char>(c);
|
_buffer[_size++] = static_cast<char>(c);
|
||||||
if (_size + 1 >= bufferCapacity) flush();
|
if (_size + 1 >= bufferCapacity)
|
||||||
|
flush();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@ class StaticStringWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t write(uint8_t c) {
|
size_t write(uint8_t c) {
|
||||||
if (p >= end) return 0;
|
if (p >= end)
|
||||||
|
return 0;
|
||||||
*p++ = static_cast<char>(c);
|
*p++ = static_cast<char>(c);
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -15,10 +15,12 @@ class ArduinoStringAdapter {
|
|||||||
ArduinoStringAdapter(const ::String& str) : _str(&str) {}
|
ArduinoStringAdapter(const ::String& str) : _str(&str) {}
|
||||||
|
|
||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (isNull()) return NULL;
|
if (isNull())
|
||||||
|
return NULL;
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
char* dup = pool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str->c_str(), n);
|
if (dup)
|
||||||
|
memcpy(dup, _str->c_str(), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ class ConstRamStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
if (!_str) return 0;
|
if (!_str)
|
||||||
|
return 0;
|
||||||
return strlen(_str);
|
return strlen(_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,12 @@ class FlashStringAdapter {
|
|||||||
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {}
|
FlashStringAdapter(const __FlashStringHelper* str) : _str(str) {}
|
||||||
|
|
||||||
int8_t compare(const char* other) const {
|
int8_t compare(const char* other) const {
|
||||||
if (!other && !_str) return 0;
|
if (!other && !_str)
|
||||||
if (!_str) return -1;
|
return 0;
|
||||||
if (!other) return 1;
|
if (!_str)
|
||||||
|
return -1;
|
||||||
|
if (!other)
|
||||||
|
return 1;
|
||||||
return int8_t(-strcmp_P(other, reinterpret_cast<const char*>(_str)));
|
return int8_t(-strcmp_P(other, reinterpret_cast<const char*>(_str)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,10 +31,12 @@ class FlashStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str)
|
||||||
|
return NULL;
|
||||||
size_t n = size() + 1; // copy the terminator
|
size_t n = size() + 1; // copy the terminator
|
||||||
char* dup = pool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
|
if (dup)
|
||||||
|
memcpy_P(dup, reinterpret_cast<const char*>(_str), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +45,8 @@ class FlashStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
if (!_str) return 0;
|
if (!_str)
|
||||||
|
return 0;
|
||||||
return strlen_P(reinterpret_cast<const char*>(_str));
|
return strlen_P(reinterpret_cast<const char*>(_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,10 +13,12 @@ class RamStringAdapter : public ConstRamStringAdapter {
|
|||||||
RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {}
|
RamStringAdapter(const char* str) : ConstRamStringAdapter(str) {}
|
||||||
|
|
||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str)
|
||||||
|
return NULL;
|
||||||
size_t n = size() + 1;
|
size_t n = size() + 1;
|
||||||
char* dup = pool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str, n);
|
if (dup)
|
||||||
|
memcpy(dup, _str, n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,12 @@ class SizedFlashStringAdapter {
|
|||||||
: _str(str), _size(sz) {}
|
: _str(str), _size(sz) {}
|
||||||
|
|
||||||
int8_t compare(const char* other) const {
|
int8_t compare(const char* other) const {
|
||||||
if (!other && !_str) return 0;
|
if (!other && !_str)
|
||||||
if (!_str) return -1;
|
return 0;
|
||||||
if (!other) return 1;
|
if (!_str)
|
||||||
|
return -1;
|
||||||
|
if (!other)
|
||||||
|
return 1;
|
||||||
return int8_t(
|
return int8_t(
|
||||||
-strncmp_P(other, reinterpret_cast<const char*>(_str), _size));
|
-strncmp_P(other, reinterpret_cast<const char*>(_str), _size));
|
||||||
}
|
}
|
||||||
@ -30,9 +33,11 @@ class SizedFlashStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str)
|
||||||
|
return NULL;
|
||||||
char* dup = pool->allocFrozenString(_size);
|
char* dup = pool->allocFrozenString(_size);
|
||||||
if (dup) memcpy_P(dup, reinterpret_cast<const char*>(_str), _size);
|
if (dup)
|
||||||
|
memcpy_P(dup, reinterpret_cast<const char*>(_str), _size);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,11 @@ class SizedRamStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
if (!_str) return NULL;
|
if (!_str)
|
||||||
|
return NULL;
|
||||||
char* dup = pool->allocFrozenString(_size);
|
char* dup = pool->allocFrozenString(_size);
|
||||||
if (dup) memcpy(dup, _str, _size);
|
if (dup)
|
||||||
|
memcpy(dup, _str, _size);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ class StlStringAdapter {
|
|||||||
char* save(MemoryPool* pool) const {
|
char* save(MemoryPool* pool) const {
|
||||||
size_t n = _str->length() + 1;
|
size_t n = _str->length() + 1;
|
||||||
char* dup = pool->allocFrozenString(n);
|
char* dup = pool->allocFrozenString(n);
|
||||||
if (dup) memcpy(dup, _str->c_str(), n);
|
if (dup)
|
||||||
|
memcpy(dup, _str->c_str(), n);
|
||||||
return dup;
|
return dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,12 +28,14 @@ class StlStringAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int8_t compare(const char* other) const {
|
int8_t compare(const char* other) const {
|
||||||
if (!other) return 1;
|
if (!other)
|
||||||
|
return 1;
|
||||||
return static_cast<int8_t>(_str->compare(other));
|
return static_cast<int8_t>(_str->compare(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equals(const char* expected) const {
|
bool equals(const char* expected) const {
|
||||||
if (!expected) return false;
|
if (!expected)
|
||||||
|
return false;
|
||||||
return *_str == expected;
|
return *_str == expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +27,12 @@ class String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
friend bool operator==(String lhs, String rhs) {
|
friend bool operator==(String lhs, String rhs) {
|
||||||
if (lhs._data == rhs._data) return true;
|
if (lhs._data == rhs._data)
|
||||||
if (!lhs._data) return false;
|
return true;
|
||||||
if (!rhs._data) return false;
|
if (!lhs._data)
|
||||||
|
return false;
|
||||||
|
if (!rhs._data)
|
||||||
|
return false;
|
||||||
return strcmp(lhs._data, rhs._data) == 0;
|
return strcmp(lhs._data, rhs._data) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,14 @@ namespace ARDUINOJSON_NAMESPACE {
|
|||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
|
inline bool slotSetKey(VariantSlot* var, TAdaptedString key, MemoryPool* pool) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
if (key.isStatic()) {
|
if (key.isStatic()) {
|
||||||
var->setLinkedKey(make_not_null(key.data()));
|
var->setLinkedKey(make_not_null(key.data()));
|
||||||
} else {
|
} else {
|
||||||
const char* dup = key.save(pool);
|
const char* dup = key.save(pool);
|
||||||
if (!dup) return false;
|
if (!dup)
|
||||||
|
return false;
|
||||||
var->setOwnedKey(make_not_null(dup));
|
var->setOwnedKey(make_not_null(dup));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -32,7 +32,8 @@ template <typename T>
|
|||||||
inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(
|
inline typename enable_if<IsWriteableString<T>::value, T>::type variantAs(
|
||||||
const VariantData* _data) {
|
const VariantData* _data) {
|
||||||
const char* cstr = _data != 0 ? _data->asString() : 0;
|
const char* cstr = _data != 0 ? _data->asString() : 0;
|
||||||
if (cstr) return T(cstr);
|
if (cstr)
|
||||||
|
return T(cstr);
|
||||||
T s;
|
T s;
|
||||||
serializeJson(VariantConstRef(_data), s);
|
serializeJson(VariantConstRef(_data), s);
|
||||||
return s;
|
return s;
|
||||||
|
@ -185,12 +185,14 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void remove(size_t index) {
|
void remove(size_t index) {
|
||||||
if (isArray()) _content.asCollection.remove(index);
|
if (isArray())
|
||||||
|
_content.asCollection.remove(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
void remove(TAdaptedString key) {
|
void remove(TAdaptedString key) {
|
||||||
if (isObject()) _content.asCollection.remove(key);
|
if (isObject())
|
||||||
|
_content.asCollection.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBoolean(bool value) {
|
void setBoolean(bool value) {
|
||||||
@ -329,8 +331,10 @@ class VariantData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VariantData *addElement(MemoryPool *pool) {
|
VariantData *addElement(MemoryPool *pool) {
|
||||||
if (isNull()) toArray();
|
if (isNull())
|
||||||
if (!isArray()) return 0;
|
toArray();
|
||||||
|
if (!isArray())
|
||||||
|
return 0;
|
||||||
return _content.asCollection.add(pool);
|
return _content.asCollection.add(pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,15 +349,19 @@ class VariantData {
|
|||||||
|
|
||||||
template <typename TAdaptedString>
|
template <typename TAdaptedString>
|
||||||
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) {
|
VariantData *getOrAddMember(TAdaptedString key, MemoryPool *pool) {
|
||||||
if (isNull()) toObject();
|
if (isNull())
|
||||||
if (!isObject()) return 0;
|
toObject();
|
||||||
|
if (!isObject())
|
||||||
|
return 0;
|
||||||
VariantData *var = _content.asCollection.get(key);
|
VariantData *var = _content.asCollection.get(key);
|
||||||
if (var) return var;
|
if (var)
|
||||||
|
return var;
|
||||||
return _content.asCollection.add(key, pool);
|
return _content.asCollection.add(key, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
|
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
|
||||||
if (_flags & VALUE_IS_OWNED) _content.asString += stringDistance;
|
if (_flags & VALUE_IS_OWNED)
|
||||||
|
_content.asString += stringDistance;
|
||||||
if (_flags & COLLECTION_MASK)
|
if (_flags & COLLECTION_MASK)
|
||||||
_content.asCollection.movePointers(stringDistance, variantDistance);
|
_content.asCollection.movePointers(stringDistance, variantDistance);
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ inline CollectionData *variantAsObject(VariantData *var) {
|
|||||||
|
|
||||||
inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
|
inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
|
||||||
MemoryPool *pool) {
|
MemoryPool *pool) {
|
||||||
if (!dst) return false;
|
if (!dst)
|
||||||
|
return false;
|
||||||
if (!src) {
|
if (!src) {
|
||||||
dst->setNull();
|
dst->setNull();
|
||||||
return true;
|
return true;
|
||||||
@ -39,8 +40,10 @@ inline bool variantCopyFrom(VariantData *dst, const VariantData *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantEquals(const VariantData *a, const VariantData *b) {
|
inline bool variantEquals(const VariantData *a, const VariantData *b) {
|
||||||
if (a == b) return true;
|
if (a == b)
|
||||||
if (!a || !b) return false;
|
return true;
|
||||||
|
if (!a || !b)
|
||||||
|
return false;
|
||||||
return a->equals(*b);
|
return a->equals(*b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,20 +77,23 @@ inline bool variantIsNull(const VariantData *var) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetBoolean(VariantData *var, bool value) {
|
inline bool variantSetBoolean(VariantData *var, bool value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setBoolean(value);
|
var->setBoolean(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetFloat(VariantData *var, Float value) {
|
inline bool variantSetFloat(VariantData *var, Float value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setFloat(value);
|
var->setFloat(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetLinkedRaw(VariantData *var,
|
inline bool variantSetLinkedRaw(VariantData *var,
|
||||||
SerializedValue<const char *> value) {
|
SerializedValue<const char *> value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setLinkedRaw(value);
|
var->setLinkedRaw(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -100,24 +106,28 @@ inline bool variantSetOwnedRaw(VariantData *var, SerializedValue<T> value,
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool variantSetSignedInteger(VariantData *var, T value) {
|
inline bool variantSetSignedInteger(VariantData *var, T value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setSignedInteger(value);
|
var->setSignedInteger(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetLinkedString(VariantData *var, const char *value) {
|
inline bool variantSetLinkedString(VariantData *var, const char *value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setLinkedString(value);
|
var->setLinkedString(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void variantSetNull(VariantData *var) {
|
inline void variantSetNull(VariantData *var) {
|
||||||
if (!var) return;
|
if (!var)
|
||||||
|
return;
|
||||||
var->setNull();
|
var->setNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetOwnedString(VariantData *var, char *value) {
|
inline bool variantSetOwnedString(VariantData *var, char *value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setOwnedString(value);
|
var->setOwnedString(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -128,7 +138,8 @@ inline bool variantSetOwnedString(VariantData *var, T value, MemoryPool *pool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool variantSetUnsignedInteger(VariantData *var, UInt value) {
|
inline bool variantSetUnsignedInteger(VariantData *var, UInt value) {
|
||||||
if (!var) return false;
|
if (!var)
|
||||||
|
return false;
|
||||||
var->setUnsignedInteger(value);
|
var->setUnsignedInteger(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -138,12 +149,14 @@ inline size_t variantSize(const VariantData *var) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline CollectionData *variantToArray(VariantData *var) {
|
inline CollectionData *variantToArray(VariantData *var) {
|
||||||
if (!var) return 0;
|
if (!var)
|
||||||
|
return 0;
|
||||||
return &var->toArray();
|
return &var->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline CollectionData *variantToObject(VariantData *var) {
|
inline CollectionData *variantToObject(VariantData *var) {
|
||||||
if (!var) return 0;
|
if (!var)
|
||||||
|
return 0;
|
||||||
return &var->toObject();
|
return &var->toObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +324,8 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
FORCE_INLINE VariantRef getOrAddMember(const TString &) const;
|
FORCE_INLINE VariantRef getOrAddMember(const TString &) const;
|
||||||
|
|
||||||
FORCE_INLINE void remove(size_t index) const {
|
FORCE_INLINE void remove(size_t index) const {
|
||||||
if (_data) _data->remove(index);
|
if (_data)
|
||||||
|
_data->remove(index);
|
||||||
}
|
}
|
||||||
// remove(char*) const
|
// remove(char*) const
|
||||||
// remove(const char*) const
|
// remove(const char*) const
|
||||||
@ -332,14 +333,16 @@ class VariantRef : public VariantRefBase<VariantData>,
|
|||||||
template <typename TChar>
|
template <typename TChar>
|
||||||
FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove(
|
FORCE_INLINE typename enable_if<IsString<TChar *>::value>::type remove(
|
||||||
TChar *key) const {
|
TChar *key) const {
|
||||||
if (_data) _data->remove(adaptString(key));
|
if (_data)
|
||||||
|
_data->remove(adaptString(key));
|
||||||
}
|
}
|
||||||
// remove(const std::string&) const
|
// remove(const std::string&) const
|
||||||
// remove(const String&) const
|
// remove(const String&) const
|
||||||
template <typename TString>
|
template <typename TString>
|
||||||
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
|
FORCE_INLINE typename enable_if<IsString<TString>::value>::type remove(
|
||||||
const TString &key) const {
|
const TString &key) const {
|
||||||
if (_data) _data->remove(adaptString(key));
|
if (_data)
|
||||||
|
_data->remove(adaptString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -49,7 +49,8 @@ class VariantSlot {
|
|||||||
VariantSlot* next(size_t distance) {
|
VariantSlot* next(size_t distance) {
|
||||||
VariantSlot* slot = this;
|
VariantSlot* slot = this;
|
||||||
while (distance--) {
|
while (distance--) {
|
||||||
if (!slot->_next) return 0;
|
if (!slot->_next)
|
||||||
|
return 0;
|
||||||
slot += slot->_next;
|
slot += slot->_next;
|
||||||
}
|
}
|
||||||
return slot;
|
return slot;
|
||||||
@ -93,8 +94,10 @@ class VariantSlot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
|
void movePointers(ptrdiff_t stringDistance, ptrdiff_t variantDistance) {
|
||||||
if (_flags & KEY_IS_OWNED) _key += stringDistance;
|
if (_flags & KEY_IS_OWNED)
|
||||||
if (_flags & VALUE_IS_OWNED) _content.asString += stringDistance;
|
_key += stringDistance;
|
||||||
|
if (_flags & VALUE_IS_OWNED)
|
||||||
|
_content.asString += stringDistance;
|
||||||
if (_flags & COLLECTION_MASK)
|
if (_flags & COLLECTION_MASK)
|
||||||
_content.asCollection.movePointers(stringDistance, variantDistance);
|
_content.asCollection.movePointers(stringDistance, variantDistance);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user