forked from bblanchon/ArduinoJson
Compare commits
20 Commits
v5.0-beta-
...
v5.0.2
Author | SHA1 | Date | |
---|---|---|---|
04b8781c8d | |||
5a4d993f7d | |||
823a172681 | |||
a1943e21ed | |||
01c287bc89 | |||
0cf8249b14 | |||
a8265a799d | |||
18bb653f10 | |||
a003a31952 | |||
0a1c27f873 | |||
75f8e25aed | |||
39c506b419 | |||
ef2641b49b | |||
bce101578d | |||
10e466426a | |||
9b90aeffa5 | |||
601b51890f | |||
2524a00a96 | |||
f5b83f9314 | |||
5e7b9ec688 |
3
.clang-format
Normal file
3
.clang-format
Normal file
@ -0,0 +1,3 @@
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
|
||||
BasedOnStyle: Google
|
10
.travis.yml
10
.travis.yml
@ -3,8 +3,18 @@ compiler:
|
||||
- gcc
|
||||
- clang
|
||||
before_install:
|
||||
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16"
|
||||
- sleep 3
|
||||
- export DISPLAY=:1.0
|
||||
- wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz
|
||||
- tar xf arduino-1.6.5-linux64.tar.xz
|
||||
- sudo mv arduino-1.6.5 /usr/local/share/arduino
|
||||
- sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino
|
||||
- sudo ln -s $PWD /usr/local/share/arduino/libraries/ArduinoJson
|
||||
- sudo pip install cpp-coveralls
|
||||
script:
|
||||
- cmake -DCOVERAGE=true . && make && make test
|
||||
- arduino --verify --board arduino:avr:uno $PWD/examples/JsonParserExample/JsonParserExample.ino
|
||||
- arduino --verify --board arduino:avr:uno $PWD/examples/JsonGeneratorExample/JsonGeneratorExample.ino
|
||||
after_success:
|
||||
- if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi
|
||||
|
26
CHANGELOG.md
26
CHANGELOG.md
@ -1,14 +1,31 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v5.0 (currently in beta)
|
||||
----
|
||||
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
|
||||
------
|
||||
|
||||
* Fixed compilation with Arduino 1.0.6 (issue #99)
|
||||
|
||||
v5.0.0
|
||||
------
|
||||
|
||||
* Added support of `String` class (issues #55, #56, #70, #77)
|
||||
* Added `JsonBuffer::strdup()` to make a copy of a string (issues #10, #57)
|
||||
* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87)
|
||||
* Added support of non standard JSON input (issue #44)
|
||||
* Added support of comments in JSON input (issue #88)
|
||||
* Added implicit cast between numerical types (issues #64, #69, #93)
|
||||
* Added ability to read number values as string (issue #90)
|
||||
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66)
|
||||
* Switched to new the library layout (requires Arduino 1.0.6 or above)
|
||||
|
||||
@ -24,6 +41,11 @@ The `String` class is **bad** because it uses dynamic memory allocation.
|
||||
Compared to static allocation, it compiles to a bigger, slower program, and is less predictable.
|
||||
You certainly don't want that in an embedded environment!
|
||||
|
||||
v4.6
|
||||
----
|
||||
|
||||
* Fixed segmentation fault in `DynamicJsonBuffer` when memory allocation fails (issue #92)
|
||||
|
||||
v4.5
|
||||
----
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
The MIT License (MIT)
|
||||
---------------------
|
||||
|
||||
Copyright © 2014 Benoit BLANCHON
|
||||
Copyright © 2014-2015 Benoit BLANCHON
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
18
README.md
18
README.md
@ -1,20 +1,20 @@
|
||||
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.*
|
||||
|
||||
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.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* JSON decoding
|
||||
* JSON decoding (comments are supported)
|
||||
* JSON encoding (with optional indentation)
|
||||
* Elegant API, very easy to use
|
||||
* Elegant API, very easy to use
|
||||
* Efficient (no malloc, nor copy)
|
||||
* Portable (written in C++98)
|
||||
* Self-contained (no external dependency)
|
||||
@ -25,7 +25,7 @@ Quick start
|
||||
-----------
|
||||
|
||||
#### Decoding / Parsing
|
||||
|
||||
|
||||
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
|
||||
|
||||
StaticJsonBuffer<200> jsonBuffer;
|
||||
@ -38,7 +38,7 @@ Quick start
|
||||
double longitude = root["data"][1];
|
||||
|
||||
#### Encoding / Generating
|
||||
|
||||
|
||||
StaticJsonBuffer<200> jsonBuffer;
|
||||
|
||||
JsonObject& root = jsonBuffer.createObject();
|
||||
@ -57,13 +57,13 @@ Quick start
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The documentation is available online in the [Arduino JSON wiki](https://github.com/bblanchon/ArduinoJson/wiki)
|
||||
The documentation is available online in the [Arduino JSON wiki](https://github.com/bblanchon/ArduinoJson/wiki)
|
||||
|
||||
Testimonials
|
||||
------------
|
||||
|
||||
From Arduino's Forum user `jflaplante`:
|
||||
> I tried aJson json-arduino before trying your library. I always ran into memory problem after a while.
|
||||
> I tried aJson json-arduino before trying your library. I always ran into memory problem after a while.
|
||||
> I have no such problem so far with your library. It is working perfectly with my web services.
|
||||
|
||||
From Arduino's Forum user `gbathree`:
|
||||
@ -80,4 +80,4 @@ From GitHub user `zacsketches`:
|
||||
|
||||
---
|
||||
|
||||
Found this library useful? [Help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile:
|
||||
Found this library useful? Please star this project or [help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile:
|
||||
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Arduino JSON library - IndentedPrint example
|
||||
* Benoit Blanchon 2014 - MIT License
|
||||
*/
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
@ -27,4 +28,4 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright Benoit Blanchon 2014
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
@ -39,4 +39,4 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright Benoit Blanchon 2014
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
@ -34,4 +34,4 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
// not used in this example
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// This class reproduces Arduino's Print
|
||||
// This class reproduces Arduino's Print class
|
||||
class Print {
|
||||
public:
|
||||
virtual ~Print() {}
|
||||
|
@ -10,7 +10,14 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef std::string String;
|
||||
// This class reproduces Arduino's String class
|
||||
class String : public std::string {
|
||||
public:
|
||||
String(const char *cstr = "") : std::string(cstr) {}
|
||||
String(const String &str) : std::string(str) {}
|
||||
explicit String(long);
|
||||
explicit String(double, unsigned char decimalPlaces = 2);
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
|
@ -6,41 +6,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonBuffer.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "Internals/BlockJsonBuffer.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
// Forward declaration
|
||||
namespace Internals {
|
||||
struct DynamicJsonBufferBlock;
|
||||
}
|
||||
|
||||
// Implements a JsonBuffer with dynamic memory allocation.
|
||||
// You are strongly encouraged to consider using StaticJsonBuffer which is much
|
||||
// more suitable for embedded systems.
|
||||
class DynamicJsonBuffer : public JsonBuffer {
|
||||
public:
|
||||
DynamicJsonBuffer();
|
||||
~DynamicJsonBuffer();
|
||||
|
||||
size_t size() const;
|
||||
|
||||
protected:
|
||||
virtual void* alloc(size_t bytes);
|
||||
|
||||
private:
|
||||
typedef Internals::DynamicJsonBufferBlock Block;
|
||||
|
||||
static const size_t FIRST_BLOCK_CAPACITY = 32;
|
||||
|
||||
static Block* createBlock(size_t capacity);
|
||||
|
||||
inline bool canAllocInHead(size_t bytes) const;
|
||||
inline void* allocInHead(size_t bytes);
|
||||
inline void addNewBlock();
|
||||
|
||||
Block* _head;
|
||||
};
|
||||
typedef Internals::BlockJsonBuffer<Internals::DefaultAllocator>
|
||||
DynamicJsonBuffer;
|
||||
}
|
||||
|
93
include/ArduinoJson/Internals/BlockJsonBuffer.hpp
Normal file
93
include/ArduinoJson/Internals/BlockJsonBuffer.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../JsonBuffer.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
class DefaultAllocator {
|
||||
public:
|
||||
void* allocate(size_t size) { return malloc(size); }
|
||||
void deallocate(void* pointer) { free(pointer); }
|
||||
};
|
||||
|
||||
template <typename TAllocator>
|
||||
class BlockJsonBuffer : public JsonBuffer {
|
||||
struct Block;
|
||||
struct EmptyBlock {
|
||||
Block* next;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
};
|
||||
struct Block : EmptyBlock {
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
public:
|
||||
BlockJsonBuffer() : _head(NULL) {}
|
||||
|
||||
~BlockJsonBuffer() {
|
||||
Block* currentBlock = _head;
|
||||
|
||||
while (currentBlock != NULL) {
|
||||
Block* nextBlock = currentBlock->next;
|
||||
_allocator.deallocate(currentBlock);
|
||||
currentBlock = nextBlock;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t total = 0;
|
||||
for (const Block* b = _head; b; b = b->next) total += b->size;
|
||||
return total;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void* alloc(size_t bytes) {
|
||||
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t FIRST_BLOCK_CAPACITY = 32;
|
||||
|
||||
bool canAllocInHead(size_t bytes) const {
|
||||
return _head != NULL && _head->size + bytes <= _head->capacity;
|
||||
}
|
||||
|
||||
void* allocInHead(size_t bytes) {
|
||||
void* p = _head->data + _head->size;
|
||||
_head->size += round_size_up(bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
void* allocInNewBlock(size_t bytes) {
|
||||
size_t capacity = FIRST_BLOCK_CAPACITY;
|
||||
if (_head != NULL) capacity = _head->capacity * 2;
|
||||
if (bytes > capacity) capacity = bytes;
|
||||
if (!addNewBlock(capacity)) return NULL;
|
||||
return allocInHead(bytes);
|
||||
}
|
||||
|
||||
bool addNewBlock(size_t capacity) {
|
||||
size_t bytes = sizeof(EmptyBlock) + capacity;
|
||||
Block* block = static_cast<Block*>(_allocator.allocate(bytes));
|
||||
if (block == NULL) return false;
|
||||
block->capacity = capacity;
|
||||
block->size = 0;
|
||||
block->next = _head;
|
||||
_head = block;
|
||||
return true;
|
||||
}
|
||||
|
||||
Block* _head;
|
||||
TAllocator _allocator;
|
||||
};
|
||||
}
|
||||
}
|
31
include/ArduinoJson/Internals/DynamicStringBuilder.hpp
Normal file
31
include/ArduinoJson/Internals/DynamicStringBuilder.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Arduino/Print.hpp"
|
||||
#include "../Arduino/String.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
// A Print implementation that allows to write in a String
|
||||
class DynamicStringBuilder : public Print {
|
||||
public:
|
||||
DynamicStringBuilder(String &str) : _str(str) {}
|
||||
|
||||
virtual size_t write(uint8_t c) {
|
||||
_str += c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
DynamicStringBuilder &operator=(const DynamicStringBuilder &);
|
||||
|
||||
String &_str;
|
||||
};
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ class JsonParser {
|
||||
public:
|
||||
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
||||
: _buffer(buffer),
|
||||
_readPtr(json),
|
||||
_readPtr(json ? json : ""),
|
||||
_writePtr(json),
|
||||
_nestingLimit(nestingLimit) {}
|
||||
|
||||
@ -28,16 +28,12 @@ class JsonParser {
|
||||
|
||||
private:
|
||||
bool skip(char charToSkip);
|
||||
bool skip(const char *wordToSkip);
|
||||
|
||||
const char *parseString();
|
||||
bool parseAnythingTo(JsonVariant *destination);
|
||||
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
|
||||
|
||||
inline bool parseArrayTo(JsonVariant *destination);
|
||||
inline bool parseBooleanTo(JsonVariant *destination);
|
||||
inline bool parseNullTo(JsonVariant *destination);
|
||||
inline bool parseNumberTo(JsonVariant *destination);
|
||||
inline bool parseObjectTo(JsonVariant *destination);
|
||||
inline bool parseStringTo(JsonVariant *destination);
|
||||
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include "IndentedPrint.hpp"
|
||||
#include "JsonWriter.hpp"
|
||||
#include "Prettyfier.hpp"
|
||||
#include "StringBuilder.hpp"
|
||||
#include "StaticStringBuilder.hpp"
|
||||
#include "DynamicStringBuilder.hpp"
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#include "StreamPrintAdapter.hpp"
|
||||
@ -33,15 +34,20 @@ class JsonPrintable {
|
||||
}
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
std::ostream& printTo(std::ostream &os) const {
|
||||
std::ostream &printTo(std::ostream &os) const {
|
||||
StreamPrintAdapter adapter(os);
|
||||
printTo(adapter);
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
size_t printTo(char *buffer, size_t bufferSize) const {
|
||||
StringBuilder sb(buffer, bufferSize);
|
||||
StaticStringBuilder sb(buffer, bufferSize);
|
||||
return printTo(sb);
|
||||
}
|
||||
|
||||
size_t printTo(String &str) const {
|
||||
DynamicStringBuilder sb(str);
|
||||
return printTo(sb);
|
||||
}
|
||||
|
||||
@ -51,7 +57,7 @@ class JsonPrintable {
|
||||
}
|
||||
|
||||
size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
|
||||
StringBuilder sb(buffer, bufferSize);
|
||||
StaticStringBuilder sb(buffer, bufferSize);
|
||||
return prettyPrintTo(sb);
|
||||
}
|
||||
|
||||
@ -60,6 +66,11 @@ class JsonPrintable {
|
||||
return prettyPrintTo(indentedPrint);
|
||||
}
|
||||
|
||||
size_t prettyPrintTo(String &str) const {
|
||||
DynamicStringBuilder sb(str);
|
||||
return prettyPrintTo(sb);
|
||||
}
|
||||
|
||||
size_t measureLength() const {
|
||||
DummyPrint dp;
|
||||
return printTo(dp);
|
||||
@ -75,11 +86,10 @@ class JsonPrintable {
|
||||
};
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
template<typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os, const JsonPrintable<T>& v) {
|
||||
template <typename T>
|
||||
inline std::ostream &operator<<(std::ostream &os, const JsonPrintable<T> &v) {
|
||||
return v.printTo(os);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,17 +17,11 @@ namespace Internals {
|
||||
// A union that defines the actual content of a JsonVariant.
|
||||
// The enum JsonVariantType determines which member is in use.
|
||||
union JsonVariantContent {
|
||||
bool asBoolean;
|
||||
double asDouble; // asDouble is also used for float
|
||||
long asLong; // asLong is also used for char, short and int
|
||||
long asLong; // asLong is also used for bool, char, short and int
|
||||
const char* asString; // asString can be null
|
||||
JsonArray* asArray; // asArray cannot be null
|
||||
JsonObject* asObject; // asObject cannot be null
|
||||
|
||||
template <typename T>
|
||||
T as() const;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include "JsonVariantContent.ipp"
|
||||
|
@ -1,96 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
// Forward declarations
|
||||
class JsonArray;
|
||||
class JsonObject;
|
||||
|
||||
namespace Internals {
|
||||
template <>
|
||||
inline bool JsonVariantContent::as<bool>() const {
|
||||
return asBoolean;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline char const* JsonVariantContent::as<char const*>() const {
|
||||
return asString;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double JsonVariantContent::as<double>() const {
|
||||
return asDouble;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float JsonVariantContent::as<float>() const {
|
||||
return static_cast<float>(asDouble);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonArray& JsonVariantContent::as<JsonArray&>() const {
|
||||
return *asArray;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonArray& JsonVariantContent::as<JsonArray const&>() const {
|
||||
return *asArray;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject& JsonVariantContent::as<JsonObject&>() const {
|
||||
return *asObject;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonObject& JsonVariantContent::as<JsonObject const&>() const {
|
||||
return *asObject;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed char JsonVariantContent::as<signed char>() const {
|
||||
return static_cast<signed char>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed int JsonVariantContent::as<signed int>() const {
|
||||
return static_cast<signed int>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed long JsonVariantContent::as<signed long>() const {
|
||||
return static_cast<signed long>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed short JsonVariantContent::as<signed short>() const {
|
||||
return static_cast<signed short>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned char JsonVariantContent::as<unsigned char>() const {
|
||||
return static_cast<unsigned char>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned int JsonVariantContent::as<unsigned int>() const {
|
||||
return static_cast<unsigned int>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long JsonVariantContent::as<unsigned long>() const {
|
||||
return static_cast<unsigned long>(asLong);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned short JsonVariantContent::as<unsigned short>() const {
|
||||
return static_cast<unsigned short>(asLong);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,11 +16,12 @@ namespace Internals {
|
||||
// The value determines which member of JsonVariantContent is used.
|
||||
enum JsonVariantType {
|
||||
JSON_UNDEFINED, // the JsonVariant has not been initialized
|
||||
JSON_UNPARSED, // the JsonVariant contains an unparsed string
|
||||
JSON_STRING, // the JsonVariant stores a const char*
|
||||
JSON_BOOLEAN, // the JsonVariant stores a bool
|
||||
JSON_LONG, // the JsonVariant stores a long
|
||||
JSON_ARRAY, // the JsonVariant stores a pointer to a JsonArray
|
||||
JSON_OBJECT, // the JsonVariant stores a pointer to a JsonObject
|
||||
JSON_BOOLEAN, // the JsonVariant stores a bool
|
||||
JSON_STRING, // the JsonVariant stores a const char*
|
||||
JSON_LONG, // the JsonVariant stores a long
|
||||
|
||||
// The following values are reserved for double values
|
||||
// Multiple values are used for double, depending on the number of decimal
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "../Arduino/Print.hpp"
|
||||
#include "Encoding.hpp"
|
||||
#include "ForceInline.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
@ -37,10 +38,8 @@ class JsonWriter {
|
||||
void writeColon() { write(':'); }
|
||||
void writeComma() { write(','); }
|
||||
|
||||
void writeBoolean(bool value) {
|
||||
write(value ? "true" : "false");
|
||||
}
|
||||
|
||||
void writeBoolean(bool value) { write(value ? "true" : "false"); }
|
||||
|
||||
void writeString(const char *value) {
|
||||
if (!value) {
|
||||
write("null");
|
||||
@ -67,9 +66,11 @@ class JsonWriter {
|
||||
_length += _sink.print(value, decimals);
|
||||
}
|
||||
|
||||
void writeRaw(const char *s) { return write(s); }
|
||||
|
||||
protected:
|
||||
void write(char c) { _length += _sink.write(c); }
|
||||
void write(const char *s) { _length += _sink.print(s); }
|
||||
FORCE_INLINE void write(const char *s) { _length += _sink.print(s); }
|
||||
|
||||
Print &_sink;
|
||||
size_t _length;
|
||||
|
@ -12,9 +12,9 @@ namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
// A Print implementation that allows to write in a char[]
|
||||
class StringBuilder : public Print {
|
||||
class StaticStringBuilder : public Print {
|
||||
public:
|
||||
StringBuilder(char *buf, int size)
|
||||
StaticStringBuilder(char *buf, int size)
|
||||
: buffer(buf), capacity(size - 1), length(0) {
|
||||
buffer[0] = '\0';
|
||||
}
|
20
include/ArduinoJson/Internals/Unparsed.hpp
Normal file
20
include/ArduinoJson/Internals/Unparsed.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
class Unparsed {
|
||||
public:
|
||||
explicit Unparsed(const char* str) : _str(str) {}
|
||||
operator const char*() const { return _str; }
|
||||
|
||||
private:
|
||||
const char* _str;
|
||||
};
|
||||
}
|
||||
}
|
@ -202,4 +202,16 @@ template <>
|
||||
inline JsonArray const &JsonVariant::invalid<JsonArray const &>() {
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonArray &JsonVariant::as<JsonArray &>() const {
|
||||
if (_type == Internals::JSON_ARRAY) return *_content.asArray;
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonArray &JsonVariant::as<const JsonArray &>() const {
|
||||
if (_type == Internals::JSON_ARRAY) return *_content.asArray;
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
}
|
||||
|
@ -14,14 +14,7 @@ class JsonArraySubscript : public JsonSubscriptBase<JsonArraySubscript> {
|
||||
FORCE_INLINE JsonArraySubscript(JsonArray& array, size_t index)
|
||||
: _array(array), _index(index) {}
|
||||
|
||||
using JsonSubscriptBase::operator=;
|
||||
|
||||
FORCE_INLINE JsonArraySubscript& operator=(const JsonArraySubscript& other) {
|
||||
// to prevent Visual Studio warning C4512: assignment operator could not be
|
||||
// generated
|
||||
_array.set(_index, other._array.get(other._index));
|
||||
return *this;
|
||||
}
|
||||
using JsonSubscriptBase<JsonArraySubscript>::operator=;
|
||||
|
||||
FORCE_INLINE bool success() const { return _index < _array.size(); }
|
||||
|
||||
|
@ -59,9 +59,15 @@ class JsonBuffer {
|
||||
// allocation fails.
|
||||
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
|
||||
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.
|
||||
@ -76,30 +82,54 @@ class JsonBuffer {
|
||||
// allocation fails.
|
||||
JsonObject &parseObject(char *json, uint8_t nestingLimit = DEFAULT_LIMIT);
|
||||
|
||||
// Same as above with a String class
|
||||
JsonObject &parseObject(const String &json, uint8_t nesting = DEFAULT_LIMIT) {
|
||||
// Same with a const char*.
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
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 char *, size_t);
|
||||
|
||||
// Allocates n bytes in the JsonBuffer.
|
||||
// Return a pointer to the allocated memory or NULL if allocation fails.
|
||||
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().
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
// level deep.
|
||||
// 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.
|
||||
static const uint8_t DEFAULT_LIMIT = 10;
|
||||
};
|
||||
|
@ -217,4 +217,16 @@ template <>
|
||||
inline JsonObject &JsonVariant::invalid<JsonObject &>() {
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject &JsonVariant::as<JsonObject &>() const {
|
||||
if (_type == Internals::JSON_OBJECT) return *_content.asObject;
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonObject &JsonVariant::as<const JsonObject &>() const {
|
||||
if (_type == Internals::JSON_OBJECT) return *_content.asObject;
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,6 @@ class JsonObjectSubscript
|
||||
|
||||
using JsonSubscriptBase<JsonObjectSubscript<TKey> >::operator=;
|
||||
|
||||
FORCE_INLINE JsonObjectSubscript<TKey>& operator=(
|
||||
const JsonObjectSubscript<TKey>& other) {
|
||||
// to prevent Visual Studio warning C4512: assignment operator could not be
|
||||
// generated
|
||||
return set(other.get());
|
||||
}
|
||||
|
||||
FORCE_INLINE bool success() const { return _object.containsKey(_key); }
|
||||
|
||||
FORCE_INLINE operator JsonVariant() const { return _object.get(_key); }
|
||||
|
@ -74,9 +74,9 @@ class JsonSubscriptBase : public JsonVariantBase<TImpl> {
|
||||
private:
|
||||
template <typename TValue>
|
||||
FORCE_INLINE TImpl& assign(TValue value) {
|
||||
TImpl* impl = static_cast<TImpl*>(this);
|
||||
impl->template set<TValue>(value);
|
||||
return *impl;
|
||||
TImpl* that = static_cast<TImpl*>(this);
|
||||
that->template set<TValue>(value);
|
||||
return *that;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Internals/JsonPrintable.hpp"
|
||||
#include "Internals/JsonVariantContent.hpp"
|
||||
#include "Internals/JsonVariantType.hpp"
|
||||
#include "Internals/Unparsed.hpp"
|
||||
#include "JsonVariantBase.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
@ -55,6 +56,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
// Create a JsonVariant containing a string.
|
||||
FORCE_INLINE JsonVariant(const char *value);
|
||||
|
||||
// Create a JsonVariant containing an unparsed string
|
||||
FORCE_INLINE JsonVariant(Internals::Unparsed value);
|
||||
|
||||
// Create a JsonVariant containing a reference to an array.
|
||||
FORCE_INLINE JsonVariant(JsonArray &array);
|
||||
|
||||
@ -64,12 +68,12 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
// Get the variant as the specified type.
|
||||
// See cast operators for details.
|
||||
template <typename T>
|
||||
FORCE_INLINE T as() const;
|
||||
T as() const;
|
||||
|
||||
// Tells weither the variant has the specified type.
|
||||
// Returns true if the variant has type type T, false otherwise.
|
||||
template <typename T>
|
||||
FORCE_INLINE bool is() const;
|
||||
bool is() const;
|
||||
|
||||
// Serialize the variant to a JsonWriter
|
||||
void writeTo(Internals::JsonWriter &writer) const;
|
||||
|
@ -12,7 +12,7 @@ namespace ArduinoJson {
|
||||
|
||||
inline JsonVariant::JsonVariant(bool value) {
|
||||
_type = Internals::JSON_BOOLEAN;
|
||||
_content.asBoolean = value;
|
||||
_content.asLong = value;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(const char *value) {
|
||||
@ -20,6 +20,11 @@ inline JsonVariant::JsonVariant(const char *value) {
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(Internals::Unparsed value) {
|
||||
_type = Internals::JSON_UNPARSED;
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(double value, uint8_t decimals) {
|
||||
_type = static_cast<Internals::JsonVariantType>(
|
||||
Internals::JSON_DOUBLE_0_DECIMALS + decimals);
|
||||
@ -82,9 +87,61 @@ inline JsonVariant::JsonVariant(unsigned short value) {
|
||||
_content.asLong = value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonVariant::as() const {
|
||||
return is<T>() ? _content.as<T>() : invalid<T>();
|
||||
template <>
|
||||
double JsonVariant::as<double>() const;
|
||||
|
||||
template <>
|
||||
long JsonVariant::as<long>() const;
|
||||
|
||||
template <>
|
||||
String JsonVariant::as<String>() const;
|
||||
|
||||
template <>
|
||||
const char *JsonVariant::as<const char *>() const;
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::as<bool>() const {
|
||||
return as<long>() != 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed char JsonVariant::as<signed char>() const {
|
||||
return static_cast<signed char>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned char JsonVariant::as<unsigned char>() const {
|
||||
return static_cast<unsigned char>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed short JsonVariant::as<signed short>() const {
|
||||
return static_cast<signed short>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned short JsonVariant::as<unsigned short>() const {
|
||||
return static_cast<unsigned short>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline signed int JsonVariant::as<signed int>() const {
|
||||
return static_cast<signed int>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned int JsonVariant::as<unsigned int>() const {
|
||||
return static_cast<unsigned int>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long JsonVariant::as<unsigned long>() const {
|
||||
return static_cast<unsigned long>(as<long>());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float JsonVariant::as<float>() const {
|
||||
return static_cast<float>(as<double>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -97,6 +154,12 @@ inline bool JsonVariant::is() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <> // in .cpp
|
||||
bool JsonVariant::is<signed long>() const;
|
||||
|
||||
template <> // in .cpp
|
||||
bool JsonVariant::is<double>() const;
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<bool>() const {
|
||||
return _type == Internals::JSON_BOOLEAN;
|
||||
@ -107,14 +170,9 @@ inline bool JsonVariant::is<char const *>() const {
|
||||
return _type == Internals::JSON_STRING;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<double>() const {
|
||||
return _type >= Internals::JSON_DOUBLE_0_DECIMALS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<float>() const {
|
||||
return _type >= Internals::JSON_DOUBLE_0_DECIMALS;
|
||||
return is<double>();
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -139,42 +197,37 @@ inline bool JsonVariant::is<JsonObject const &>() const {
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<signed char>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<signed int>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<signed long>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<signed short>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<unsigned char>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<unsigned int>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<unsigned long>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonVariant::is<unsigned short>() const {
|
||||
return _type == Internals::JSON_LONG;
|
||||
return is<signed long>();
|
||||
}
|
||||
|
||||
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||
|
@ -21,11 +21,10 @@ class StaticJsonBuffer : public JsonBuffer {
|
||||
size_t capacity() const { return CAPACITY; }
|
||||
size_t size() const { return _size; }
|
||||
|
||||
protected:
|
||||
virtual void* alloc(size_t bytes) {
|
||||
if (_size + bytes > CAPACITY) return NULL;
|
||||
void* p = &_buffer[_size];
|
||||
_size += bytes;
|
||||
_size += round_size_up(bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ArduinoJson
|
||||
version=5.0.0
|
||||
version=5.0.2
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=An efficient and elegant JSON library for Arduino.
|
||||
|
42
scripts/create-size-graph.sh
Executable file
42
scripts/create-size-graph.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
OUTPUT="$(pwd)/sizes.csv"
|
||||
|
||||
echo "Tag;Date;Parser;Generator" > $OUTPUT
|
||||
|
||||
cd $(dirname $(dirname $0))
|
||||
|
||||
git tag | while read TAG
|
||||
do
|
||||
|
||||
git checkout -q tags/$TAG
|
||||
|
||||
DATE=$(git log -1 --date=short --pretty=format:%cd)
|
||||
PARSER_SIZE=$(arduino --verify examples/JsonParserExample/JsonParserExample.ino 2>/dev/null | grep -e 'Sketch uses' | sed 's/.*uses \([0-9]*\).\([0-9]\+\).*/\1\2/')
|
||||
|
||||
if [ -e 'examples/JsonGeneratorExample/JsonGeneratorExample.ino' ]; then
|
||||
GENERATOR_SIZE=$(arduino --verify examples/JsonGeneratorExample/JsonGeneratorExample.ino 2>/dev/null | grep -e 'Sketch uses' | sed 's/.*uses \([0-9]*\).\([0-9]\+\).*/\1\2/')
|
||||
else
|
||||
GENERATOR_SIZE=""
|
||||
fi
|
||||
|
||||
echo $TAG
|
||||
if [ ! -z "$PARSER_SIZE" ]
|
||||
then
|
||||
echo "JsonParserExample = $PARSER_SIZE bytes"
|
||||
else
|
||||
echo "JsonParserExample compilation failed."
|
||||
fi
|
||||
|
||||
if [ ! -z "$GENERATOR_SIZE" ]
|
||||
then
|
||||
echo "JsonGeneratorExample = $GENERATOR_SIZE bytes"
|
||||
else
|
||||
echo "JsonGeneratorExample compilation failed."
|
||||
fi
|
||||
|
||||
echo "$TAG;$DATE;$PARSER_SIZE;$GENERATOR_SIZE" >> $OUTPUT
|
||||
|
||||
done
|
@ -17,6 +17,13 @@
|
||||
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||
#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 n = 0;
|
||||
while (*s) {
|
||||
|
25
src/Arduino/String.cpp
Normal file
25
src/Arduino/String.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#ifndef ARDUINO
|
||||
|
||||
#include "../../include/ArduinoJson/Arduino/String.hpp"
|
||||
|
||||
#include <stdio.h> // for sprintf()
|
||||
|
||||
String::String(double value, unsigned char digits) {
|
||||
char tmp[32];
|
||||
sprintf(tmp, "%.*f", digits, value);
|
||||
*this = tmp;
|
||||
}
|
||||
|
||||
String::String(long value) {
|
||||
char tmp[32];
|
||||
sprintf(tmp, "%ld", value);
|
||||
*this = tmp;
|
||||
}
|
||||
|
||||
#endif
|
@ -43,6 +43,7 @@ endif()
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_definitions(
|
||||
-Wc++11-compat
|
||||
-Wdeprecated-register
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include "../include/ArduinoJson/DynamicJsonBuffer.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
struct DynamicJsonBufferBlockWithoutData {
|
||||
DynamicJsonBufferBlock* next;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
struct DynamicJsonBufferBlock : DynamicJsonBufferBlockWithoutData {
|
||||
uint8_t data[1];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
DynamicJsonBuffer::DynamicJsonBuffer() {
|
||||
_head = createBlock(FIRST_BLOCK_CAPACITY);
|
||||
}
|
||||
|
||||
DynamicJsonBuffer::~DynamicJsonBuffer() {
|
||||
Block* currentBlock = _head;
|
||||
|
||||
while (currentBlock != NULL) {
|
||||
Block* nextBlock = currentBlock->next;
|
||||
free(currentBlock);
|
||||
currentBlock = nextBlock;
|
||||
}
|
||||
}
|
||||
|
||||
size_t DynamicJsonBuffer::size() const {
|
||||
size_t total = 0;
|
||||
|
||||
for (const Block* b = _head; b != NULL; b = b->next) {
|
||||
total += b->size;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void* DynamicJsonBuffer::alloc(size_t bytes) {
|
||||
while (!canAllocInHead(bytes)) addNewBlock();
|
||||
return allocInHead(bytes);
|
||||
}
|
||||
|
||||
bool DynamicJsonBuffer::canAllocInHead(size_t bytes) const {
|
||||
return _head->size + bytes <= _head->capacity;
|
||||
}
|
||||
|
||||
void* DynamicJsonBuffer::allocInHead(size_t bytes) {
|
||||
void* p = _head->data + _head->size;
|
||||
_head->size += bytes;
|
||||
return p;
|
||||
}
|
||||
|
||||
void DynamicJsonBuffer::addNewBlock() {
|
||||
Block* block = createBlock(_head->capacity * 2);
|
||||
block->next = _head;
|
||||
_head = block;
|
||||
}
|
||||
|
||||
DynamicJsonBuffer::Block* DynamicJsonBuffer::createBlock(size_t capacity) {
|
||||
size_t blkSize = sizeof(DynamicJsonBufferBlockWithoutData) + capacity;
|
||||
Block* block = static_cast<Block*>(malloc(blkSize));
|
||||
block->capacity = capacity;
|
||||
block->size = 0;
|
||||
block->next = NULL;
|
||||
return block;
|
||||
}
|
@ -6,9 +6,6 @@
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/JsonParser.hpp"
|
||||
|
||||
#include <stdlib.h> // for strtol, strtod
|
||||
#include <ctype.h>
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||
#include "../../include/ArduinoJson/JsonArray.hpp"
|
||||
@ -19,24 +16,13 @@ using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
bool JsonParser::skip(char charToSkip) {
|
||||
register const char *ptr = skipSpacesAndComments(_readPtr);
|
||||
const char *ptr = skipSpacesAndComments(_readPtr);
|
||||
if (*ptr != charToSkip) return false;
|
||||
ptr++;
|
||||
_readPtr = skipSpacesAndComments(ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::skip(const char *wordToSkip) {
|
||||
register const char *ptr = _readPtr;
|
||||
while (*wordToSkip && *ptr == *wordToSkip) {
|
||||
wordToSkip++;
|
||||
ptr++;
|
||||
}
|
||||
if (*wordToSkip != '\0') return false;
|
||||
_readPtr = ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
||||
if (_nestingLimit == 0) return false;
|
||||
_nestingLimit--;
|
||||
@ -55,27 +41,6 @@ inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||
case '{':
|
||||
return parseObjectTo(destination);
|
||||
|
||||
case 't':
|
||||
case 'f':
|
||||
return parseBooleanTo(destination);
|
||||
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return parseNumberTo(destination);
|
||||
|
||||
case 'n':
|
||||
return parseNullTo(destination);
|
||||
|
||||
default:
|
||||
return parseStringTo(destination);
|
||||
}
|
||||
@ -166,64 +131,24 @@ bool JsonParser::parseObjectTo(JsonVariant *destination) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::parseBooleanTo(JsonVariant *destination) {
|
||||
if (skip("true")) {
|
||||
*destination = true;
|
||||
return true;
|
||||
} else if (skip("false")) {
|
||||
*destination = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool JsonParser::parseNumberTo(JsonVariant *destination) {
|
||||
char *endOfLong;
|
||||
long longValue = strtol(_readPtr, &endOfLong, 10);
|
||||
char stopChar = *endOfLong;
|
||||
|
||||
// Could it be a floating point value?
|
||||
bool couldBeFloat = stopChar == '.' || stopChar == 'e' || stopChar == 'E';
|
||||
|
||||
if (couldBeFloat) {
|
||||
// Yes => parse it as a double
|
||||
double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr));
|
||||
// Count the decimal digits
|
||||
uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1);
|
||||
// Set the variant as a double
|
||||
*destination = JsonVariant(doubleValue, decimals);
|
||||
} else {
|
||||
// No => set the variant as a long
|
||||
_readPtr = endOfLong;
|
||||
*destination = longValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::parseNullTo(JsonVariant *destination) {
|
||||
const char *NULL_STRING = NULL;
|
||||
if (!skip("null")) return false;
|
||||
*destination = NULL_STRING;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool isInRange(char c, char min, char max) {
|
||||
return min <= c && c <= max;
|
||||
}
|
||||
|
||||
static inline bool isLetterOrNumber(char c) {
|
||||
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
|
||||
isInRange(c, 'A', 'Z');
|
||||
isInRange(c, 'A', 'Z') || c == '-' || c == '.';
|
||||
}
|
||||
|
||||
static inline bool isQuote(char c) { return c == '\'' || c == '\"'; }
|
||||
|
||||
const char *JsonParser::parseString() {
|
||||
const char *readPtr = _readPtr;
|
||||
char *writePtr = _writePtr;
|
||||
|
||||
char c = *readPtr;
|
||||
|
||||
if (c == '\'' || c == '\"') { // quotes
|
||||
if (isQuote(c)) { // quotes
|
||||
char stopChar = c;
|
||||
for (;;) {
|
||||
c = *++readPtr;
|
||||
@ -263,7 +188,13 @@ const char *JsonParser::parseString() {
|
||||
}
|
||||
|
||||
bool JsonParser::parseStringTo(JsonVariant *destination) {
|
||||
bool hasQuotes = isQuote(_readPtr[0]);
|
||||
const char *value = parseString();
|
||||
*destination = value;
|
||||
return value != NULL;
|
||||
if (value == NULL) return false;
|
||||
if (hasQuotes) {
|
||||
*destination = value;
|
||||
} else {
|
||||
*destination = Unparsed(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -4,11 +4,11 @@
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/StringBuilder.hpp"
|
||||
#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
size_t StringBuilder::write(uint8_t c) {
|
||||
size_t StaticStringBuilder::write(uint8_t c) {
|
||||
if (length >= capacity) return 0;
|
||||
|
||||
buffer[length++] = c;
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <string.h> // for strcmp
|
||||
|
||||
#include "../include/ArduinoJson/Internals/StringBuilder.hpp"
|
||||
#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../include/ArduinoJson/JsonBuffer.hpp"
|
||||
|
||||
|
@ -9,22 +9,117 @@
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../include/ArduinoJson/JsonObject.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
#include <errno.h> // for errno
|
||||
#include <stdlib.h> // for strtol, strtod
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
void JsonVariant::writeTo(JsonWriter &writer) const {
|
||||
if (is<const JsonArray &>())
|
||||
as<const JsonArray &>().writeTo(writer);
|
||||
else if (is<const JsonObject &>())
|
||||
as<const JsonObject &>().writeTo(writer);
|
||||
else if (is<const char *>())
|
||||
writer.writeString(as<const char *>());
|
||||
else if (is<long>())
|
||||
writer.writeLong(as<long>());
|
||||
else if (is<bool>())
|
||||
writer.writeBoolean(as<bool>());
|
||||
else if (is<double>()) {
|
||||
namespace ArduinoJson {
|
||||
|
||||
template <>
|
||||
const char *JsonVariant::as<const char *>() const {
|
||||
if (_type == JSON_UNPARSED && _content.asString &&
|
||||
!strcmp("null", _content.asString))
|
||||
return NULL;
|
||||
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <>
|
||||
double JsonVariant::as<double>() const {
|
||||
if (_type >= JSON_DOUBLE_0_DECIMALS) return _content.asDouble;
|
||||
|
||||
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
|
||||
return static_cast<double>(_content.asLong);
|
||||
|
||||
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString)
|
||||
return strtod(_content.asString, NULL);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
template <>
|
||||
long JsonVariant::as<long>() const {
|
||||
if (_type == JSON_LONG || _type == JSON_BOOLEAN) return _content.asLong;
|
||||
|
||||
if (_type >= JSON_DOUBLE_0_DECIMALS)
|
||||
return static_cast<long>(_content.asDouble);
|
||||
|
||||
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
|
||||
if (!strcmp("true", _content.asString)) return 1;
|
||||
return strtol(_content.asString, NULL, 10);
|
||||
}
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
template <>
|
||||
String JsonVariant::as<String>() const {
|
||||
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
|
||||
_content.asString != NULL)
|
||||
return String(_content.asString);
|
||||
|
||||
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
|
||||
return String(_content.asLong);
|
||||
|
||||
if (_type >= JSON_DOUBLE_0_DECIMALS) {
|
||||
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
|
||||
writer.writeDouble(as<double>(), decimals);
|
||||
return String(_content.asDouble, decimals);
|
||||
}
|
||||
|
||||
String s;
|
||||
printTo(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool JsonVariant::is<signed long>() const {
|
||||
if (_type == JSON_LONG) return true;
|
||||
|
||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
strtol(_content.asString, &end, 10);
|
||||
|
||||
return *end == '\0' && errno == 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool JsonVariant::is<double>() const {
|
||||
if (_type >= JSON_DOUBLE_0_DECIMALS) return true;
|
||||
|
||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
strtod(_content.asString, &end);
|
||||
|
||||
return *end == '\0' && errno == 0 && !is<long>();
|
||||
}
|
||||
|
||||
void JsonVariant::writeTo(JsonWriter &writer) const {
|
||||
if (_type == JSON_ARRAY)
|
||||
_content.asArray->writeTo(writer);
|
||||
|
||||
else if (_type == JSON_OBJECT)
|
||||
_content.asObject->writeTo(writer);
|
||||
|
||||
else if (_type == JSON_STRING)
|
||||
writer.writeString(_content.asString);
|
||||
|
||||
else if (_type == JSON_UNPARSED)
|
||||
writer.writeRaw(_content.asString);
|
||||
|
||||
else if (_type == JSON_LONG)
|
||||
writer.writeLong(_content.asLong);
|
||||
|
||||
else if (_type == JSON_BOOLEAN)
|
||||
writer.writeBoolean(_content.asLong != 0);
|
||||
|
||||
else if (_type >= JSON_DOUBLE_0_DECIMALS) {
|
||||
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
|
||||
writer.writeDouble(_content.asDouble, decimals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,3 +164,37 @@ TEST_F(ArduinoStringTests, JsonArraySubscript) {
|
||||
eraseString(value);
|
||||
ASSERT_STREQ("world", array[0]);
|
||||
}
|
||||
|
||||
TEST_F(ArduinoStringTests, JsonArray_PrintTo) {
|
||||
JsonArray &array = _jsonBuffer.createArray();
|
||||
array.add(4);
|
||||
array.add(2);
|
||||
String json;
|
||||
array.printTo(json);
|
||||
ASSERT_EQ(String("[4,2]"), json);
|
||||
}
|
||||
|
||||
TEST_F(ArduinoStringTests, JsonArray_PrettyPrintTo) {
|
||||
JsonArray &array = _jsonBuffer.createArray();
|
||||
array.add(4);
|
||||
array.add(2);
|
||||
String json;
|
||||
array.prettyPrintTo(json);
|
||||
ASSERT_EQ(String("[\r\n 4,\r\n 2\r\n]"), json);
|
||||
}
|
||||
|
||||
TEST_F(ArduinoStringTests, JsonObject_PrintTo) {
|
||||
JsonObject &object = _jsonBuffer.createObject();
|
||||
object["key"] = "value";
|
||||
String json;
|
||||
object.printTo(json);
|
||||
ASSERT_EQ(String("{\"key\":\"value\"}"), json);
|
||||
}
|
||||
|
||||
TEST_F(ArduinoStringTests, JsonObject_PrettyPrintTo) {
|
||||
JsonObject &object = _jsonBuffer.createObject();
|
||||
object["key"] = "value";
|
||||
String json;
|
||||
object.prettyPrintTo(json);
|
||||
ASSERT_EQ(String("{\r\n \"key\": \"value\"\r\n}"), json);
|
||||
}
|
||||
|
@ -10,6 +10,11 @@ include_directories(
|
||||
|
||||
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
|
||||
${TESTS_FILES}
|
||||
${INC_FILES}
|
||||
|
@ -22,9 +22,9 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
|
||||
TEST_F(DynamicJsonBuffer_Basic_Tests, SizeIncreasesAfterAlloc) {
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(1, buffer.size());
|
||||
ASSERT_LE(1, buffer.size());
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(2, buffer.size());
|
||||
ASSERT_LE(2, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
||||
@ -32,3 +32,12 @@ TEST_F(DynamicJsonBuffer_Basic_Tests, ReturnDifferentPointer) {
|
||||
void* p2 = buffer.alloc(2);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
37
test/DynamicJsonBuffer_NoMemory_Tests.cpp
Normal file
37
test/DynamicJsonBuffer_NoMemory_Tests.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class DynamicJsonBuffer_NoMemory_Tests : public ::testing::Test {
|
||||
class NoMemoryAllocator {
|
||||
public:
|
||||
void* allocate(size_t) { return NULL; }
|
||||
void deallocate(void*) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
Internals::BlockJsonBuffer<NoMemoryAllocator> _jsonBuffer;
|
||||
};
|
||||
|
||||
TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateArray) {
|
||||
ASSERT_FALSE(_jsonBuffer.createArray().success());
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_NoMemory_Tests, CreateObject) {
|
||||
ASSERT_FALSE(_jsonBuffer.createObject().success());
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseArray) {
|
||||
char json[] = "[]";
|
||||
ASSERT_FALSE(_jsonBuffer.parseArray(json).success());
|
||||
}
|
||||
|
||||
TEST_F(DynamicJsonBuffer_NoMemory_Tests, ParseObject) {
|
||||
char json[] = "{}";
|
||||
ASSERT_FALSE(_jsonBuffer.parseObject(json).success());
|
||||
}
|
28
test/Issue90.cpp
Normal file
28
test/Issue90.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <limits.h> // for LONG_MAX
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#define SUITE Issue90
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
static const char* superLong =
|
||||
"12345678901234567890123456789012345678901234567890123456789012345678901234"
|
||||
"5678901234567890123456789012345678901234567890123456789012345678901234567";
|
||||
|
||||
static const JsonVariant variant = Unparsed(superLong);
|
||||
|
||||
TEST(SUITE, IsNotALong) { ASSERT_FALSE(variant.is<long>()); }
|
||||
|
||||
TEST(SUITE, AsLong) { ASSERT_EQ(LONG_MAX, variant.as<long>()); }
|
||||
|
||||
TEST(SUITE, IsAString) { ASSERT_FALSE(variant.is<const char*>()); }
|
||||
|
||||
TEST(SUITE, AsString) { ASSERT_STREQ(superLong, variant.as<const char*>()); }
|
@ -144,26 +144,6 @@ TEST_F(JsonParser_Array_Tests, TwoNulls) {
|
||||
secondElementMustBe(nullCharPtr);
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, IncompleteNull) {
|
||||
whenInputIs("[nul!]");
|
||||
parseMustFail();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, IncompleteTrue) {
|
||||
whenInputIs("[tru!]");
|
||||
parseMustFail();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, IncompleteFalse) {
|
||||
whenInputIs("[fals!]");
|
||||
parseMustFail();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, MixedTrueFalse) {
|
||||
whenInputIs("[trufalse]");
|
||||
parseMustFail();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, TwoStringsDoubleQuotes) {
|
||||
whenInputIs("[ \"hello\" , \"world\" ]");
|
||||
|
||||
|
@ -13,21 +13,26 @@ TEST(JsonParser_Nested_Tests, ArrayNestedInObject) {
|
||||
|
||||
JsonObject &object = jsonBuffer.parseObject(jsonString);
|
||||
JsonArray &array1 = object["ab"];
|
||||
JsonArray &array2 = object["cd"];
|
||||
const JsonArray &array2 = object["cd"];
|
||||
JsonArray &array3 = object["ef"];
|
||||
|
||||
ASSERT_TRUE(object.success());
|
||||
|
||||
ASSERT_TRUE(array1.success());
|
||||
ASSERT_TRUE(array2.success());
|
||||
ASSERT_FALSE(array3.success());
|
||||
|
||||
ASSERT_EQ(2, array1.size());
|
||||
ASSERT_EQ(2, array2.size());
|
||||
ASSERT_EQ(0, array3.size());
|
||||
|
||||
EXPECT_EQ(1, array1[0].as<int>());
|
||||
EXPECT_EQ(2, array1[1].as<int>());
|
||||
|
||||
EXPECT_EQ(3, array2[0].as<int>());
|
||||
EXPECT_EQ(4, array2[1].as<int>());
|
||||
|
||||
EXPECT_EQ(0, array3[0].as<int>());
|
||||
}
|
||||
|
||||
TEST(JsonParser_Nested_Tests, ObjectNestedInArray) {
|
||||
@ -37,18 +42,22 @@ TEST(JsonParser_Nested_Tests, ObjectNestedInArray) {
|
||||
|
||||
JsonArray &array = jsonBuffer.parseArray(jsonString);
|
||||
JsonObject &object1 = array[0];
|
||||
JsonObject &object2 = array[1];
|
||||
const JsonObject &object2 = array[1];
|
||||
JsonObject &object3 = array[2];
|
||||
|
||||
ASSERT_TRUE(array.success());
|
||||
|
||||
ASSERT_TRUE(object1.success());
|
||||
ASSERT_TRUE(object2.success());
|
||||
ASSERT_FALSE(object3.success());
|
||||
|
||||
ASSERT_EQ(2, object1.size());
|
||||
ASSERT_EQ(2, object2.size());
|
||||
ASSERT_EQ(0, object3.size());
|
||||
|
||||
EXPECT_EQ(1, object1["a"].as<int>());
|
||||
EXPECT_EQ(2, object1["b"].as<int>());
|
||||
EXPECT_EQ(3, object2["c"].as<int>());
|
||||
EXPECT_EQ(4, object2["d"].as<int>());
|
||||
EXPECT_EQ(0, object3["e"].as<int>());
|
||||
}
|
||||
|
182
test/JsonVariant_As_Tests.cpp
Normal file
182
test/JsonVariant_As_Tests.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static const char* null = 0;
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleAsBool) {
|
||||
JsonVariant variant = 4.2;
|
||||
ASSERT_TRUE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleAsCstr) {
|
||||
JsonVariant variant = 4.2;
|
||||
ASSERT_FALSE(variant.as<const char*>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleAsString) {
|
||||
JsonVariant variant = 4.2;
|
||||
ASSERT_EQ(String("4.20"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleAsLong) {
|
||||
JsonVariant variant = 4.2;
|
||||
ASSERT_EQ(4L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleZeroAsBool) {
|
||||
JsonVariant variant = 0.0;
|
||||
ASSERT_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, DoubleZeroAsLong) {
|
||||
JsonVariant variant = 0.0;
|
||||
ASSERT_EQ(0L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, FalseAsBool) {
|
||||
JsonVariant variant = false;
|
||||
ASSERT_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, FalseAsDouble) {
|
||||
JsonVariant variant = false;
|
||||
ASSERT_EQ(0.0, variant.as<double>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, FalseAsLong) {
|
||||
JsonVariant variant = false;
|
||||
ASSERT_EQ(0L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, FalseAsString) {
|
||||
JsonVariant variant = false;
|
||||
ASSERT_EQ(String("0"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueAsBool) {
|
||||
JsonVariant variant = true;
|
||||
ASSERT_TRUE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueAsDouble) {
|
||||
JsonVariant variant = true;
|
||||
ASSERT_EQ(1.0, variant.as<double>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueAsLong) {
|
||||
JsonVariant variant = true;
|
||||
ASSERT_EQ(1L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueAsString) {
|
||||
JsonVariant variant = true;
|
||||
ASSERT_EQ(String("1"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, LongAsBool) {
|
||||
JsonVariant variant = 42L;
|
||||
ASSERT_TRUE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, LongZeroAsBool) {
|
||||
JsonVariant variant = 0L;
|
||||
ASSERT_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, LongAsDouble) {
|
||||
JsonVariant variant = 42L;
|
||||
ASSERT_EQ(42.0, variant.as<double>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, LongAsString) {
|
||||
JsonVariant variant = 42L;
|
||||
ASSERT_EQ(String("42"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, LongZeroAsDouble) {
|
||||
JsonVariant variant = 0L;
|
||||
ASSERT_EQ(0.0, variant.as<double>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NullAsBool) {
|
||||
JsonVariant variant = null;
|
||||
ASSERT_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NullAsDouble) {
|
||||
JsonVariant variant = null;
|
||||
ASSERT_EQ(0.0, variant.as<double>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NullAsLong) {
|
||||
JsonVariant variant = null;
|
||||
ASSERT_EQ(0L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NullAsString) {
|
||||
JsonVariant variant = null;
|
||||
ASSERT_EQ(String("null"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NumberStringAsBool) {
|
||||
JsonVariant variant = "42";
|
||||
ASSERT_TRUE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, NumberStringAsLong) {
|
||||
JsonVariant variant = "42";
|
||||
ASSERT_EQ(42L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, RandomStringAsBool) {
|
||||
JsonVariant variant = "hello";
|
||||
ASSERT_FALSE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, RandomStringAsLong) {
|
||||
JsonVariant variant = "hello";
|
||||
ASSERT_EQ(0L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, RandomStringAsString) {
|
||||
JsonVariant variant = "hello";
|
||||
ASSERT_EQ(String("hello"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueStringAsBool) {
|
||||
JsonVariant variant = "true";
|
||||
ASSERT_TRUE(variant.as<bool>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, TrueStringAsLong) {
|
||||
JsonVariant variant = "true";
|
||||
ASSERT_EQ(1L, variant.as<long>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, ObjectAsString) {
|
||||
DynamicJsonBuffer buffer;
|
||||
|
||||
JsonObject& obj = buffer.createObject();
|
||||
obj["key"] = "value";
|
||||
|
||||
JsonVariant variant = obj;
|
||||
ASSERT_EQ(String("{\"key\":\"value\"}"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, ArrayAsString) {
|
||||
DynamicJsonBuffer buffer;
|
||||
|
||||
JsonArray& arr = buffer.createArray();
|
||||
arr.add(4);
|
||||
arr.add(2);
|
||||
|
||||
JsonVariant variant = arr;
|
||||
ASSERT_EQ(String("[4,2]"), variant.as<String>());
|
||||
}
|
92
test/JsonVariant_Is_Tests.cpp
Normal file
92
test/JsonVariant_Is_Tests.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright Benoit Blanchon 2014-2015
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#define SUITE JsonVariant_Is_Tests
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
template <typename TTo, typename TFrom>
|
||||
void assertIsNot(TFrom value) {
|
||||
JsonVariant variant = value;
|
||||
ASSERT_FALSE(variant.is<TTo>());
|
||||
}
|
||||
|
||||
template <typename TTo>
|
||||
void assertIsNot(JsonArray& value) {
|
||||
JsonVariant variant = value;
|
||||
ASSERT_FALSE(variant.is<TTo>());
|
||||
}
|
||||
|
||||
template <typename TTo, typename TFrom>
|
||||
void assertIs(TFrom value) {
|
||||
JsonVariant variant = value;
|
||||
ASSERT_TRUE(variant.is<TTo>());
|
||||
}
|
||||
|
||||
template <typename TTo>
|
||||
void assertIs(JsonArray& value) {
|
||||
JsonVariant variant = value;
|
||||
ASSERT_TRUE(variant.is<TTo>());
|
||||
}
|
||||
|
||||
TEST(SUITE, ArrayIsArry) { assertIs<JsonArray&>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsBool) { assertIsNot<bool>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsDouble) { assertIsNot<double>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsFloat) { assertIsNot<float>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsInt) { assertIsNot<int>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsLong) { assertIsNot<long>(JsonArray::invalid()); }
|
||||
TEST(SUITE, ArrayIsString) { assertIsNot<const char*>(JsonArray::invalid()); }
|
||||
|
||||
TEST(SUITE, BoolIsArray) { assertIsNot<JsonArray&>(true); }
|
||||
TEST(SUITE, BoolIsBool) { assertIs<bool>(true); }
|
||||
TEST(SUITE, BoolIsDouble) { assertIsNot<double>(true); }
|
||||
TEST(SUITE, BoolIsFloat) { assertIsNot<float>(true); }
|
||||
TEST(SUITE, BoolIsInt) { assertIsNot<int>(true); }
|
||||
TEST(SUITE, BoolIsLong) { assertIsNot<long>(true); }
|
||||
TEST(SUITE, BoolIsString) { assertIsNot<const char*>(true); }
|
||||
|
||||
TEST(SUITE, DoubleIsArray) { assertIsNot<JsonArray&>(4.2); }
|
||||
TEST(SUITE, DoubleIsBool) { assertIsNot<bool>(4.2); }
|
||||
TEST(SUITE, DoubleIsDouble) { assertIs<double>(4.2); }
|
||||
TEST(SUITE, DoubleIsFloat) { assertIs<float>(4.2); }
|
||||
TEST(SUITE, DoubleIsInt) { assertIsNot<int>(4.2); }
|
||||
TEST(SUITE, DoubleIsLong) { assertIsNot<long>(4.2); }
|
||||
TEST(SUITE, DoubleIsString) { assertIsNot<const char*>(4.2); }
|
||||
|
||||
TEST(SUITE, LongIsArray) { assertIsNot<JsonArray&>(42L); }
|
||||
TEST(SUITE, LongIsBool) { assertIsNot<bool>(42L); }
|
||||
TEST(SUITE, LongIsDouble) { assertIsNot<double>(42L); }
|
||||
TEST(SUITE, LongIsFloat) { assertIsNot<float>(42L); }
|
||||
TEST(SUITE, LongIsInt) { assertIs<int>(42L); }
|
||||
TEST(SUITE, LongIsLong) { assertIs<long>(42L); }
|
||||
TEST(SUITE, LongIsString) { assertIsNot<const char*>(42L); }
|
||||
|
||||
TEST(SUITE, StringIsArray) { assertIsNot<JsonArray&>("42"); }
|
||||
TEST(SUITE, StringIsBool) { assertIsNot<bool>("42"); }
|
||||
TEST(SUITE, StringIsDouble) { assertIsNot<double>("42"); }
|
||||
TEST(SUITE, StringIsFloat) { assertIsNot<float>("42"); }
|
||||
TEST(SUITE, StringIsInt) { assertIsNot<int>("42"); }
|
||||
TEST(SUITE, StringIsLong) { assertIsNot<long>("42"); }
|
||||
TEST(SUITE, StringIsString) { assertIs<const char*>("42"); }
|
||||
|
||||
TEST(SUITE, UnparsedIntIsArra) { assertIsNot<JsonArray&>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsBool) { assertIsNot<bool>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsDouble) { assertIsNot<double>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsFloat) { assertIsNot<float>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsInt) { assertIs<int>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsLong) { assertIs<long>(Unparsed("42")); }
|
||||
TEST(SUITE, UnparsedIntIsString) { assertIsNot<const char*>(Unparsed("42")); }
|
||||
|
||||
TEST(SUITE, UnparsedFloatIsBool) { assertIsNot<bool>(Unparsed("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsDouble) { assertIs<double>(Unparsed("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsFloat) { assertIs<float>(Unparsed("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsInt) { assertIsNot<int>(Unparsed("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsLong) { assertIsNot<long>(Unparsed("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsStr) { assertIsNot<const char*>(Unparsed("4.2")); }
|
@ -7,14 +7,14 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <ArduinoJson/Internals/JsonWriter.hpp>
|
||||
#include <ArduinoJson/Internals/StringBuilder.hpp>
|
||||
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
class JsonWriter_WriteString_Tests : public testing::Test {
|
||||
protected:
|
||||
void whenInputIs(const char *input) {
|
||||
StringBuilder sb(buffer, sizeof(buffer));
|
||||
StaticStringBuilder sb(buffer, sizeof(buffer));
|
||||
JsonWriter writer(sb);
|
||||
writer.writeString(input);
|
||||
returnValue = writer.bytesWritten();
|
||||
|
@ -13,11 +13,11 @@ using namespace ArduinoJson;
|
||||
|
||||
class StaticJsonBuffer_Basic_Tests : public testing::Test {
|
||||
protected:
|
||||
StaticJsonBuffer<42> buffer;
|
||||
StaticJsonBuffer<64> buffer;
|
||||
};
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, CapacityMatchTemplateParameter) {
|
||||
ASSERT_EQ(42, buffer.capacity());
|
||||
ASSERT_EQ(64, buffer.capacity());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
@ -26,34 +26,43 @@ TEST_F(StaticJsonBuffer_Basic_Tests, InitialSizeIsZero) {
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, GrowsAfterAlloc) {
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(1, buffer.size());
|
||||
ASSERT_LE(1, buffer.size());
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(2, buffer.size());
|
||||
ASSERT_LE(2, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenFull) {
|
||||
buffer.alloc(42);
|
||||
buffer.alloc(64);
|
||||
buffer.alloc(1);
|
||||
ASSERT_EQ(42, buffer.size());
|
||||
ASSERT_EQ(64, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, DoesntGrowWhenTooSmall) {
|
||||
buffer.alloc(43);
|
||||
buffer.alloc(65);
|
||||
ASSERT_EQ(0, buffer.size());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNonNull) {
|
||||
void *p = buffer.alloc(42);
|
||||
void *p = buffer.alloc(64);
|
||||
ASSERT_NE(static_cast<void *>(0), p);
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenFull) {
|
||||
buffer.alloc(42);
|
||||
buffer.alloc(64);
|
||||
void *p = buffer.alloc(1);
|
||||
ASSERT_EQ(NULL, p);
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_Basic_Tests, ReturnsNullWhenTooSmall) {
|
||||
void *p = buffer.alloc(43);
|
||||
void *p = buffer.alloc(65);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -69,4 +69,12 @@ TEST_F(StaticJsonBuffer_ParseArray_Tests,
|
||||
with(bufferOfRightSize);
|
||||
whenInputIs("[{}]");
|
||||
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());
|
||||
}
|
||||
|
@ -70,4 +70,12 @@ TEST_F(StaticJsonBuffer_ParseObject_Tests,
|
||||
with(bufferOfRightSize);
|
||||
whenInputIs("{\"a\":[]}");
|
||||
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());
|
||||
}
|
||||
|
@ -5,14 +5,14 @@
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ArduinoJson/Internals/StringBuilder.hpp>
|
||||
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
class StringBuilderTests : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
_stringBuilder = new StringBuilder(_buffer, sizeof(_buffer));
|
||||
_stringBuilder = new StaticStringBuilder(_buffer, sizeof(_buffer));
|
||||
}
|
||||
|
||||
virtual void TearDown() { delete _stringBuilder; }
|
||||
|
Reference in New Issue
Block a user