forked from bblanchon/ArduinoJson
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
04b8781c8d | |||
5a4d993f7d | |||
823a172681 | |||
a1943e21ed | |||
01c287bc89 | |||
0cf8249b14 | |||
a8265a799d | |||
18bb653f10 |
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,6 +1,16 @@
|
|||||||
ArduinoJson: change log
|
ArduinoJson: change log
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
v5.0.2
|
||||||
|
------
|
||||||
|
|
||||||
|
* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the
|
||||||
|
`StaticJsonBuffer` is too small to hold a copy of the string
|
||||||
|
* Fixed Clang warning "register specifier is deprecated" (issue #102)
|
||||||
|
* Fixed GCC warning "declaration shadows a member" (issue #103)
|
||||||
|
* Fixed memory alignment, which made ESP8266 crash (issue #104)
|
||||||
|
* Fixed compilation on Visual Studio 2010 and 2012 (issue #107)
|
||||||
|
|
||||||
v5.0.1
|
v5.0.1
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Arduino JSON library
|
Arduino JSON library
|
||||||
====================
|
====================
|
||||||
|
|
||||||
[](https://travis-ci.org/bblanchon/ArduinoJson) [](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master)
|
[](https://ci.appveyor.com/project/bblanchon/arduinojson/branch/master) [](https://travis-ci.org/bblanchon/ArduinoJson) [](https://coveralls.io/r/bblanchon/ArduinoJson?branch=master)
|
||||||
|
|
||||||
*An elegant and efficient JSON library for embedded systems.*
|
*An elegant and efficient JSON library for embedded systems.*
|
||||||
|
|
||||||
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
|
It's designed to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
|
||||||
|
|
||||||
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
|
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class BlockJsonBuffer : public JsonBuffer {
|
|||||||
|
|
||||||
void* allocInHead(size_t bytes) {
|
void* allocInHead(size_t bytes) {
|
||||||
void* p = _head->data + _head->size;
|
void* p = _head->data + _head->size;
|
||||||
_head->size += bytes;
|
_head->size += round_size_up(bytes);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,8 +76,8 @@ class BlockJsonBuffer : public JsonBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool addNewBlock(size_t capacity) {
|
bool addNewBlock(size_t capacity) {
|
||||||
size_t size = sizeof(EmptyBlock) + capacity;
|
size_t bytes = sizeof(EmptyBlock) + capacity;
|
||||||
Block* block = static_cast<Block*>(_allocator.allocate(size));
|
Block* block = static_cast<Block*>(_allocator.allocate(bytes));
|
||||||
if (block == NULL) return false;
|
if (block == NULL) return false;
|
||||||
block->capacity = capacity;
|
block->capacity = capacity;
|
||||||
block->size = 0;
|
block->size = 0;
|
||||||
|
@ -19,7 +19,7 @@ class JsonParser {
|
|||||||
public:
|
public:
|
||||||
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
||||||
: _buffer(buffer),
|
: _buffer(buffer),
|
||||||
_readPtr(json),
|
_readPtr(json ? json : ""),
|
||||||
_writePtr(json),
|
_writePtr(json),
|
||||||
_nestingLimit(nestingLimit) {}
|
_nestingLimit(nestingLimit) {}
|
||||||
|
|
||||||
|
@ -59,9 +59,15 @@ class JsonBuffer {
|
|||||||
// allocation fails.
|
// allocation fails.
|
||||||
JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
JsonArray &parseArray(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
||||||
|
|
||||||
|
// Same with a const char*.
|
||||||
|
// With this overload, the JsonBuffer will make a copy of the string
|
||||||
|
JsonArray &parseArray(const char *json, uint8_t nesting = DEFAULT_LIMIT) {
|
||||||
|
return parseArray(strdup(json), nesting);
|
||||||
|
}
|
||||||
|
|
||||||
// Same as above with a String class
|
// Same as above with a String class
|
||||||
JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
|
JsonArray &parseArray(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
|
||||||
return parseArray(strdup(json), nesting);
|
return parseArray(json.c_str(), nesting);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocates and populate a JsonObject from a JSON string.
|
// Allocates and populate a JsonObject from a JSON string.
|
||||||
@ -76,30 +82,54 @@ class JsonBuffer {
|
|||||||
// allocation fails.
|
// allocation fails.
|
||||||
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
||||||
|
|
||||||
// Same as above with a String class
|
// Same with a const char*.
|
||||||
JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
|
// With this overload, the JsonBuffer will make a copy of the string
|
||||||
|
JsonObject &parseObject(const char *json, uint8_t nesting = DEFAULT_LIMIT) {
|
||||||
return parseObject(strdup(json), nesting);
|
return parseObject(strdup(json), nesting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same as above with a String class
|
||||||
|
JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
|
||||||
|
return parseObject(json.c_str(), nesting);
|
||||||
|
}
|
||||||
|
|
||||||
// Duplicate a string
|
// Duplicate a string
|
||||||
char *strdup(const char *src) { return strdup(src, strlen(src)); }
|
char *strdup(const char *src) {
|
||||||
|
return src ? strdup(src, strlen(src)) : NULL;
|
||||||
|
}
|
||||||
char *strdup(const String &src) { return strdup(src.c_str(), src.length()); }
|
char *strdup(const String &src) { return strdup(src.c_str(), src.length()); }
|
||||||
char *strdup(const char *, size_t);
|
|
||||||
|
|
||||||
// Allocates n bytes in the JsonBuffer.
|
// Allocates n bytes in the JsonBuffer.
|
||||||
// Return a pointer to the allocated memory or NULL if allocation fails.
|
// Return a pointer to the allocated memory or NULL if allocation fails.
|
||||||
virtual void *alloc(size_t size) = 0;
|
virtual void *alloc(size_t size) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Preserve aligment if nessary
|
||||||
|
static FORCE_INLINE size_t round_size_up(size_t bytes) {
|
||||||
|
#if defined ARDUINO_ARCH_AVR
|
||||||
|
// alignment isn't needed for 8-bit AVR
|
||||||
|
return bytes;
|
||||||
|
#else
|
||||||
|
const size_t x = sizeof(void *) - 1;
|
||||||
|
return (bytes + x) & ~x;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *strdup(const char *, size_t);
|
||||||
|
|
||||||
// Default value of nesting limit of parseArray() and parseObject().
|
// Default value of nesting limit of parseArray() and parseObject().
|
||||||
//
|
//
|
||||||
// The nesting limit is a contain on the level of nesting allowed in the JSON
|
// The nesting limit is a contain on the level of nesting allowed in the
|
||||||
|
// JSON
|
||||||
// string.
|
// string.
|
||||||
// If set to 0, only a flat array or objects can be parsed.
|
// If set to 0, only a flat array or objects can be parsed.
|
||||||
// If set to 1, the object can contain nested arrays or objects but only 1
|
// If set to 1, the object can contain nested arrays or objects but only 1
|
||||||
// level deep.
|
// level deep.
|
||||||
// And bigger values will allow more level of nesting.
|
// And bigger values will allow more level of nesting.
|
||||||
//
|
//
|
||||||
// The purpose of this feature is to prevent stack overflow that could lead to
|
// The purpose of this feature is to prevent stack overflow that could
|
||||||
|
// lead to
|
||||||
// a security risk.
|
// a security risk.
|
||||||
static const uint8_t DEFAULT_LIMIT = 10;
|
static const uint8_t DEFAULT_LIMIT = 10;
|
||||||
};
|
};
|
||||||
|
@ -74,9 +74,9 @@ class JsonSubscriptBase : public JsonVariantBase<TImpl> {
|
|||||||
private:
|
private:
|
||||||
template <typename TValue>
|
template <typename TValue>
|
||||||
FORCE_INLINE TImpl& assign(TValue value) {
|
FORCE_INLINE TImpl& assign(TValue value) {
|
||||||
TImpl* impl = static_cast<TImpl*>(this);
|
TImpl* that = static_cast<TImpl*>(this);
|
||||||
impl->template set<TValue>(value);
|
that->template set<TValue>(value);
|
||||||
return *impl;
|
return *that;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,10 @@ class StaticJsonBuffer : public JsonBuffer {
|
|||||||
size_t capacity() const { return CAPACITY; }
|
size_t capacity() const { return CAPACITY; }
|
||||||
size_t size() const { return _size; }
|
size_t size() const { return _size; }
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void* alloc(size_t bytes) {
|
virtual void* alloc(size_t bytes) {
|
||||||
if (_size + bytes > CAPACITY) return NULL;
|
if (_size + bytes > CAPACITY) return NULL;
|
||||||
void* p = &_buffer[_size];
|
void* p = &_buffer[_size];
|
||||||
_size += bytes;
|
_size += round_size_up(bytes);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=ArduinoJson
|
name=ArduinoJson
|
||||||
version=5.0.1
|
version=5.0.2
|
||||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||||
sentence=An efficient and elegant JSON library for Arduino.
|
sentence=An efficient and elegant JSON library for Arduino.
|
||||||
|
@ -17,6 +17,13 @@
|
|||||||
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Visual Studo 2012 didn't have isnan, nor isinf
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||||
|
#include <float.h>
|
||||||
|
#define isnan(x) _isnan(x)
|
||||||
|
#define isinf(x) (!_finite(x))
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t Print::print(const char s[]) {
|
size_t Print::print(const char s[]) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
|
@ -43,6 +43,7 @@ endif()
|
|||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
add_definitions(
|
add_definitions(
|
||||||
-Wc++11-compat
|
-Wc++11-compat
|
||||||
|
-Wdeprecated-register
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ using namespace ArduinoJson;
|
|||||||
using namespace ArduinoJson::Internals;
|
using namespace ArduinoJson::Internals;
|
||||||
|
|
||||||
bool JsonParser::skip(char charToSkip) {
|
bool JsonParser::skip(char charToSkip) {
|
||||||
register const char *ptr = skipSpacesAndComments(_readPtr);
|
const char *ptr = skipSpacesAndComments(_readPtr);
|
||||||
if (*ptr != charToSkip) return false;
|
if (*ptr != charToSkip) return false;
|
||||||
ptr++;
|
ptr++;
|
||||||
_readPtr = skipSpacesAndComments(ptr);
|
_readPtr = skipSpacesAndComments(ptr);
|
||||||
|
@ -10,6 +10,11 @@ include_directories(
|
|||||||
|
|
||||||
add_definitions(-DGTEST_HAS_PTHREAD=0)
|
add_definitions(-DGTEST_HAS_PTHREAD=0)
|
||||||
|
|
||||||
|
# Workaround for Visual Studio 2012
|
||||||
|
if (MSVC AND MSVC_VERSION EQUAL 1700)
|
||||||
|
add_definitions(-D_VARIADIC_MAX=10)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(ArduinoJsonTests
|
add_executable(ArduinoJsonTests
|
||||||
${TESTS_FILES}
|
${TESTS_FILES}
|
||||||
${INC_FILES}
|
${INC_FILES}
|
||||||
|
@ -22,9 +22,9 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
|||||||
|
|
||||||
TEST_F(DynamicJsonBuffer_Basic_Tests, SizeIncreasesAfterAlloc) {
|
TEST_F(DynamicJsonBuffer_Basic_Tests, SizeIncreasesAfterAlloc) {
|
||||||
buffer.alloc(1);
|
buffer.alloc(1);
|
||||||
ASSERT_EQ(1, buffer.size());
|
ASSERT_LE(1, buffer.size());
|
||||||
buffer.alloc(1);
|
buffer.alloc(1);
|
||||||
ASSERT_EQ(2, buffer.size());
|
ASSERT_LE(2, buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
||||||
@ -32,3 +32,12 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
|||||||
void* p2 = buffer.alloc(2);
|
void* p2 = buffer.alloc(2);
|
||||||
ASSERT_NE(p1, p2);
|
ASSERT_NE(p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DynamicJsonBuffer_Basic_Tests, Alignment) {
|
||||||
|
size_t mask = sizeof(void*) - 1;
|
||||||
|
|
||||||
|
for (size_t size = 1; size <= sizeof(void*); size++) {
|
||||||
|
size_t addr = reinterpret_cast<size_t>(buffer.alloc(1));
|
||||||
|
ASSERT_EQ(0, addr & mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,11 +13,11 @@ using namespace ArduinoJson;
|
|||||||
|
|
||||||
class StaticJsonBuffer_Basic_Tests : public testing::Test {
|
class StaticJsonBuffer_Basic_Tests : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
StaticJsonBuffer<42> buffer;
|
StaticJsonBuffer<64> buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, CapacityMatchTemplateParameter) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, CapacityMatchTemplateParameter) {
|
||||||
ASSERT_EQ(42, buffer.capacity());
|
ASSERT_EQ(64, buffer.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||||
@ -26,34 +26,43 @@ TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
|||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, GrowsAfterAlloc) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, GrowsAfterAlloc) {
|
||||||
buffer.alloc(1);
|
buffer.alloc(1);
|
||||||
ASSERT_EQ(1, buffer.size());
|
ASSERT_LE(1, buffer.size());
|
||||||
buffer.alloc(1);
|
buffer.alloc(1);
|
||||||
ASSERT_EQ(2, buffer.size());
|
ASSERT_LE(2, buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenFull) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenFull) {
|
||||||
buffer.alloc(42);
|
buffer.alloc(64);
|
||||||
buffer.alloc(1);
|
buffer.alloc(1);
|
||||||
ASSERT_EQ(42, buffer.size());
|
ASSERT_EQ(64, buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenTooSmall) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenTooSmall) {
|
||||||
buffer.alloc(43);
|
buffer.alloc(65);
|
||||||
ASSERT_EQ(0, buffer.size());
|
ASSERT_EQ(0, buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNonNull) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNonNull) {
|
||||||
void *p = buffer.alloc(42);
|
void *p = buffer.alloc(64);
|
||||||
ASSERT_NE(static_cast<void *>(0), p);
|
ASSERT_NE(static_cast<void *>(0), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenFull) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenFull) {
|
||||||
buffer.alloc(42);
|
buffer.alloc(64);
|
||||||
void *p = buffer.alloc(1);
|
void *p = buffer.alloc(1);
|
||||||
ASSERT_EQ(NULL, p);
|
ASSERT_EQ(NULL, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenTooSmall) {
|
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenTooSmall) {
|
||||||
void *p = buffer.alloc(43);
|
void *p = buffer.alloc(65);
|
||||||
ASSERT_EQ(NULL, p);
|
ASSERT_EQ(NULL, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StaticJsonBuffer_Basic_Tests, Alignment) {
|
||||||
|
size_t mask = sizeof(void *) - 1;
|
||||||
|
|
||||||
|
for (size_t size = 1; size <= sizeof(void *); size++) {
|
||||||
|
size_t addr = reinterpret_cast<size_t>(buffer.alloc(1));
|
||||||
|
ASSERT_EQ(0, addr & mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -70,3 +70,11 @@ TEST_F(StaticJsonBuffer_ParseArray_Tests,
|
|||||||
whenInputIs("[{}]");
|
whenInputIs("[{}]");
|
||||||
parseMustSucceed();
|
parseMustSucceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StaticJsonBuffer_ParseArray_Tests, CharPtrNull) {
|
||||||
|
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((char*)0).success());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StaticJsonBuffer_ParseArray_Tests, ConstCharPtrNull) {
|
||||||
|
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((const char*)0).success());
|
||||||
|
}
|
||||||
|
@ -71,3 +71,11 @@ TEST_F(StaticJsonBuffer_ParseObject_Tests,
|
|||||||
whenInputIs("{\"a\":[]}");
|
whenInputIs("{\"a\":[]}");
|
||||||
parseMustSucceed();
|
parseMustSucceed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StaticJsonBuffer_ParseObject_Tests, CharPtrNull) {
|
||||||
|
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((char*)0).success());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StaticJsonBuffer_ParseObject_Tests, ConstCharPtrNull) {
|
||||||
|
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((const char*)0).success());
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user