mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-03 21:57:02 +02:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
387b565705 | |||
96f486001d | |||
a498abc14a | |||
c64340a9bb | |||
79d80a5dbf | |||
7ebff5949f | |||
434080572c | |||
c87a0e97ab | |||
2dbd94951c | |||
1e044f50c7 | |||
a7aa98510c | |||
729ab56878 | |||
907b627e16 | |||
10fcca20f8 | |||
59cd1f1433 | |||
4a2c570270 | |||
8c7edbd9c3 | |||
0801e16327 | |||
0df2a365f5 | |||
c7d6d33e6c | |||
c705f3cfeb | |||
7fecb36aee | |||
657a2ea8d9 | |||
dd064f4c96 | |||
3bc05b97ea | |||
bbd515f6f6 | |||
9b3e3a3d9c | |||
a3a2ca4796 | |||
eab13dc565 | |||
bebd1c400c | |||
36d1bb2f52 |
@ -1,4 +1,5 @@
|
||||
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
|
||||
BasedOnStyle: Google
|
||||
Standard: Cpp03
|
||||
Standard: Cpp03
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
|
11
.github/ISSUE_TEMPLATE.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<!--
|
||||
Thanks for using ArduinoJson :-)
|
||||
|
||||
Before opening an issue, please make sure you've read these:
|
||||
https://github.com/bblanchon/ArduinoJson/wiki/FAQ
|
||||
https://github.com/bblanchon/ArduinoJson/wiki/Avoiding-pitfalls
|
||||
|
||||
Next, make sure you provide all the relevant information: platform, code snippet, and error messages.
|
||||
|
||||
Please be concise!
|
||||
-->
|
45
.travis.yml
45
.travis.yml
@ -64,17 +64,50 @@ matrix:
|
||||
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.7']
|
||||
packages: ['clang-3.7']
|
||||
env: SCRIPT=cmake CMAKE_CXX_COMPILER=clang++-3.7
|
||||
# - compiler: clang
|
||||
# addons:
|
||||
# apt:
|
||||
# sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.8']
|
||||
# packages: ['clang-3.8']
|
||||
# env: SCRIPT=cmake CMAKE_CXX_COMPILER=clang++-3.8
|
||||
- compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test','llvm-toolchain-precise-3.8']
|
||||
packages: ['clang-3.8']
|
||||
env: SCRIPT=cmake CMAKE_CXX_COMPILER=clang++-3.8
|
||||
- compiler: gcc
|
||||
env: SCRIPT=coverage
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.1
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.2
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: beta-xcode6.3
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: xcode7.1
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: xcode7.2
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
compiler: clang
|
||||
env: SCRIPT=cmake-osx
|
||||
- env: SCRIPT=arduino VERSION=1.5.8 BOARD=arduino:avr:uno
|
||||
- env: SCRIPT=arduino VERSION=1.6.7 BOARD=arduino:avr:uno
|
||||
- env: SCRIPT=arduino VERSION=1.6.8 BOARD=arduino:avr:uno
|
||||
- env: SCRIPT=arduino VERSION=1.6.9 BOARD=arduino:avr:uno
|
||||
- env: SCRIPT=platformio BOARD=uno
|
||||
- env: SCRIPT=platformio BOARD=due
|
||||
- env: SCRIPT=platformio BOARD=esp01
|
||||
|
@ -5,10 +5,4 @@
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
// About this file
|
||||
// ---------------
|
||||
// This file is here for [PlatformIO](http://platformio.org/).
|
||||
// It must be present in the root for the tool to find it.
|
||||
// Feel free to ignore this file if your working in another environment.
|
||||
|
||||
#include "include/ArduinoJson.h"
|
||||
|
51
CHANGELOG.md
51
CHANGELOG.md
@ -1,6 +1,49 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v5.6.5
|
||||
------
|
||||
|
||||
* `as<char*>()` now returns `true` when input is `null` (issue #330)
|
||||
|
||||
v5.6.4
|
||||
------
|
||||
|
||||
* Fixed error in float serialization (issue #324)
|
||||
|
||||
v5.6.3
|
||||
------
|
||||
|
||||
* Improved speed of float serialization (about twice faster)
|
||||
* Added `as<JsonArray>()` as a synonym for `as<JsonArray&>()`... (issue #291)
|
||||
* Fixed `call of overloaded isinf(double&) is ambiguous` (issue #284)
|
||||
|
||||
v5.6.2
|
||||
------
|
||||
|
||||
* Fixed build when another lib does `#undef isnan` (issue #284)
|
||||
|
||||
v5.6.1
|
||||
------
|
||||
|
||||
* Added missing `#pragma once` (issue #310)
|
||||
|
||||
v5.6.0
|
||||
------
|
||||
|
||||
* ArduinoJson is now a header-only library (issue #199)
|
||||
|
||||
v5.5.1
|
||||
------
|
||||
|
||||
* Fixed compilation error with Intel Galileo (issue #299)
|
||||
|
||||
v5.5.0
|
||||
------
|
||||
|
||||
* Added `JsonVariant::success()` (issue #279)
|
||||
* Renamed `JsonVariant::invalid<T>()` to `JsonVariant::defaultValue<T>()`
|
||||
|
||||
v5.4.0
|
||||
------
|
||||
|
||||
@ -79,7 +122,7 @@ v5.0.3
|
||||
v5.0.2
|
||||
------
|
||||
|
||||
* Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the
|
||||
* 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)
|
||||
@ -195,14 +238,14 @@ v3.1
|
||||
|
||||
Old generator API:
|
||||
|
||||
JsonObject<3> root;
|
||||
JsonObject<3> root;
|
||||
root.add("sensor", "gps");
|
||||
root.add("time", 1351824120);
|
||||
root.add("data", array);
|
||||
|
||||
New generator API:
|
||||
|
||||
JsonObject<3> root;
|
||||
JsonObject<3> root;
|
||||
root["sensor"] = "gps";
|
||||
root["time"] = 1351824120;
|
||||
root["data"] = array;
|
||||
@ -259,7 +302,7 @@ v1.1
|
||||
* Example: changed `char* json` into `char[] json` so that the bytes are not write protected
|
||||
* Fixed parsing bug when the JSON contains multi-dimensional arrays
|
||||
|
||||
v1.0
|
||||
v1.0
|
||||
----
|
||||
|
||||
Initial release
|
||||
|
@ -5,7 +5,7 @@
|
||||
# https://github.com/bblanchon/ArduinoJson
|
||||
# If you like this project, please add a star!
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(ArduinoJson)
|
||||
|
||||
enable_testing()
|
||||
@ -18,5 +18,4 @@ if(${COVERAGE})
|
||||
set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(test)
|
||||
|
24
README.md
24
README.md
@ -20,6 +20,7 @@ Features
|
||||
* Portable (written in C++98)
|
||||
* Self-contained (no external dependency)
|
||||
* Small footprint
|
||||
* Header-only library
|
||||
* MIT License
|
||||
|
||||
Works on
|
||||
@ -28,7 +29,7 @@ Works on
|
||||
* All Arduino boards (Uno, Due, Mini, Micro, Yun...)
|
||||
* ESP8266
|
||||
* Teensy
|
||||
* Intel Edison
|
||||
* Intel Edison and Galileo
|
||||
* PlatformIO
|
||||
* Energia
|
||||
* RedBearLab boards (BLE Nano...)
|
||||
@ -110,14 +111,19 @@ Donators
|
||||
|
||||
Special thanks to the following persons and companies who made generous donations to the library author:
|
||||
|
||||
* Robert Murphy
|
||||
* Surge Communications
|
||||
* Alex Scott
|
||||
* Firepick Services LLC
|
||||
* A B Doodkorte
|
||||
* Scott Smith
|
||||
* Johann Stieger
|
||||
* Gustavo Donizeti Gini
|
||||
* Robert Murphy <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
|
||||
* Surge Communications <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
|
||||
* Alex Scott <img alt='United Kingdom' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1ec-1f1e7.svg' width='18' height='18'>
|
||||
* Firepick Services LLC <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
|
||||
* A B Doodkorte <img alt='Netherlands' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1f3-1f1f1.svg' width='18' height='18'>
|
||||
* Scott Smith <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
|
||||
* Johann Stieger <img alt='Austria' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1e6-1f1f9.svg' width='18' height='18'>
|
||||
* Gustavo Donizeti Gini <img alt='Brazil' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1e7-1f1f7.svg' width='18' height='18'>
|
||||
* Charles-Henri Hallard <img alt='France' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1eb-1f1f7.svg' width='18' height='18'>
|
||||
* Martijn van den Burg <img alt='Netherlands' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1f3-1f1f1.svg' width='18' height='18'>
|
||||
* Nick Koumaris <img alt='Greece' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1ec-1f1f7.svg' width='18' height='18'>
|
||||
* Jon Williams <img alt='USA' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1fa-1f1f8.svg' width='18' height='18'>
|
||||
* Kestutis Liaugminas <img alt='Lithuania' src='https://cdnjs.cloudflare.com/ajax/libs/emojione/2.1.4/assets/svg/1f1f1-1f1f9.svg' width='18' height='18'>
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,11 +1,13 @@
|
||||
version: 5.4.0.{build}
|
||||
version: 5.6.5.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- CMAKE_GENERATOR: Visual Studio 14 2015
|
||||
- CMAKE_GENERATOR: Visual Studio 12 2013
|
||||
- CMAKE_GENERATOR: Visual Studio 11 2012
|
||||
- CMAKE_GENERATOR: Visual Studio 10 2010
|
||||
- CMAKE_GENERATOR: MinGW Makefiles
|
||||
# - CMAKE_GENERATOR: MinGW Makefiles
|
||||
# Note: Disabled because of unexplicated error -1073741511
|
||||
# This used to work fine with GCC 4.8.2 then failed after they upgraded to GCC 4.9.3
|
||||
configuration: Debug
|
||||
before_build:
|
||||
- set PATH=C:\MinGW\bin;%PATH:C:\Program Files\Git\usr\bin;=% # Workaround for CMake not wanting sh.exe on PATH for MinGW
|
||||
|
@ -5,9 +5,5 @@
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "ArduinoJson/DynamicJsonBuffer.hpp"
|
||||
#include "ArduinoJson/JsonArray.hpp"
|
||||
#include "ArduinoJson/JsonObject.hpp"
|
||||
#include "ArduinoJson/StaticJsonBuffer.hpp"
|
||||
|
||||
#include "ArduinoJson.hpp"
|
||||
using namespace ArduinoJson;
|
||||
|
21
include/ArduinoJson.hpp
Normal file
21
include/ArduinoJson.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ArduinoJson/DynamicJsonBuffer.hpp"
|
||||
#include "ArduinoJson/JsonArray.hpp"
|
||||
#include "ArduinoJson/JsonObject.hpp"
|
||||
#include "ArduinoJson/StaticJsonBuffer.hpp"
|
||||
|
||||
#include "ArduinoJson/Internals/JsonParser.ipp"
|
||||
#include "ArduinoJson/JsonArray.ipp"
|
||||
#include "ArduinoJson/JsonBuffer.ipp"
|
||||
#include "ArduinoJson/JsonObject.ipp"
|
||||
#include "ArduinoJson/JsonVariant.ipp"
|
||||
|
||||
using namespace ArduinoJson;
|
@ -11,12 +11,26 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#endif
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
class DefaultAllocator {
|
||||
public:
|
||||
void* allocate(size_t size) { return malloc(size); }
|
||||
void deallocate(void* pointer) { free(pointer); }
|
||||
void* allocate(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
void deallocate(void* pointer) {
|
||||
free(pointer);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TAllocator>
|
||||
@ -51,7 +65,6 @@ class BlockJsonBuffer : public JsonBuffer {
|
||||
return total;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void* alloc(size_t bytes) {
|
||||
return canAllocInHead(bytes) ? allocInHead(bytes) : allocInNewBlock(bytes);
|
||||
}
|
||||
@ -92,3 +105,11 @@ class BlockJsonBuffer : public JsonBuffer {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
@ -9,6 +9,48 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
const char *skipSpacesAndComments(const char *ptr);
|
||||
inline const char *skipCStyleComment(const char *ptr) {
|
||||
ptr += 2;
|
||||
for (;;) {
|
||||
if (ptr[0] == '\0') return ptr;
|
||||
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *skipCppStyleComment(const char *ptr) {
|
||||
ptr += 2;
|
||||
for (;;) {
|
||||
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *skipSpacesAndComments(const char *ptr) {
|
||||
for (;;) {
|
||||
switch (ptr[0]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
ptr++;
|
||||
continue;
|
||||
case '/':
|
||||
switch (ptr[1]) {
|
||||
case '*':
|
||||
ptr = skipCStyleComment(ptr);
|
||||
break;
|
||||
case '/':
|
||||
ptr = skipCppStyleComment(ptr);
|
||||
break;
|
||||
default:
|
||||
return ptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class Encoding {
|
||||
public:
|
||||
// Optimized for code size on a 8-bit AVR
|
||||
static char escapeChar(char c) {
|
||||
const char *p = _escapeTable;
|
||||
const char *p = escapeTable(false);
|
||||
while (p[0] && p[1] != c) {
|
||||
p += 2;
|
||||
}
|
||||
@ -25,7 +25,7 @@ class Encoding {
|
||||
|
||||
// Optimized for code size on a 8-bit AVR
|
||||
static char unescapeChar(char c) {
|
||||
const char *p = _escapeTable + 4;
|
||||
const char *p = escapeTable(true);
|
||||
for (;;) {
|
||||
if (p[0] == '\0') return c;
|
||||
if (p[0] == c) return p[1];
|
||||
@ -34,7 +34,9 @@ class Encoding {
|
||||
}
|
||||
|
||||
private:
|
||||
static const char _escapeTable[];
|
||||
static const char *escapeTable(bool excludeIdenticals) {
|
||||
return &"\"\"\\\\b\bf\fn\nr\rt\t"[excludeIdenticals ? 4 : 0];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,13 @@ class IndentedPrint : public Print {
|
||||
isNewLine = true;
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(uint8_t c) {
|
||||
size_t n = 0;
|
||||
if (isNewLine) n += writeTabs();
|
||||
n += sink->write(c);
|
||||
isNewLine = c == '\n';
|
||||
return n;
|
||||
}
|
||||
|
||||
// Adds one level of indentation
|
||||
void indent() {
|
||||
@ -46,7 +52,11 @@ class IndentedPrint : public Print {
|
||||
uint8_t tabSize : 3;
|
||||
bool isNewLine : 1;
|
||||
|
||||
size_t writeTabs();
|
||||
size_t writeTabs() {
|
||||
size_t n = 0;
|
||||
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
|
||||
return n;
|
||||
}
|
||||
|
||||
static const int MAX_LEVEL = 15; // because it's only 4 bits
|
||||
static const int MAX_TAB_SIZE = 7; // because it's only 3 bits
|
||||
|
@ -44,6 +44,19 @@ class JsonParser {
|
||||
inline bool parseObjectTo(JsonVariant *destination);
|
||||
inline bool parseStringTo(JsonVariant *destination);
|
||||
|
||||
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') || c == '-' || c == '.';
|
||||
}
|
||||
|
||||
static inline bool isQuote(char c) {
|
||||
return c == '\'' || c == '\"';
|
||||
}
|
||||
|
||||
JsonBuffer *_buffer;
|
||||
const char *_readPtr;
|
||||
char *_writePtr;
|
||||
|
@ -5,18 +5,12 @@
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/JsonParser.hpp"
|
||||
#pragma once
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||
#include "../../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../../include/ArduinoJson/JsonBuffer.hpp"
|
||||
#include "../../include/ArduinoJson/JsonObject.hpp"
|
||||
#include "Comments.hpp"
|
||||
#include "JsonParser.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
bool JsonParser::skip(char charToSkip) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::skip(char charToSkip) {
|
||||
const char *ptr = skipSpacesAndComments(_readPtr);
|
||||
if (*ptr != charToSkip) return false;
|
||||
ptr++;
|
||||
@ -24,7 +18,8 @@ bool JsonParser::skip(char charToSkip) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo(
|
||||
JsonVariant *destination) {
|
||||
if (_nestingLimit == 0) return false;
|
||||
_nestingLimit--;
|
||||
bool success = parseAnythingToUnsafe(destination);
|
||||
@ -32,7 +27,8 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
||||
return success;
|
||||
}
|
||||
|
||||
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe(
|
||||
JsonVariant *destination) {
|
||||
_readPtr = skipSpacesAndComments(_readPtr);
|
||||
|
||||
switch (*_readPtr) {
|
||||
@ -47,7 +43,8 @@ inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||
}
|
||||
}
|
||||
|
||||
JsonArray &JsonParser::parseArray() {
|
||||
inline ArduinoJson::JsonArray &
|
||||
ArduinoJson::Internals::JsonParser::parseArray() {
|
||||
// Create an empty array
|
||||
JsonArray &array = _buffer->createArray();
|
||||
|
||||
@ -78,7 +75,8 @@ ERROR_NO_MEMORY:
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
bool JsonParser::parseArrayTo(JsonVariant *destination) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::parseArrayTo(
|
||||
JsonVariant *destination) {
|
||||
JsonArray &array = parseArray();
|
||||
if (!array.success()) return false;
|
||||
|
||||
@ -86,7 +84,8 @@ bool JsonParser::parseArrayTo(JsonVariant *destination) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JsonObject &JsonParser::parseObject() {
|
||||
inline ArduinoJson::JsonObject &
|
||||
ArduinoJson::Internals::JsonParser::parseObject() {
|
||||
// Create an empty object
|
||||
JsonObject &object = _buffer->createObject();
|
||||
|
||||
@ -124,7 +123,8 @@ ERROR_NO_MEMORY:
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
bool JsonParser::parseObjectTo(JsonVariant *destination) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::parseObjectTo(
|
||||
JsonVariant *destination) {
|
||||
JsonObject &object = parseObject();
|
||||
if (!object.success()) return false;
|
||||
|
||||
@ -132,18 +132,7 @@ bool JsonParser::parseObjectTo(JsonVariant *destination) {
|
||||
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') || c == '-' || c == '.';
|
||||
}
|
||||
|
||||
static inline bool isQuote(char c) { return c == '\'' || c == '\"'; }
|
||||
|
||||
const char *JsonParser::parseString() {
|
||||
inline const char *ArduinoJson::Internals::JsonParser::parseString() {
|
||||
const char *readPtr = _readPtr;
|
||||
char *writePtr = _writePtr;
|
||||
|
||||
@ -188,7 +177,8 @@ const char *JsonParser::parseString() {
|
||||
return startPtr;
|
||||
}
|
||||
|
||||
bool JsonParser::parseStringTo(JsonVariant *destination) {
|
||||
inline bool ArduinoJson::Internals::JsonParser::parseStringTo(
|
||||
JsonVariant *destination) {
|
||||
bool hasQuotes = isQuote(_readPtr[0]);
|
||||
const char *value = parseString();
|
||||
if (value == NULL) return false;
|
45
include/ArduinoJson/Internals/JsonVariantAs.hpp
Normal file
45
include/ArduinoJson/Internals/JsonVariantAs.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Internals {
|
||||
|
||||
// A metafunction that returns the type of the value returned by
|
||||
// JsonVariant::as<T>()
|
||||
template <typename T>
|
||||
struct JsonVariantAs {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct JsonVariantAs<char*> {
|
||||
typedef const char* type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct JsonVariantAs<JsonArray> {
|
||||
typedef JsonArray& type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct JsonVariantAs<const JsonArray> {
|
||||
typedef const JsonArray& type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct JsonVariantAs<JsonObject> {
|
||||
typedef JsonObject& type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct JsonVariantAs<const JsonObject> {
|
||||
typedef const JsonObject& type;
|
||||
};
|
||||
}
|
||||
}
|
@ -7,12 +7,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Polyfills/isInfinity.hpp"
|
||||
#include "../Polyfills/isNaN.hpp"
|
||||
#include "../Polyfills/attributes.hpp"
|
||||
#include "../Polyfills/math.hpp"
|
||||
#include "../Polyfills/normalize.hpp"
|
||||
#include "../Print.hpp"
|
||||
#include "Encoding.hpp"
|
||||
#include "ForceInline.hpp"
|
||||
#include "JsonFloat.hpp"
|
||||
#include "JsonInteger.hpp"
|
||||
|
||||
@ -33,18 +32,34 @@ class JsonWriter {
|
||||
// Returns the number of bytes sent to the Print implementation.
|
||||
// This is very handy for implementations of printTo() that must return the
|
||||
// number of bytes written.
|
||||
size_t bytesWritten() const { return _length; }
|
||||
size_t bytesWritten() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
void beginArray() { writeRaw('['); }
|
||||
void endArray() { writeRaw(']'); }
|
||||
void beginArray() {
|
||||
writeRaw('[');
|
||||
}
|
||||
void endArray() {
|
||||
writeRaw(']');
|
||||
}
|
||||
|
||||
void beginObject() { writeRaw('{'); }
|
||||
void endObject() { writeRaw('}'); }
|
||||
void beginObject() {
|
||||
writeRaw('{');
|
||||
}
|
||||
void endObject() {
|
||||
writeRaw('}');
|
||||
}
|
||||
|
||||
void writeColon() { writeRaw(':'); }
|
||||
void writeComma() { writeRaw(','); }
|
||||
void writeColon() {
|
||||
writeRaw(':');
|
||||
}
|
||||
void writeComma() {
|
||||
writeRaw(',');
|
||||
}
|
||||
|
||||
void writeBoolean(bool value) { writeRaw(value ? "true" : "false"); }
|
||||
void writeBoolean(bool value) {
|
||||
writeRaw(value ? "true" : "false");
|
||||
}
|
||||
|
||||
void writeString(const char *value) {
|
||||
if (!value) {
|
||||
@ -66,7 +81,7 @@ class JsonWriter {
|
||||
}
|
||||
}
|
||||
|
||||
void writeFloat(JsonFloat value, int digits = 2) {
|
||||
void writeFloat(JsonFloat value, uint8_t digits = 2) {
|
||||
if (Polyfills::isNaN(value)) return writeRaw("NaN");
|
||||
|
||||
if (value < 0.0) {
|
||||
@ -83,11 +98,8 @@ class JsonWriter {
|
||||
powersOf10 = 0;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
JsonFloat rounding = 0.5;
|
||||
for (uint8_t i = 0; i < digits; ++i) rounding /= 10.0;
|
||||
|
||||
value += rounding;
|
||||
// Round up last digit (so that print(1.999, 2) prints as "2.00")
|
||||
value += getRoundingBias(digits);
|
||||
|
||||
// Extract the integer part of the value and print it
|
||||
JsonUInt int_part = static_cast<JsonUInt>(value);
|
||||
@ -101,10 +113,13 @@ class JsonWriter {
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while (digits-- > 0) {
|
||||
// Extract digit
|
||||
remainder *= 10.0;
|
||||
JsonUInt toPrint = JsonUInt(remainder);
|
||||
writeInteger(JsonUInt(remainder));
|
||||
remainder -= static_cast<JsonFloat>(toPrint);
|
||||
char currentDigit = char(remainder);
|
||||
remainder -= static_cast<JsonFloat>(currentDigit);
|
||||
|
||||
// Print
|
||||
writeRaw(char('0' + currentDigit));
|
||||
}
|
||||
|
||||
if (powersOf10 < 0) {
|
||||
@ -120,20 +135,23 @@ class JsonWriter {
|
||||
|
||||
void writeInteger(JsonUInt value) {
|
||||
char buffer[22];
|
||||
char *ptr = buffer + sizeof(buffer) - 1;
|
||||
|
||||
uint8_t i = 0;
|
||||
*ptr = 0;
|
||||
do {
|
||||
buffer[i++] = static_cast<char>(value % 10 + '0');
|
||||
*--ptr = static_cast<char>(value % 10 + '0');
|
||||
value /= 10;
|
||||
} while (value);
|
||||
|
||||
while (i > 0) {
|
||||
writeRaw(buffer[--i]);
|
||||
}
|
||||
writeRaw(ptr);
|
||||
}
|
||||
|
||||
void writeRaw(const char *s) { _length += _sink.print(s); }
|
||||
void writeRaw(char c) { _length += _sink.write(c); }
|
||||
void writeRaw(const char *s) {
|
||||
_length += _sink.print(s);
|
||||
}
|
||||
void writeRaw(char c) {
|
||||
_length += _sink.write(c);
|
||||
}
|
||||
|
||||
protected:
|
||||
Print &_sink;
|
||||
@ -141,6 +159,26 @@ class JsonWriter {
|
||||
|
||||
private:
|
||||
JsonWriter &operator=(const JsonWriter &); // cannot be assigned
|
||||
|
||||
static JsonFloat getLastDigit(uint8_t digits) {
|
||||
// Designed as a compromise between code size and speed
|
||||
switch (digits) {
|
||||
case 0:
|
||||
return 1e-0;
|
||||
case 1:
|
||||
return 1e-1;
|
||||
case 2:
|
||||
return 1e-2;
|
||||
case 3:
|
||||
return 1e-3;
|
||||
default:
|
||||
return getLastDigit(uint8_t(digits - 4)) * 1e-4;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE static JsonFloat getRoundingBias(uint8_t digits) {
|
||||
return 0.5 * getLastDigit(digits);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -36,21 +36,56 @@ class List {
|
||||
// Would return false in the following situation:
|
||||
// - the memory allocation failed (StaticJsonBuffer was too small)
|
||||
// - the JSON parsing failed
|
||||
bool success() const { return _buffer != NULL; }
|
||||
bool success() const {
|
||||
return _buffer != NULL;
|
||||
}
|
||||
|
||||
// Returns the numbers of elements in the list.
|
||||
// For a JsonObject, it would return the number of key-value pairs
|
||||
size_t size() const;
|
||||
size_t size() const {
|
||||
size_t nodeCount = 0;
|
||||
for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
iterator begin() { return iterator(_firstNode); }
|
||||
iterator end() { return iterator(NULL); }
|
||||
iterator begin() {
|
||||
return iterator(_firstNode);
|
||||
}
|
||||
iterator end() {
|
||||
return iterator(NULL);
|
||||
}
|
||||
|
||||
const_iterator begin() const { return const_iterator(_firstNode); }
|
||||
const_iterator end() const { return const_iterator(NULL); }
|
||||
const_iterator begin() const {
|
||||
return const_iterator(_firstNode);
|
||||
}
|
||||
const_iterator end() const {
|
||||
return const_iterator(NULL);
|
||||
}
|
||||
|
||||
protected:
|
||||
node_type *addNewNode();
|
||||
void removeNode(node_type *nodeToRemove);
|
||||
node_type *addNewNode() {
|
||||
node_type *newNode = new (_buffer) node_type();
|
||||
|
||||
if (_firstNode) {
|
||||
node_type *lastNode = _firstNode;
|
||||
while (lastNode->next) lastNode = lastNode->next;
|
||||
lastNode->next = newNode;
|
||||
} else {
|
||||
_firstNode = newNode;
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
void removeNode(node_type *nodeToRemove) {
|
||||
if (!nodeToRemove) return;
|
||||
if (nodeToRemove == _firstNode) {
|
||||
_firstNode = nodeToRemove->next;
|
||||
} else {
|
||||
for (node_type *node = _firstNode; node; node = node->next)
|
||||
if (node->next == nodeToRemove) node->next = nodeToRemove->next;
|
||||
}
|
||||
}
|
||||
|
||||
JsonBuffer *_buffer;
|
||||
node_type *_firstNode;
|
||||
|
@ -20,24 +20,89 @@ class Prettyfier : public Print {
|
||||
_inString = false;
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(uint8_t c) {
|
||||
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
|
||||
_previousChar = c;
|
||||
return n;
|
||||
}
|
||||
|
||||
private:
|
||||
Prettyfier& operator=(const Prettyfier&); // cannot be assigned
|
||||
|
||||
bool inEmptyBlock() { return _previousChar == '{' || _previousChar == '['; }
|
||||
bool inEmptyBlock() {
|
||||
return _previousChar == '{' || _previousChar == '[';
|
||||
}
|
||||
|
||||
size_t handleStringChar(uint8_t);
|
||||
size_t handleMarkupChar(uint8_t);
|
||||
size_t handleStringChar(uint8_t c) {
|
||||
bool isQuote = c == '"' && _previousChar != '\\';
|
||||
|
||||
size_t handleBlockClose(uint8_t);
|
||||
size_t handleBlockOpen(uint8_t);
|
||||
size_t handleColon();
|
||||
size_t handleComma();
|
||||
size_t handleQuoteOpen();
|
||||
size_t handleNormalChar(uint8_t);
|
||||
size_t indentIfNeeded();
|
||||
size_t unindentIfNeeded();
|
||||
if (isQuote) _inString = false;
|
||||
|
||||
return _sink.write(c);
|
||||
}
|
||||
|
||||
size_t handleMarkupChar(uint8_t c) {
|
||||
switch (c) {
|
||||
case '{':
|
||||
case '[':
|
||||
return writeBlockOpen(c);
|
||||
|
||||
case '}':
|
||||
case ']':
|
||||
return writeBlockClose(c);
|
||||
|
||||
case ':':
|
||||
return writeColon();
|
||||
|
||||
case ',':
|
||||
return writeComma();
|
||||
|
||||
case '"':
|
||||
return writeQuoteOpen();
|
||||
|
||||
default:
|
||||
return writeNormalChar(c);
|
||||
}
|
||||
}
|
||||
|
||||
size_t writeBlockClose(uint8_t c) {
|
||||
return unindentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
size_t writeBlockOpen(uint8_t c) {
|
||||
return indentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
size_t writeColon() {
|
||||
return _sink.write(':') + _sink.write(' ');
|
||||
}
|
||||
|
||||
size_t writeComma() {
|
||||
return _sink.write(',') + _sink.println();
|
||||
}
|
||||
|
||||
size_t writeQuoteOpen() {
|
||||
_inString = true;
|
||||
return indentIfNeeded() + _sink.write('"');
|
||||
}
|
||||
|
||||
size_t writeNormalChar(uint8_t c) {
|
||||
return indentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
size_t indentIfNeeded() {
|
||||
if (!inEmptyBlock()) return 0;
|
||||
|
||||
_sink.indent();
|
||||
return _sink.println();
|
||||
}
|
||||
|
||||
size_t unindentIfNeeded() {
|
||||
if (inEmptyBlock()) return 0;
|
||||
|
||||
_sink.unindent();
|
||||
return _sink.println();
|
||||
}
|
||||
|
||||
uint8_t _previousChar;
|
||||
IndentedPrint& _sink;
|
||||
|
@ -20,7 +20,13 @@ class StaticStringBuilder : public Print {
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t c);
|
||||
virtual size_t write(uint8_t c) {
|
||||
if (length >= capacity) return 0;
|
||||
|
||||
buffer[length++] = c;
|
||||
buffer[length] = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
char *buffer;
|
||||
|
@ -56,10 +56,12 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
: Internals::List<JsonVariant>(buffer) {}
|
||||
|
||||
// Gets the value at the specified index
|
||||
FORCE_INLINE JsonVariant operator[](size_t index) const;
|
||||
JsonVariant operator[](size_t index) const {
|
||||
return get(index);
|
||||
}
|
||||
|
||||
// Gets or sets the value at specified index
|
||||
FORCE_INLINE JsonArraySubscript operator[](size_t index);
|
||||
JsonArraySubscript operator[](size_t index);
|
||||
|
||||
// Adds the specified value at the end of the array.
|
||||
//
|
||||
@ -72,7 +74,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
// bool add(double value);
|
||||
// bool add(const char*);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool add(
|
||||
bool add(
|
||||
T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
|
||||
@ -83,18 +85,16 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
// bool add(JsonArray&);
|
||||
// bool add(JsonObject&);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool add(
|
||||
const T &value,
|
||||
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
|
||||
bool add(const T &value,
|
||||
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
|
||||
return addNode<T &>(const_cast<T &>(value));
|
||||
}
|
||||
// bool add(float value, uint8_t decimals);
|
||||
// bool add(double value, uint8_t decimals);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool add(
|
||||
T value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
|
||||
* = 0) {
|
||||
bool add(T value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
|
||||
return addNode<JsonVariant>(JsonVariant(value, decimals));
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
// bool set(size_t index, int value);
|
||||
// bool set(size_t index, short value);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
bool set(
|
||||
size_t index, T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type * = 0) {
|
||||
@ -116,31 +116,38 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
// bool set(size_t index, JsonArray&);
|
||||
// bool set(size_t index, JsonObject&);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
size_t index, const T &value,
|
||||
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
|
||||
bool set(size_t index, const T &value,
|
||||
typename TypeTraits::EnableIf<CanSet<T &>::value>::type * = 0) {
|
||||
return setNodeAt<T &>(index, const_cast<T &>(value));
|
||||
}
|
||||
// bool set(size_t index, float value, uint8_t decimals = 2);
|
||||
// bool set(size_t index, double value, uint8_t decimals = 2);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
size_t index, T value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
|
||||
* = 0) {
|
||||
bool set(size_t index, T value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
|
||||
return setNodeAt<const JsonVariant &>(index, JsonVariant(value, decimals));
|
||||
}
|
||||
|
||||
// Gets the value at the specified index.
|
||||
FORCE_INLINE JsonVariant get(size_t index) const;
|
||||
JsonVariant get(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content : JsonVariant();
|
||||
}
|
||||
|
||||
// Gets the value at the specified index.
|
||||
template <typename T>
|
||||
FORCE_INLINE T get(size_t index) const;
|
||||
typename Internals::JsonVariantAs<T>::type get(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content.as<T>() : JsonVariant::defaultValue<T>();
|
||||
}
|
||||
|
||||
// Check the type of the value at specified index.
|
||||
template <typename T>
|
||||
FORCE_INLINE bool is(size_t index) const;
|
||||
bool is(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content.is<T>() : false;
|
||||
}
|
||||
|
||||
// Creates a JsonArray and adds a reference at the end of the array.
|
||||
// It's a shortcut for JsonBuffer::createArray() and JsonArray::add()
|
||||
@ -151,15 +158,34 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
JsonObject &createNestedObject();
|
||||
|
||||
// Removes element at specified index.
|
||||
void removeAt(size_t index);
|
||||
void removeAt(size_t index) {
|
||||
removeNode(getNodeAt(index));
|
||||
}
|
||||
|
||||
// Returns a reference an invalid JsonArray.
|
||||
// This object is meant to replace a NULL pointer.
|
||||
// This is used when memory allocation or JSON parsing fail.
|
||||
static JsonArray &invalid() { return _invalid; }
|
||||
static JsonArray &invalid() {
|
||||
static JsonArray instance(NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Serialize the array to the specified JsonWriter.
|
||||
void writeTo(Internals::JsonWriter &writer) const;
|
||||
void writeTo(Internals::JsonWriter &writer) const {
|
||||
writer.beginArray();
|
||||
|
||||
const node_type *child = _firstNode;
|
||||
while (child) {
|
||||
child->content.writeTo(writer);
|
||||
|
||||
child = child->next;
|
||||
if (!child) break;
|
||||
|
||||
writer.writeComma();
|
||||
}
|
||||
|
||||
writer.endArray();
|
||||
}
|
||||
|
||||
// Imports a 1D array
|
||||
template <typename T, size_t N>
|
||||
@ -215,20 +241,28 @@ class JsonArray : public Internals::JsonPrintable<JsonArray>,
|
||||
}
|
||||
|
||||
private:
|
||||
node_type *getNodeAt(size_t index) const;
|
||||
node_type *getNodeAt(size_t index) const {
|
||||
node_type *node = _firstNode;
|
||||
while (node && index--) node = node->next;
|
||||
return node;
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
bool setNodeAt(size_t index, TValue value);
|
||||
bool setNodeAt(size_t index, TValue value) {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node != NULL && setNodeValue<TValue>(node, value);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
bool addNode(TValue);
|
||||
bool addNode(TValue value) {
|
||||
node_type *node = addNewNode();
|
||||
return node != NULL && setNodeValue<TValue>(node, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE bool setNodeValue(node_type *, T value);
|
||||
|
||||
// The instance returned by JsonArray::invalid()
|
||||
static JsonArray _invalid;
|
||||
bool setNodeValue(node_type *node, T value) {
|
||||
node->content = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include "JsonArray.ipp"
|
||||
|
@ -13,32 +13,6 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
inline JsonArraySubscript JsonArray::operator[](size_t index) {
|
||||
return JsonArraySubscript(*this, index);
|
||||
}
|
||||
|
||||
inline JsonVariant JsonArray::operator[](size_t index) const {
|
||||
return get(index);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
inline bool JsonArray::addNode(TValue value) {
|
||||
node_type *node = addNewNode();
|
||||
return node != NULL && setNodeValue<TValue>(node, value);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
inline bool JsonArray::setNodeAt(size_t index, TValue value) {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node != NULL && setNodeValue<TValue>(node, value);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
inline bool JsonArray::setNodeValue(node_type *node, TValue value) {
|
||||
node->content = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonArray::setNodeValue(node_type *node, String &value) {
|
||||
const char *copy = _buffer->strdup(value);
|
||||
@ -47,36 +21,23 @@ inline bool JsonArray::setNodeValue(node_type *node, String &value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline JsonVariant JsonArray::get(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content : JsonVariant();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonArray::get(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content.as<T>() : JsonVariant::invalid<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool JsonArray::is(size_t index) const {
|
||||
node_type *node = getNodeAt(index);
|
||||
return node ? node->content.is<T>() : false;
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
|
||||
int index) const {
|
||||
return asArray()[index];
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonArray &JsonVariant::invalid<JsonArray &>() {
|
||||
inline JsonArray &JsonVariant::defaultValue<JsonArray>() {
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonArray const &JsonVariant::invalid<JsonArray const &>() {
|
||||
inline JsonArray &JsonVariant::defaultValue<JsonArray &>() {
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonArray &JsonVariant::defaultValue<const JsonArray>() {
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const JsonArray &JsonVariant::defaultValue<const JsonArray &>() {
|
||||
return JsonArray::invalid();
|
||||
}
|
||||
|
||||
|
@ -42,12 +42,16 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool success() const { return _index < _array.size(); }
|
||||
FORCE_INLINE bool success() const {
|
||||
return _index < _array.size();
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariant() const { return _array.get(_index); }
|
||||
FORCE_INLINE operator JsonVariant() const {
|
||||
return _array.get(_index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE T as() const {
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<T>::type as() const {
|
||||
return _array.get<T>(_index);
|
||||
}
|
||||
|
||||
@ -77,6 +81,16 @@ inline std::ostream& operator<<(std::ostream& os,
|
||||
}
|
||||
#endif
|
||||
|
||||
inline JsonArraySubscript JsonArray::operator[](size_t index) {
|
||||
return JsonArraySubscript(*this, index);
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonArraySubscript JsonVariantBase<TImplem>::operator[](
|
||||
int index) const {
|
||||
return asArray()[index];
|
||||
}
|
||||
|
||||
} // namespace ArduinoJson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -11,12 +11,16 @@
|
||||
#include <stdint.h> // for uint8_t
|
||||
#include <string.h>
|
||||
|
||||
#include "String.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "String.hpp"
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#endif
|
||||
|
||||
@ -149,3 +153,11 @@ class JsonBuffer {
|
||||
static const uint8_t DEFAULT_LIMIT = 10;
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
46
include/ArduinoJson/JsonBuffer.ipp
Normal file
46
include/ArduinoJson/JsonBuffer.ipp
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Internals/JsonParser.hpp"
|
||||
|
||||
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
|
||||
JsonArray *ptr = new (this) JsonArray(this);
|
||||
return ptr ? *ptr : JsonArray::invalid();
|
||||
}
|
||||
|
||||
inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::createObject() {
|
||||
JsonObject *ptr = new (this) JsonObject(this);
|
||||
return ptr ? *ptr : JsonObject::invalid();
|
||||
}
|
||||
|
||||
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::parseArray(
|
||||
char *json, uint8_t nestingLimit) {
|
||||
Internals::JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseArray();
|
||||
}
|
||||
|
||||
inline ArduinoJson::JsonObject &ArduinoJson::JsonBuffer::parseObject(
|
||||
char *json, uint8_t nestingLimit) {
|
||||
Internals::JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseObject();
|
||||
}
|
||||
|
||||
inline ArduinoJson::JsonVariant ArduinoJson::JsonBuffer::parse(
|
||||
char *json, uint8_t nestingLimit) {
|
||||
Internals::JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseVariant();
|
||||
}
|
||||
|
||||
inline char *ArduinoJson::JsonBuffer::strdup(const char *source,
|
||||
size_t length) {
|
||||
size_t size = length + 1;
|
||||
char *dest = static_cast<char *>(alloc(size));
|
||||
if (dest != NULL) memcpy(dest, source, size);
|
||||
return dest;
|
||||
}
|
@ -52,15 +52,16 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
||||
// Create an empty JsonArray attached to the specified JsonBuffer.
|
||||
// You should not use this constructor directly.
|
||||
// Instead, use JsonBuffer::createObject() or JsonBuffer.parseObject().
|
||||
FORCE_INLINE explicit JsonObject(JsonBuffer* buffer)
|
||||
: Internals::List<JsonPair>(buffer) {}
|
||||
explicit JsonObject(JsonBuffer* buffer) : Internals::List<JsonPair>(buffer) {}
|
||||
|
||||
// Gets or sets the value associated with the specified key.
|
||||
FORCE_INLINE JsonObjectSubscript<const char*> operator[](const char* key);
|
||||
FORCE_INLINE JsonObjectSubscript<const String&> operator[](const String& key);
|
||||
JsonObjectSubscript<const char*> operator[](const char* key);
|
||||
JsonObjectSubscript<const String&> operator[](const String& key);
|
||||
|
||||
// Gets the value associated with the specified key.
|
||||
FORCE_INLINE JsonVariant operator[](JsonObjectKey key) const;
|
||||
JsonVariant operator[](JsonObjectKey key) const {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
// Sets the specified key with the specified value.
|
||||
// bool set(TKey key, bool value);
|
||||
@ -73,7 +74,7 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
||||
// bool set(TKey key, const char* value);
|
||||
// bool set(TKey key, RawJson value);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
bool set(
|
||||
JsonObjectKey key, T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
CanSet<T>::value && !TypeTraits::IsReference<T>::value>::type* = 0) {
|
||||
@ -84,71 +85,117 @@ class JsonObject : public Internals::JsonPrintable<JsonObject>,
|
||||
// bool set(Key, JsonObject&);
|
||||
// bool set(Key, JsonVariant&);
|
||||
template <typename T>
|
||||
FORCE_INLINE bool set(
|
||||
JsonObjectKey key, const T& value,
|
||||
typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) {
|
||||
bool set(JsonObjectKey key, const T& value,
|
||||
typename TypeTraits::EnableIf<CanSet<T&>::value>::type* = 0) {
|
||||
return setNodeAt<T&>(key, const_cast<T&>(value));
|
||||
}
|
||||
// bool set(Key, float value, uint8_t decimals);
|
||||
// bool set(Key, double value, uint8_t decimals);
|
||||
template <typename TValue>
|
||||
FORCE_INLINE bool set(
|
||||
JsonObjectKey key, TValue value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) {
|
||||
bool set(JsonObjectKey key, TValue value, uint8_t decimals,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsFloatingPoint<TValue>::value>::type* = 0) {
|
||||
return setNodeAt<const JsonVariant&>(key, JsonVariant(value, decimals));
|
||||
}
|
||||
|
||||
// Gets the value associated with the specified key.
|
||||
FORCE_INLINE JsonVariant get(JsonObjectKey) const;
|
||||
JsonVariant get(JsonObjectKey key) const {
|
||||
node_type* node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value : JsonVariant();
|
||||
}
|
||||
|
||||
// Gets the value associated with the specified key.
|
||||
template <typename T>
|
||||
FORCE_INLINE T get(JsonObjectKey) const;
|
||||
typename Internals::JsonVariantAs<T>::type get(JsonObjectKey key) const {
|
||||
node_type* node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value.as<T>() : JsonVariant::defaultValue<T>();
|
||||
}
|
||||
|
||||
// Checks the type of the value associated with the specified key.
|
||||
template <typename T>
|
||||
FORCE_INLINE bool is(JsonObjectKey) const;
|
||||
bool is(JsonObjectKey key) const {
|
||||
node_type* node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value.is<T>() : false;
|
||||
}
|
||||
|
||||
// Creates and adds a JsonArray.
|
||||
// This is a shortcut for JsonBuffer::createArray() and JsonObject::add().
|
||||
FORCE_INLINE JsonArray& createNestedArray(JsonObjectKey key);
|
||||
JsonArray& createNestedArray(JsonObjectKey key);
|
||||
|
||||
// Creates and adds a JsonObject.
|
||||
// This is a shortcut for JsonBuffer::createObject() and JsonObject::add().
|
||||
FORCE_INLINE JsonObject& createNestedObject(JsonObjectKey key);
|
||||
JsonObject& createNestedObject(JsonObjectKey key);
|
||||
|
||||
// Tells weither the specified key is present and associated with a value.
|
||||
FORCE_INLINE bool containsKey(JsonObjectKey key) const;
|
||||
bool containsKey(JsonObjectKey key) const {
|
||||
return getNodeAt(key.c_str()) != NULL;
|
||||
}
|
||||
|
||||
// Removes the specified key and the associated value.
|
||||
void remove(JsonObjectKey key);
|
||||
void remove(JsonObjectKey key) {
|
||||
removeNode(getNodeAt(key.c_str()));
|
||||
}
|
||||
|
||||
// Returns a reference an invalid JsonObject.
|
||||
// This object is meant to replace a NULL pointer.
|
||||
// This is used when memory allocation or JSON parsing fail.
|
||||
static JsonObject& invalid() { return _invalid; }
|
||||
static JsonObject& invalid() {
|
||||
static JsonObject instance(NULL);
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Serialize the object to the specified JsonWriter
|
||||
void writeTo(Internals::JsonWriter& writer) const;
|
||||
void writeTo(Internals::JsonWriter& writer) const {
|
||||
writer.beginObject();
|
||||
|
||||
const node_type* node = _firstNode;
|
||||
while (node) {
|
||||
writer.writeString(node->content.key);
|
||||
writer.writeColon();
|
||||
node->content.value.writeTo(writer);
|
||||
|
||||
node = node->next;
|
||||
if (!node) break;
|
||||
|
||||
writer.writeComma();
|
||||
}
|
||||
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns the list node that matches the specified key.
|
||||
node_type* getNodeAt(const char* key) const;
|
||||
|
||||
node_type* getOrCreateNodeAt(const char* key);
|
||||
node_type* getNodeAt(const char* key) const {
|
||||
for (node_type* node = _firstNode; node; node = node->next) {
|
||||
if (!strcmp(node->content.key, key)) return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE bool setNodeAt(JsonObjectKey key, T value);
|
||||
bool setNodeAt(JsonObjectKey key, T value) {
|
||||
node_type* node = getNodeAt(key.c_str());
|
||||
if (!node) {
|
||||
node = addNewNode();
|
||||
if (!node || !setNodeKey(node, key)) return false;
|
||||
}
|
||||
return setNodeValue<T>(node, value);
|
||||
}
|
||||
|
||||
FORCE_INLINE bool setNodeKey(node_type*, JsonObjectKey key);
|
||||
bool setNodeKey(node_type* node, JsonObjectKey key) {
|
||||
if (key.needs_copy()) {
|
||||
node->content.key = _buffer->strdup(key.c_str());
|
||||
if (node->content.key == NULL) return false;
|
||||
} else {
|
||||
node->content.key = key.c_str();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE bool setNodeValue(node_type*, T value);
|
||||
|
||||
// The instance returned by JsonObject::invalid()
|
||||
static JsonObject _invalid;
|
||||
bool setNodeValue(node_type* node, T value) {
|
||||
node->content.value = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include "JsonObject.ipp"
|
||||
|
@ -13,72 +13,6 @@
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
inline JsonVariant JsonObject::get(JsonObjectKey key) const {
|
||||
node_type *node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value : JsonVariant();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonObject::get(JsonObjectKey key) const {
|
||||
node_type *node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value.as<T>() : JsonVariant::invalid<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool JsonObject::is(JsonObjectKey key) const {
|
||||
node_type *node = getNodeAt(key.c_str());
|
||||
return node ? node->content.value.is<T>() : false;
|
||||
}
|
||||
|
||||
inline JsonObjectSubscript<const char *> JsonObject::operator[](
|
||||
const char *key) {
|
||||
return JsonObjectSubscript<const char *>(*this, key);
|
||||
}
|
||||
|
||||
inline JsonObjectSubscript<const String &> JsonObject::operator[](
|
||||
const String &key) {
|
||||
return JsonObjectSubscript<const String &>(*this, key);
|
||||
}
|
||||
|
||||
inline JsonVariant JsonObject::operator[](JsonObjectKey key) const {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
inline bool JsonObject::containsKey(JsonObjectKey key) const {
|
||||
return getNodeAt(key.c_str()) != NULL;
|
||||
}
|
||||
|
||||
inline void JsonObject::remove(JsonObjectKey key) {
|
||||
removeNode(getNodeAt(key.c_str()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool JsonObject::setNodeAt(JsonObjectKey key, T value) {
|
||||
node_type *node = getNodeAt(key.c_str());
|
||||
if (!node) {
|
||||
node = addNewNode();
|
||||
if (!node || !setNodeKey(node, key))
|
||||
return false;
|
||||
}
|
||||
return setNodeValue<T>(node, value);
|
||||
}
|
||||
|
||||
inline bool JsonObject::setNodeKey(node_type *node, JsonObjectKey key) {
|
||||
if (key.needs_copy()) {
|
||||
node->content.key = _buffer->strdup(key.c_str());
|
||||
if (node->content.key == NULL) return false;
|
||||
} else {
|
||||
node->content.key = key.c_str();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
inline bool JsonObject::setNodeValue(node_type *node, TValue value) {
|
||||
node->content.value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool JsonObject::setNodeValue(node_type *node, String &value) {
|
||||
node->content.value = _buffer->strdup(value);
|
||||
@ -91,25 +25,23 @@ inline bool JsonObject::setNodeValue(node_type *node, const String &value) {
|
||||
return node->content.value;
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonObjectSubscript<const char *> JsonVariantBase<TImplem>::
|
||||
operator[](const char *key) const {
|
||||
return asObject()[key];
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonObjectSubscript<const String &> JsonVariantBase<TImplem>::
|
||||
operator[](const String &key) const {
|
||||
return asObject()[key];
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject const &JsonVariant::invalid<JsonObject const &>() {
|
||||
inline const JsonObject &JsonVariant::defaultValue<const JsonObject &>() {
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject &JsonVariant::invalid<JsonObject &>() {
|
||||
inline const JsonObject &JsonVariant::defaultValue<const JsonObject>() {
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject &JsonVariant::defaultValue<JsonObject &>() {
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline JsonObject &JsonVariant::defaultValue<JsonObject>() {
|
||||
return JsonObject::invalid();
|
||||
}
|
||||
|
||||
|
@ -45,12 +45,16 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool success() const { return _object.containsKey(_key); }
|
||||
FORCE_INLINE bool success() const {
|
||||
return _object.containsKey(_key);
|
||||
}
|
||||
|
||||
FORCE_INLINE operator JsonVariant() const { return _object.get(_key); }
|
||||
FORCE_INLINE operator JsonVariant() const {
|
||||
return _object.get(_key);
|
||||
}
|
||||
|
||||
template <typename TValue>
|
||||
FORCE_INLINE TValue as() const {
|
||||
FORCE_INLINE typename Internals::JsonVariantAs<TValue>::type as() const {
|
||||
return _object.get<TValue>(_key);
|
||||
}
|
||||
|
||||
@ -69,7 +73,9 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript<TKey> > {
|
||||
return _object.set(_key, value, decimals);
|
||||
}
|
||||
|
||||
FORCE_INLINE JsonVariant get() { return _object.get(_key); }
|
||||
FORCE_INLINE JsonVariant get() {
|
||||
return _object.get(_key);
|
||||
}
|
||||
|
||||
void writeTo(Internals::JsonWriter& writer) const {
|
||||
_object.get(_key).writeTo(writer);
|
||||
@ -92,6 +98,28 @@ inline std::ostream& operator<<(
|
||||
}
|
||||
#endif
|
||||
|
||||
inline JsonObjectSubscript<const char*> JsonObject::operator[](
|
||||
const char* key) {
|
||||
return JsonObjectSubscript<const char*>(*this, key);
|
||||
}
|
||||
|
||||
inline JsonObjectSubscript<const String&> JsonObject::operator[](
|
||||
const String& key) {
|
||||
return JsonObjectSubscript<const String&>(*this, key);
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonObjectSubscript<const char*> JsonVariantBase<TImplem>::
|
||||
operator[](const char* key) const {
|
||||
return asObject()[key];
|
||||
}
|
||||
|
||||
template <typename TImplem>
|
||||
inline const JsonObjectSubscript<const String&> JsonVariantBase<TImplem>::
|
||||
operator[](const String& key) const {
|
||||
return asObject()[key];
|
||||
}
|
||||
|
||||
} // namespace ArduinoJson
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -41,11 +41,15 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
struct IsConstructibleFrom;
|
||||
|
||||
// Creates an uninitialized JsonVariant
|
||||
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
|
||||
JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
|
||||
|
||||
// Create a JsonVariant containing a boolean value.
|
||||
// It will be serialized as "true" or "false" in JSON.
|
||||
FORCE_INLINE JsonVariant(bool value);
|
||||
JsonVariant(bool value) {
|
||||
using namespace Internals;
|
||||
_type = JSON_BOOLEAN;
|
||||
_content.asInteger = static_cast<JsonInteger>(value);
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a floating point value.
|
||||
// The second argument specifies the number of decimal digits to write in
|
||||
@ -53,10 +57,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
// JsonVariant(double value, uint8_t decimals);
|
||||
// JsonVariant(float value, uint8_t decimals);
|
||||
template <typename T>
|
||||
FORCE_INLINE JsonVariant(
|
||||
T value, uint8_t decimals = 2,
|
||||
typename TypeTraits::EnableIf<TypeTraits::IsFloatingPoint<T>::value>::type
|
||||
* = 0) {
|
||||
JsonVariant(T value, uint8_t decimals = 2,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsFloatingPoint<T>::value>::type * = 0) {
|
||||
using namespace Internals;
|
||||
_type = static_cast<JsonVariantType>(JSON_FLOAT_0_DECIMALS + decimals);
|
||||
_content.asFloat = static_cast<JsonFloat>(value);
|
||||
@ -67,9 +70,9 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
// JsonVariant(signed int)
|
||||
// JsonVariant(signed long)
|
||||
template <typename T>
|
||||
FORCE_INLINE JsonVariant(
|
||||
T value, typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSignedIntegral<T>::value>::type * = 0) {
|
||||
JsonVariant(T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSignedIntegral<T>::value>::type * = 0) {
|
||||
using namespace Internals;
|
||||
if (value >= 0) {
|
||||
_type = JSON_POSITIVE_INTEGER;
|
||||
@ -83,25 +86,37 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
// JsonVariant(unsigned int)
|
||||
// JsonVariant(unsigned long)
|
||||
template <typename T>
|
||||
FORCE_INLINE JsonVariant(
|
||||
T value, typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsUnsignedIntegral<T>::value>::type * = 0) {
|
||||
JsonVariant(T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsUnsignedIntegral<T>::value>::type * = 0) {
|
||||
using namespace Internals;
|
||||
_type = JSON_POSITIVE_INTEGER;
|
||||
_content.asInteger = static_cast<JsonUInt>(value);
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a string.
|
||||
FORCE_INLINE JsonVariant(const char *value);
|
||||
JsonVariant(const char *value) {
|
||||
_type = Internals::JSON_STRING;
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing an unparsed string
|
||||
FORCE_INLINE JsonVariant(RawJson value);
|
||||
JsonVariant(RawJson value) {
|
||||
_type = Internals::JSON_UNPARSED;
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a reference to an array.
|
||||
FORCE_INLINE JsonVariant(JsonArray &array);
|
||||
JsonVariant(JsonArray &array) {
|
||||
_type = Internals::JSON_ARRAY;
|
||||
_content.asArray = &array;
|
||||
}
|
||||
|
||||
// Create a JsonVariant containing a reference to an object.
|
||||
FORCE_INLINE JsonVariant(JsonObject &object);
|
||||
JsonVariant(JsonObject &object) {
|
||||
_type = Internals::JSON_OBJECT;
|
||||
_content.asObject = &object;
|
||||
}
|
||||
|
||||
// Get the variant as the specified type.
|
||||
//
|
||||
@ -162,28 +177,43 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
//
|
||||
// JsonArray& as<JsonArray> const;
|
||||
// JsonArray& as<JsonArray&> const;
|
||||
// JsonArray& as<const JsonArray&> const;
|
||||
template <typename T>
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<
|
||||
typename TypeTraits::RemoveConst<
|
||||
typename TypeTraits::RemoveReference<T>::type>::type,
|
||||
JsonArray>::value,
|
||||
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
|
||||
JsonArray>::value,
|
||||
JsonArray &>::type
|
||||
as() const {
|
||||
return asArray();
|
||||
}
|
||||
//
|
||||
// const JsonArray& as<const JsonArray&> const;
|
||||
template <typename T>
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
|
||||
const JsonArray>::value,
|
||||
const JsonArray &>::type
|
||||
as() const {
|
||||
return asArray();
|
||||
}
|
||||
//
|
||||
// JsonObject& as<JsonObject> const;
|
||||
// JsonObject& as<JsonObject&> const;
|
||||
template <typename T>
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
|
||||
JsonObject>::value,
|
||||
JsonObject &>::type
|
||||
as() const {
|
||||
return asObject();
|
||||
}
|
||||
//
|
||||
// JsonObject& as<const JsonObject> const;
|
||||
// JsonObject& as<const JsonObject&> const;
|
||||
template <typename T>
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<
|
||||
typename TypeTraits::RemoveConst<
|
||||
typename TypeTraits::RemoveReference<T>::type>::type,
|
||||
JsonObject>::value,
|
||||
JsonObject &>::type
|
||||
TypeTraits::IsSame<typename TypeTraits::RemoveReference<T>::type,
|
||||
const JsonObject>::value,
|
||||
const JsonObject &>::type
|
||||
as() const {
|
||||
return asObject();
|
||||
}
|
||||
@ -256,23 +286,34 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
return isObject();
|
||||
}
|
||||
|
||||
// Returns true if the variant has a value
|
||||
bool success() const {
|
||||
return _type != Internals::JSON_UNDEFINED;
|
||||
}
|
||||
|
||||
// Serialize the variant to a JsonWriter
|
||||
void writeTo(Internals::JsonWriter &writer) const;
|
||||
|
||||
// TODO: rename
|
||||
// Value returned if the variant has an incompatible type
|
||||
template <typename T>
|
||||
static T invalid();
|
||||
static typename Internals::JsonVariantAs<T>::type defaultValue() {
|
||||
return T();
|
||||
}
|
||||
|
||||
// DEPRECATED: use as<char*>() instead
|
||||
const char *asString() const;
|
||||
|
||||
// DEPRECATED: use as<JsonArray>() instead
|
||||
JsonArray &asArray() const;
|
||||
|
||||
// DEPRECATED: use as<JsonObject>() instead
|
||||
JsonObject &asObject() const;
|
||||
|
||||
private:
|
||||
// It's not allowed to store a char
|
||||
template <typename T>
|
||||
FORCE_INLINE JsonVariant(T value,
|
||||
typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<T, char>::value>::type * = 0);
|
||||
JsonVariant(T value, typename TypeTraits::EnableIf<
|
||||
TypeTraits::IsSame<T, char>::value>::type * = 0);
|
||||
|
||||
String toString() const;
|
||||
Internals::JsonFloat asFloat() const;
|
||||
@ -281,9 +322,17 @@ class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||
bool isBoolean() const;
|
||||
bool isFloat() const;
|
||||
bool isInteger() const;
|
||||
bool isArray() const { return _type == Internals::JSON_ARRAY; }
|
||||
bool isObject() const { return _type == Internals::JSON_OBJECT; }
|
||||
bool isString() const { return _type == Internals::JSON_STRING; }
|
||||
bool isArray() const {
|
||||
return _type == Internals::JSON_ARRAY;
|
||||
}
|
||||
bool isObject() const {
|
||||
return _type == Internals::JSON_OBJECT;
|
||||
}
|
||||
bool isString() const {
|
||||
return _type == Internals::JSON_STRING ||
|
||||
_type == Internals::JSON_UNPARSED && _content.asString &&
|
||||
!strcmp("null", _content.asString);
|
||||
}
|
||||
|
||||
// The current type of the variant
|
||||
Internals::JsonVariantType _type;
|
||||
@ -323,6 +372,3 @@ struct JsonVariant::IsConstructibleFrom {
|
||||
TypeTraits::IsSame<T, const JsonVariant &>::value;
|
||||
};
|
||||
}
|
||||
|
||||
// Include inline implementations
|
||||
#include "JsonVariant.ipp"
|
||||
|
@ -10,42 +10,15 @@
|
||||
#include "Configuration.hpp"
|
||||
#include "JsonVariant.hpp"
|
||||
#include "Internals/Parse.hpp"
|
||||
#include "JsonArray.hpp"
|
||||
#include "JsonObject.hpp"
|
||||
|
||||
#include <string.h>
|
||||
#include <string.h> // for strcmp
|
||||
#include <errno.h> // for errno
|
||||
#include <stdlib.h> // for strtol, strtod
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
inline JsonVariant::JsonVariant(bool value) {
|
||||
using namespace Internals;
|
||||
_type = JSON_BOOLEAN;
|
||||
_content.asInteger = static_cast<JsonInteger>(value);
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(const char *value) {
|
||||
_type = Internals::JSON_STRING;
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(RawJson value) {
|
||||
_type = Internals::JSON_UNPARSED;
|
||||
_content.asString = value;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(JsonArray &array) {
|
||||
_type = Internals::JSON_ARRAY;
|
||||
_content.asArray = &array;
|
||||
}
|
||||
|
||||
inline JsonVariant::JsonVariant(JsonObject &object) {
|
||||
_type = Internals::JSON_OBJECT;
|
||||
_content.asObject = &object;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T JsonVariant::invalid() {
|
||||
return T();
|
||||
}
|
||||
|
||||
inline Internals::JsonInteger JsonVariant::asInteger() const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
@ -85,6 +58,119 @@ inline Internals::JsonUInt JsonVariant::asUnsignedInteger() const {
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *JsonVariant::asString() const {
|
||||
using namespace Internals;
|
||||
if (_type == JSON_UNPARSED && _content.asString &&
|
||||
!strcmp("null", _content.asString))
|
||||
return NULL;
|
||||
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline Internals::JsonFloat JsonVariant::asFloat() const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return static_cast<JsonFloat>(_content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return -static_cast<JsonFloat>(_content.asInteger);
|
||||
case JSON_STRING:
|
||||
case JSON_UNPARSED:
|
||||
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
|
||||
default:
|
||||
return _content.asFloat;
|
||||
}
|
||||
}
|
||||
|
||||
inline String JsonVariant::toString() const {
|
||||
using namespace Internals;
|
||||
String s;
|
||||
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
|
||||
_content.asString != NULL)
|
||||
s = _content.asString;
|
||||
else
|
||||
printTo(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
inline bool JsonVariant::isBoolean() const {
|
||||
using namespace Internals;
|
||||
if (_type == JSON_BOOLEAN) return true;
|
||||
|
||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||
|
||||
return !strcmp(_content.asString, "true") ||
|
||||
!strcmp(_content.asString, "false");
|
||||
}
|
||||
|
||||
inline bool JsonVariant::isInteger() const {
|
||||
using namespace Internals;
|
||||
if (_type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER)
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool JsonVariant::isFloat() const {
|
||||
using namespace Internals;
|
||||
if (_type >= JSON_FLOAT_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>();
|
||||
}
|
||||
|
||||
inline void JsonVariant::writeTo(Internals::JsonWriter &writer) const {
|
||||
using namespace Internals;
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
return;
|
||||
|
||||
case JSON_ARRAY:
|
||||
_content.asArray->writeTo(writer);
|
||||
return;
|
||||
|
||||
case JSON_OBJECT:
|
||||
_content.asObject->writeTo(writer);
|
||||
return;
|
||||
|
||||
case JSON_STRING:
|
||||
writer.writeString(_content.asString);
|
||||
return;
|
||||
|
||||
case JSON_UNPARSED:
|
||||
writer.writeRaw(_content.asString);
|
||||
return;
|
||||
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
writer.writeRaw('-');
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
writer.writeInteger(_content.asInteger);
|
||||
return;
|
||||
|
||||
case JSON_BOOLEAN:
|
||||
writer.writeBoolean(_content.asInteger != 0);
|
||||
return;
|
||||
|
||||
default:
|
||||
uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
|
||||
writer.writeFloat(_content.asFloat, decimals);
|
||||
}
|
||||
}
|
||||
|
||||
#if ARDUINOJSON_ENABLE_STD_STREAM
|
||||
inline std::ostream &operator<<(std::ostream &os, const JsonVariant &source) {
|
||||
return source.printTo(os);
|
||||
|
@ -7,8 +7,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Internals/ForceInline.hpp"
|
||||
#include "Internals/JsonVariantAs.hpp"
|
||||
#include "JsonObjectKey.hpp"
|
||||
#include "Polyfills/attributes.hpp"
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
@ -20,20 +21,35 @@ class JsonObjectSubscript;
|
||||
template <typename TImpl>
|
||||
class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
|
||||
public:
|
||||
FORCE_INLINE const char *asString() const { return as<const char *>(); }
|
||||
// DEPRECATED: use as<char*>() instead
|
||||
FORCE_INLINE const char *asString() const {
|
||||
return as<const char *>();
|
||||
}
|
||||
|
||||
// Gets the variant as an array.
|
||||
// Returns a reference to the JsonArray or JsonArray::invalid() if the
|
||||
// variant
|
||||
// is not an array.
|
||||
FORCE_INLINE operator JsonArray &() const { return as<JsonArray &>(); }
|
||||
FORCE_INLINE JsonArray &asArray() const { return as<JsonArray &>(); }
|
||||
FORCE_INLINE operator JsonArray &() const {
|
||||
return as<JsonArray &>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use as<JsonArray>() instead
|
||||
FORCE_INLINE JsonArray &asArray() const {
|
||||
return as<JsonArray &>();
|
||||
}
|
||||
|
||||
// Gets the variant as an object.
|
||||
// Returns a reference to the JsonObject or JsonObject::invalid() if the
|
||||
// variant is not an object.
|
||||
FORCE_INLINE operator JsonObject &() const { return as<JsonObject &>(); }
|
||||
FORCE_INLINE JsonObject &asObject() const { return as<JsonObject &>(); }
|
||||
FORCE_INLINE operator JsonObject &() const {
|
||||
return as<JsonObject &>();
|
||||
}
|
||||
|
||||
// DEPRECATED: use as<JsonObject>() instead
|
||||
FORCE_INLINE JsonObject &asObject() const {
|
||||
return as<JsonObject &>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE operator T() const {
|
||||
@ -41,14 +57,16 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
FORCE_INLINE const T as() const {
|
||||
FORCE_INLINE const typename Internals::JsonVariantAs<T>::type as() const {
|
||||
return impl()->template as<T>();
|
||||
}
|
||||
|
||||
// Mimics an array or an object.
|
||||
// Returns the size of the array or object if the variant has that type.
|
||||
// Returns 0 if the variant is neither an array nor an object
|
||||
size_t size() const { return asArray().size() + asObject().size(); }
|
||||
size_t size() const {
|
||||
return asArray().size() + asObject().size();
|
||||
}
|
||||
|
||||
// Mimics an array.
|
||||
// Returns the element at specified index if the variant is an array.
|
||||
@ -68,7 +86,9 @@ class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
|
||||
void writeTo(Internals::JsonWriter &writer) const;
|
||||
|
||||
private:
|
||||
const TImpl *impl() const { return static_cast<const TImpl *>(this); }
|
||||
const TImpl *impl() const {
|
||||
return static_cast<const TImpl *>(this);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TImpl, typename TComparand>
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FORCE_INLINE __forceinline
|
||||
#define NO_INLINE __declspec(noinline)
|
||||
#else
|
||||
#define FORCE_INLINE __attribute__((always_inline))
|
||||
#define NO_INLINE __attribute__((noinline))
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
#include <float.h>
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
template <typename T>
|
||||
bool isInfinity(T x) {
|
||||
return !_finite(x);
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
bool isInfinity(T x) {
|
||||
return isinf(x);
|
||||
}
|
||||
|
||||
#ifdef __GLIBC__
|
||||
template <>
|
||||
inline bool isInfinity<double>(double x) {
|
||||
return isinfl(x);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isInfinity<float>(float x) {
|
||||
return isinff(x);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
#include <float.h>
|
||||
#else
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
template <typename T>
|
||||
bool isNaN(T x) {
|
||||
return _isnan(x) != 0;
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
bool isNaN(T x) {
|
||||
return isnan(x);
|
||||
}
|
||||
|
||||
#ifdef __GLIBC__
|
||||
template <>
|
||||
inline bool isNaN<double>(double x) {
|
||||
return isnanl(x);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isNaN<float>(float x) {
|
||||
return isnanf(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
111
include/ArduinoJson/Polyfills/math.hpp
Normal file
111
include/ArduinoJson/Polyfills/math.hpp
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#pragma once
|
||||
|
||||
// If Visual Studo <= 2012
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1700
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
template <typename T>
|
||||
bool isNaN(T x) {
|
||||
return _isnan(x) != 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool isInfinity(T x) {
|
||||
return !_finite(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// GCC warning: "conversion to 'float' from 'double' may alter its value"
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
|
||||
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||
#else
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Workaround for libs that #undef isnan or isinf
|
||||
// https://github.com/bblanchon/ArduinoJson/issues/284
|
||||
#if !defined(isnan) || !defined(isinf)
|
||||
namespace std {}
|
||||
#endif
|
||||
|
||||
namespace ArduinoJson {
|
||||
namespace Polyfills {
|
||||
|
||||
template <typename T>
|
||||
bool isNaN(T x) {
|
||||
// Workaround for libs that #undef isnan
|
||||
// https://github.com/bblanchon/ArduinoJson/issues/284
|
||||
#ifndef isnan
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
return isnan(x);
|
||||
}
|
||||
|
||||
#if defined(_GLIBCXX_HAVE_ISNANL) && _GLIBCXX_HAVE_ISNANL
|
||||
template <>
|
||||
inline bool isNaN<double>(double x) {
|
||||
return isnanl(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_GLIBCXX_HAVE_ISNANF) && _GLIBCXX_HAVE_ISNANF
|
||||
template <>
|
||||
inline bool isNaN<float>(float x) {
|
||||
return isnanf(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
bool isInfinity(T x) {
|
||||
// Workaround for libs that #undef isinf
|
||||
// https://github.com/bblanchon/ArduinoJson/issues/284
|
||||
#ifndef isinf
|
||||
using namespace std;
|
||||
#endif
|
||||
|
||||
return isinf(x);
|
||||
}
|
||||
|
||||
#if defined(_GLIBCXX_HAVE_ISINFL) && _GLIBCXX_HAVE_ISINFL
|
||||
template <>
|
||||
inline bool isInfinity<double>(double x) {
|
||||
return isinfl(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_GLIBCXX_HAVE_ISINFF) && _GLIBCXX_HAVE_ISINFF
|
||||
template <>
|
||||
inline bool isInfinity<float>(float x) {
|
||||
return isinff(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
@ -9,6 +9,16 @@
|
||||
|
||||
#include "JsonBuffer.hpp"
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#endif
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
// Implements a JsonBuffer with fixed memory allocation.
|
||||
@ -19,8 +29,12 @@ class StaticJsonBuffer : public JsonBuffer {
|
||||
public:
|
||||
explicit StaticJsonBuffer() : _size(0) {}
|
||||
|
||||
size_t capacity() const { return CAPACITY; }
|
||||
size_t size() const { return _size; }
|
||||
size_t capacity() const {
|
||||
return CAPACITY;
|
||||
}
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
virtual void* alloc(size_t bytes) {
|
||||
if (_size + bytes > CAPACITY) return NULL;
|
||||
@ -34,3 +48,11 @@ class StaticJsonBuffer : public JsonBuffer {
|
||||
size_t _size;
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
@ -6,7 +6,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/bblanchon/ArduinoJson.git"
|
||||
},
|
||||
"version": "5.4.0",
|
||||
"version": "5.6.5",
|
||||
"authors": {
|
||||
"name": "Benoit Blanchon",
|
||||
"url": "http://blog.benoitblanchon.fr"
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ArduinoJson
|
||||
version=5.4.0
|
||||
version=5.6.5
|
||||
author=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
maintainer=Benoit Blanchon <blog.benoitblanchon.fr>
|
||||
sentence=An efficient and elegant JSON library for Arduino.
|
||||
|
@ -17,5 +17,4 @@ rm -f $OUTPUT
|
||||
ArduinoJson/library.properties \
|
||||
ArduinoJson/LICENSE.md \
|
||||
ArduinoJson/README.md \
|
||||
ArduinoJson/src \
|
||||
-x!ArduinoJson/src/CMakeLists.txt
|
||||
ArduinoJson/ArduinoJson.h
|
||||
|
@ -1,52 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
TAG=$(git describe)
|
||||
OUTPUT="ArduinoJson-$TAG-old-layout.zip"
|
||||
|
||||
cd $(dirname $0)/..
|
||||
|
||||
cat > ArduinoJson.h <<END
|
||||
// WARNING:
|
||||
// --------
|
||||
// This file is a workaround for old version of the Arduino IDE.
|
||||
// If you are using Arduino IDE 1.0.6 or above, then you installed the wrong
|
||||
// package of ArduinoJson.
|
||||
// In that case, just delete the current installation and install the package.
|
||||
|
||||
END
|
||||
cp ArduinoJson.h ArduinoJson.cpp
|
||||
|
||||
cat "include/ArduinoJson.h" | sed 's!include "!include "include/!g' >> ArduinoJson.h
|
||||
|
||||
find src -name "*.cpp" |
|
||||
while read FILE; do
|
||||
echo >> ArduinoJson.cpp
|
||||
echo "// $FILE" >> ArduinoJson.cpp
|
||||
echo "//" >> ArduinoJson.cpp
|
||||
cat "$FILE" | sed 's!\.\./!!g' >> ArduinoJson.cpp
|
||||
done
|
||||
|
||||
unix2dos ArduinoJson.cpp
|
||||
unix2dos ArduinoJson.h
|
||||
|
||||
pushd ..
|
||||
|
||||
# remove existing file
|
||||
rm -f $OUTPUT
|
||||
|
||||
# create zipman dos2
|
||||
7z a $OUTPUT \
|
||||
ArduinoJson/CHANGELOG.md \
|
||||
ArduinoJson/examples \
|
||||
ArduinoJson/include/ArduinoJson \
|
||||
ArduinoJson/keywords.txt \
|
||||
ArduinoJson/LICENSE.md \
|
||||
ArduinoJson/README.md \
|
||||
ArduinoJson/ArduinoJson.h \
|
||||
ArduinoJson/ArduinoJson.cpp \
|
||||
-x!ArduinoJson/src/CMakeLists.txt
|
||||
|
||||
popd
|
||||
|
||||
rm ArduinoJson.h
|
||||
rm ArduinoJson.cpp
|
9
scripts/travis/cmake-osx.sh
Executable file
9
scripts/travis/cmake-osx.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh -eux
|
||||
|
||||
URL=https://cmake.org/files/v3.4/cmake-3.4.3-Darwin-x86_64.tar.gz
|
||||
|
||||
curl -sS $URL | tar xz -C /tmp --strip 1
|
||||
|
||||
/tmp/CMake.app/Contents/bin/cmake .
|
||||
make
|
||||
make test
|
@ -1,6 +1,8 @@
|
||||
#!/bin/sh -eux
|
||||
|
||||
curl -sS https://cmake.org/files/v3.4/cmake-3.4.0-Linux-x86_64.tar.gz | tar xz -C /tmp --strip 1
|
||||
URL=https://cmake.org/files/v3.4/cmake-3.4.3-Linux-x86_64.tar.gz
|
||||
|
||||
curl -sS $URL | tar xz -C /tmp --strip 1
|
||||
|
||||
/tmp/bin/cmake -DCMAKE_CXX_COMPILER=$CMAKE_CXX_COMPILER .
|
||||
make
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
// About this file
|
||||
// ---------------
|
||||
// This file is here to please the Arduino IDE. It must be present in the src/
|
||||
// for the IDE to find it. Feel free to ignore this file if your working in
|
||||
// another environment
|
||||
|
||||
#include "../include/ArduinoJson.h"
|
@ -1,71 +0,0 @@
|
||||
# Copyright Benoit Blanchon 2014-2016
|
||||
# MIT License
|
||||
#
|
||||
# Arduino JSON library
|
||||
# https://github.com/bblanchon/ArduinoJson
|
||||
# If you like this project, please add a star!
|
||||
|
||||
file(GLOB_RECURSE HPP_FILES ../include/*.hpp)
|
||||
file(GLOB_RECURSE IPP_FILES ../include/*.ipp)
|
||||
file(GLOB_RECURSE CPP_FILES *.cpp)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
add_compile_options(
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
-pedantic
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wcast-qual
|
||||
-Wconversion
|
||||
-Wctor-dtor-privacy
|
||||
-Wdisabled-optimization
|
||||
-Werror
|
||||
-Wextra
|
||||
-Wformat=2
|
||||
-Winit-self
|
||||
-Wmissing-include-dirs
|
||||
-Wno-parentheses
|
||||
-Wno-sign-conversion
|
||||
-Wno-unused
|
||||
-Wno-variadic-macros
|
||||
-Wnon-virtual-dtor
|
||||
-Wold-style-cast
|
||||
-Woverloaded-virtual
|
||||
-Wredundant-decls
|
||||
-Wshadow
|
||||
-Wsign-promo
|
||||
-Wstrict-overflow=5
|
||||
-Wundef
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
add_compile_options(
|
||||
-Wstrict-null-sentinel
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
|
||||
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
|
||||
add_compile_options(-Wnoexcept)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(
|
||||
-Wc++11-compat
|
||||
-Wdeprecated-register
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_options(-W4)
|
||||
endif()
|
||||
|
||||
add_library(ArduinoJson ${CPP_FILES} ${HPP_FILES} ${IPP_FILES})
|
||||
|
||||
target_include_directories(ArduinoJson INTERFACE ${CMAKE_CURRENT_LIST_DIR}/../include)
|
@ -1,52 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||
|
||||
inline static const char *skipCStyleComment(const char *ptr) {
|
||||
ptr += 2;
|
||||
for (;;) {
|
||||
if (ptr[0] == '\0') return ptr;
|
||||
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
inline static const char *skipCppStyleComment(const char *ptr) {
|
||||
ptr += 2;
|
||||
for (;;) {
|
||||
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
const char *ArduinoJson::Internals::skipSpacesAndComments(const char *ptr) {
|
||||
for (;;) {
|
||||
switch (ptr[0]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
ptr++;
|
||||
continue;
|
||||
case '/':
|
||||
switch (ptr[1]) {
|
||||
case '*':
|
||||
ptr = skipCStyleComment(ptr);
|
||||
break;
|
||||
case '/':
|
||||
ptr = skipCppStyleComment(ptr);
|
||||
break;
|
||||
default:
|
||||
return ptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||
|
||||
// How to escape special chars:
|
||||
// _escapeTable[2*i+1] => the special char
|
||||
// _escapeTable[2*i] => the char to use instead
|
||||
const char ArduinoJson::Internals::Encoding::_escapeTable[] =
|
||||
"\"\"\\\\b\bf\fn\nr\rt\t";
|
@ -1,30 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/IndentedPrint.hpp"
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
size_t IndentedPrint::write(uint8_t c) {
|
||||
size_t n = 0;
|
||||
|
||||
if (isNewLine) n += writeTabs();
|
||||
|
||||
n += sink->write(c);
|
||||
|
||||
isNewLine = c == '\n';
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
inline size_t IndentedPrint::writeTabs() {
|
||||
size_t n = 0;
|
||||
|
||||
for (int i = 0; i < level * tabSize; i++) n += sink->write(' ');
|
||||
|
||||
return n;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/List.hpp"
|
||||
|
||||
#include "../../include/ArduinoJson/JsonPair.hpp"
|
||||
#include "../../include/ArduinoJson/JsonVariant.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
template <typename T>
|
||||
size_t List<T>::size() const {
|
||||
size_t nodeCount = 0;
|
||||
for (node_type *node = _firstNode; node; node = node->next) nodeCount++;
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename List<T>::node_type *List<T>::addNewNode() {
|
||||
node_type *newNode = new (_buffer) node_type();
|
||||
|
||||
if (_firstNode) {
|
||||
node_type *lastNode = _firstNode;
|
||||
while (lastNode->next) lastNode = lastNode->next;
|
||||
lastNode->next = newNode;
|
||||
} else {
|
||||
_firstNode = newNode;
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void List<T>::removeNode(node_type *nodeToRemove) {
|
||||
if (!nodeToRemove) return;
|
||||
if (nodeToRemove == _firstNode) {
|
||||
_firstNode = nodeToRemove->next;
|
||||
} else {
|
||||
for (node_type *node = _firstNode; node; node = node->next)
|
||||
if (node->next == nodeToRemove) node->next = nodeToRemove->next;
|
||||
}
|
||||
}
|
||||
|
||||
template class ArduinoJson::Internals::List<JsonPair>;
|
||||
template class ArduinoJson::Internals::List<JsonVariant>;
|
@ -1,87 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Prettyfier.hpp"
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
size_t Prettyfier::write(uint8_t c) {
|
||||
size_t n = _inString ? handleStringChar(c) : handleMarkupChar(c);
|
||||
_previousChar = c;
|
||||
return n;
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleStringChar(uint8_t c) {
|
||||
bool isQuote = c == '"' && _previousChar != '\\';
|
||||
|
||||
if (isQuote) _inString = false;
|
||||
|
||||
return _sink.write(c);
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleMarkupChar(uint8_t c) {
|
||||
switch (c) {
|
||||
case '{':
|
||||
case '[':
|
||||
return handleBlockOpen(c);
|
||||
|
||||
case '}':
|
||||
case ']':
|
||||
return handleBlockClose(c);
|
||||
|
||||
case ':':
|
||||
return handleColon();
|
||||
|
||||
case ',':
|
||||
return handleComma();
|
||||
|
||||
case '"':
|
||||
return handleQuoteOpen();
|
||||
|
||||
default:
|
||||
return handleNormalChar(c);
|
||||
}
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleBlockOpen(uint8_t c) {
|
||||
return indentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleBlockClose(uint8_t c) {
|
||||
return unindentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleColon() {
|
||||
return _sink.write(':') + _sink.write(' ');
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleComma() {
|
||||
return _sink.write(',') + _sink.println();
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleQuoteOpen() {
|
||||
_inString = true;
|
||||
return indentIfNeeded() + _sink.write('"');
|
||||
}
|
||||
|
||||
inline size_t Prettyfier::handleNormalChar(uint8_t c) {
|
||||
return indentIfNeeded() + _sink.write(c);
|
||||
}
|
||||
|
||||
size_t Prettyfier::indentIfNeeded() {
|
||||
if (!inEmptyBlock()) return 0;
|
||||
|
||||
_sink.indent();
|
||||
return _sink.println();
|
||||
}
|
||||
|
||||
size_t Prettyfier::unindentIfNeeded() {
|
||||
if (inEmptyBlock()) return 0;
|
||||
|
||||
_sink.unindent();
|
||||
return _sink.println();
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
size_t StaticStringBuilder::write(uint8_t c) {
|
||||
if (length >= capacity) return 0;
|
||||
|
||||
buffer[length++] = c;
|
||||
buffer[length] = '\0';
|
||||
return 1;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
|
||||
#include "../include/ArduinoJson/JsonBuffer.hpp"
|
||||
#include "../include/ArduinoJson/JsonObject.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
JsonArray JsonArray::_invalid(NULL);
|
||||
|
||||
JsonArray::node_type *JsonArray::getNodeAt(size_t index) const {
|
||||
node_type *node = _firstNode;
|
||||
while (node && index--) node = node->next;
|
||||
return node;
|
||||
}
|
||||
|
||||
void JsonArray::removeAt(size_t index) { removeNode(getNodeAt(index)); }
|
||||
|
||||
void JsonArray::writeTo(JsonWriter &writer) const {
|
||||
writer.beginArray();
|
||||
|
||||
const node_type *child = _firstNode;
|
||||
while (child) {
|
||||
child->content.writeTo(writer);
|
||||
|
||||
child = child->next;
|
||||
if (!child) break;
|
||||
|
||||
writer.writeComma();
|
||||
}
|
||||
|
||||
writer.endArray();
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../include/ArduinoJson/JsonBuffer.hpp"
|
||||
|
||||
#include "../include/ArduinoJson/Internals/JsonParser.hpp"
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../include/ArduinoJson/JsonObject.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
JsonArray &JsonBuffer::createArray() {
|
||||
JsonArray *ptr = new (this) JsonArray(this);
|
||||
return ptr ? *ptr : JsonArray::invalid();
|
||||
}
|
||||
|
||||
JsonObject &JsonBuffer::createObject() {
|
||||
JsonObject *ptr = new (this) JsonObject(this);
|
||||
return ptr ? *ptr : JsonObject::invalid();
|
||||
}
|
||||
|
||||
JsonArray &JsonBuffer::parseArray(char *json, uint8_t nestingLimit) {
|
||||
JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseArray();
|
||||
}
|
||||
|
||||
JsonObject &JsonBuffer::parseObject(char *json, uint8_t nestingLimit) {
|
||||
JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseObject();
|
||||
}
|
||||
|
||||
JsonVariant JsonBuffer::parse(char *json, uint8_t nestingLimit) {
|
||||
JsonParser parser(this, json, nestingLimit);
|
||||
return parser.parseVariant();
|
||||
}
|
||||
|
||||
char *JsonBuffer::strdup(const char *source, size_t length) {
|
||||
size_t size = length + 1;
|
||||
char *dest = static_cast<char *>(alloc(size));
|
||||
if (dest != NULL) memcpy(dest, source, size);
|
||||
return dest;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../include/ArduinoJson/JsonObject.hpp"
|
||||
|
||||
#include <string.h> // for strcmp
|
||||
|
||||
#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../include/ArduinoJson/JsonBuffer.hpp"
|
||||
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
JsonObject JsonObject::_invalid(NULL);
|
||||
|
||||
JsonObject::node_type *JsonObject::getNodeAt(const char *key) const {
|
||||
for (node_type *node = _firstNode; node; node = node->next) {
|
||||
if (!strcmp(node->content.key, key)) return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void JsonObject::writeTo(JsonWriter &writer) const {
|
||||
writer.beginObject();
|
||||
|
||||
const node_type *node = _firstNode;
|
||||
while (node) {
|
||||
writer.writeString(node->content.key);
|
||||
writer.writeColon();
|
||||
node->content.value.writeTo(writer);
|
||||
|
||||
node = node->next;
|
||||
if (!node) break;
|
||||
|
||||
writer.writeComma();
|
||||
}
|
||||
|
||||
writer.endObject();
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include "../include/ArduinoJson/JsonVariant.hpp"
|
||||
|
||||
#include "../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../include/ArduinoJson/JsonObject.hpp"
|
||||
|
||||
#include <errno.h> // for errno
|
||||
#include <stdlib.h> // for strtol, strtod
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
namespace ArduinoJson {
|
||||
|
||||
const char *JsonVariant::asString() 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;
|
||||
}
|
||||
|
||||
JsonFloat JsonVariant::asFloat() const {
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
return 0;
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
case JSON_BOOLEAN:
|
||||
return static_cast<JsonFloat>(_content.asInteger);
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
return -static_cast<JsonFloat>(_content.asInteger);
|
||||
case JSON_STRING:
|
||||
case JSON_UNPARSED:
|
||||
return _content.asString ? parse<JsonFloat>(_content.asString) : 0;
|
||||
default:
|
||||
return _content.asFloat;
|
||||
}
|
||||
}
|
||||
|
||||
String JsonVariant::toString() const {
|
||||
String s;
|
||||
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
|
||||
_content.asString != NULL)
|
||||
s = _content.asString;
|
||||
else
|
||||
printTo(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool JsonVariant::isBoolean() const {
|
||||
if (_type == JSON_BOOLEAN) return true;
|
||||
|
||||
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
|
||||
|
||||
return !strcmp(_content.asString, "true") ||
|
||||
!strcmp(_content.asString, "false");
|
||||
}
|
||||
|
||||
bool JsonVariant::isInteger() const {
|
||||
if (_type == JSON_POSITIVE_INTEGER || _type == JSON_NEGATIVE_INTEGER)
|
||||
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;
|
||||
}
|
||||
|
||||
bool JsonVariant::isFloat() const {
|
||||
if (_type >= JSON_FLOAT_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 {
|
||||
switch (_type) {
|
||||
case JSON_UNDEFINED:
|
||||
return;
|
||||
|
||||
case JSON_ARRAY:
|
||||
_content.asArray->writeTo(writer);
|
||||
return;
|
||||
|
||||
case JSON_OBJECT:
|
||||
_content.asObject->writeTo(writer);
|
||||
return;
|
||||
|
||||
case JSON_STRING:
|
||||
writer.writeString(_content.asString);
|
||||
return;
|
||||
|
||||
case JSON_UNPARSED:
|
||||
writer.writeRaw(_content.asString);
|
||||
return;
|
||||
|
||||
case JSON_NEGATIVE_INTEGER:
|
||||
writer.writeRaw('-');
|
||||
case JSON_POSITIVE_INTEGER:
|
||||
writer.writeInteger(_content.asInteger);
|
||||
return;
|
||||
|
||||
case JSON_BOOLEAN:
|
||||
writer.writeBoolean(_content.asInteger != 0);
|
||||
return;
|
||||
|
||||
default:
|
||||
uint8_t decimals = static_cast<uint8_t>(_type - JSON_FLOAT_0_DECIMALS);
|
||||
writer.writeFloat(_content.asFloat, decimals);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,31 +5,69 @@
|
||||
# https://github.com/bblanchon/ArduinoJson
|
||||
# If you like this project, please add a star!
|
||||
|
||||
set(GTEST_DIR ../third-party/gtest-1.7.0)
|
||||
include(gtest.cmake)
|
||||
|
||||
file(GLOB TESTS_FILES *.hpp *.cpp)
|
||||
|
||||
include_directories(
|
||||
${GTEST_DIR}
|
||||
${GTEST_DIR}/include)
|
||||
|
||||
add_definitions(-DGTEST_HAS_PTHREAD=0)
|
||||
|
||||
# Workaround for Visual Studio 2012
|
||||
if (MSVC AND MSVC_VERSION EQUAL 1700)
|
||||
add_definitions(-D_VARIADIC_MAX=10)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
add_compile_options(
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
-pedantic
|
||||
-Wall
|
||||
-Wcast-align
|
||||
-Wcast-qual
|
||||
-Wconversion
|
||||
-Wctor-dtor-privacy
|
||||
-Wdisabled-optimization
|
||||
-Werror
|
||||
-Wextra
|
||||
-Wformat=2
|
||||
-Winit-self
|
||||
-Wmissing-include-dirs
|
||||
-Wno-parentheses
|
||||
-Wno-sign-conversion
|
||||
-Wno-unused
|
||||
-Wno-variadic-macros
|
||||
-Wnon-virtual-dtor
|
||||
-Wold-style-cast
|
||||
-Woverloaded-virtual
|
||||
-Wredundant-decls
|
||||
-Wshadow
|
||||
-Wsign-promo
|
||||
-Wstrict-overflow=5
|
||||
-Wundef
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
add_compile_options(
|
||||
-Wstrict-null-sentinel
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
|
||||
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
|
||||
add_compile_options(-Wnoexcept)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options(
|
||||
-Wc++11-compat
|
||||
-Wdeprecated-register
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_options(-W4)
|
||||
endif()
|
||||
|
||||
add_executable(ArduinoJsonTests
|
||||
${TESTS_FILES}
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
${GTEST_DIR}/src/gtest_main.cc)
|
||||
|
||||
|
||||
target_link_libraries(ArduinoJsonTests ArduinoJson)
|
||||
add_executable(ArduinoJsonTests ${TESTS_FILES})
|
||||
target_include_directories(ArduinoJsonTests PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../include)
|
||||
target_link_libraries(ArduinoJsonTests gtest)
|
||||
|
||||
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)
|
||||
|
@ -6,11 +6,7 @@
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#define protected public
|
||||
#include <ArduinoJson/DynamicJsonBuffer.hpp>
|
||||
|
||||
using namespace ArduinoJson;
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class DynamicJsonBuffer_Basic_Tests : public testing::Test {
|
||||
protected:
|
||||
|
@ -44,7 +44,7 @@ TEST(JsonArray_CopyTo_Tests, TwoOneDimensionIntegerArray) {
|
||||
DynamicJsonBuffer jsonBuffer;
|
||||
JsonArray& array = jsonBuffer.parseArray(json);
|
||||
|
||||
int destination[3][2] = {0};
|
||||
int destination[3][2] = {{0}};
|
||||
array.copyTo(destination);
|
||||
|
||||
ASSERT_EQ(1, destination[0][0]);
|
||||
|
@ -59,6 +59,7 @@ TEST_(StoreBoolean) {
|
||||
TEST_(StoreString) {
|
||||
_array[0] = "hello";
|
||||
EXPECT_STREQ("hello", _array[0].as<const char*>());
|
||||
EXPECT_STREQ("hello", _array[0].as<char*>()); // <- short hand
|
||||
EXPECT_TRUE(_array[0].is<const char*>());
|
||||
EXPECT_FALSE(_array[0].is<int>());
|
||||
}
|
||||
@ -69,6 +70,9 @@ TEST_(StoreNestedArray) {
|
||||
_array[0] = arr;
|
||||
|
||||
EXPECT_EQ(&arr, &_array[0].as<JsonArray&>());
|
||||
EXPECT_EQ(&arr, &_array[0].as<JsonArray>()); // <- short hand
|
||||
EXPECT_EQ(&arr, &_array[0].as<const JsonArray&>());
|
||||
EXPECT_EQ(&arr, &_array[0].as<const JsonArray>()); // <- short hand
|
||||
EXPECT_TRUE(_array[0].is<JsonArray&>());
|
||||
EXPECT_FALSE(_array[0].is<int>());
|
||||
}
|
||||
@ -79,6 +83,9 @@ TEST_(StoreNestedObject) {
|
||||
_array[0] = obj;
|
||||
|
||||
EXPECT_EQ(&obj, &_array[0].as<JsonObject&>());
|
||||
EXPECT_EQ(&obj, &_array[0].as<JsonObject>()); // <- short hand
|
||||
EXPECT_EQ(&obj, &_array[0].as<const JsonObject&>());
|
||||
EXPECT_EQ(&obj, &_array[0].as<const JsonObject>()); // <- short hand
|
||||
EXPECT_TRUE(_array[0].is<JsonObject&>());
|
||||
EXPECT_FALSE(_array[0].is<int>());
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ TEST_(StoreString) {
|
||||
EXPECT_TRUE(_object["hello"].is<const char*>());
|
||||
EXPECT_FALSE(_object["hello"].is<long>());
|
||||
EXPECT_STREQ("h3110", _object["hello"].as<const char*>());
|
||||
EXPECT_STREQ("h3110", _object["hello"].as<char*>()); // <- short hand
|
||||
}
|
||||
|
||||
TEST_(StoreArray) {
|
||||
@ -75,8 +76,15 @@ TEST_(StoreArray) {
|
||||
|
||||
_object["hello"] = arr;
|
||||
|
||||
EXPECT_EQ(&arr, &_object["hello"].asArray());
|
||||
EXPECT_EQ(&arr, &_object["hello"].asArray()); // <- DEPRECATED
|
||||
EXPECT_EQ(&arr, &_object["hello"].as<JsonArray&>());
|
||||
EXPECT_EQ(&arr, &_object["hello"].as<JsonArray>()); // <- short hand
|
||||
EXPECT_EQ(&arr, &_object["hello"].as<const JsonArray&>());
|
||||
EXPECT_EQ(&arr, &_object["hello"].as<const JsonArray>()); // <- short hand
|
||||
EXPECT_TRUE(_object["hello"].is<JsonArray&>());
|
||||
EXPECT_TRUE(_object["hello"].is<JsonArray>());
|
||||
EXPECT_TRUE(_object["hello"].is<const JsonArray&>());
|
||||
EXPECT_TRUE(_object["hello"].is<const JsonArray>());
|
||||
EXPECT_FALSE(_object["hello"].is<JsonObject&>());
|
||||
}
|
||||
|
||||
@ -85,8 +93,15 @@ TEST_(StoreObject) {
|
||||
|
||||
_object["hello"] = obj;
|
||||
|
||||
EXPECT_EQ(&obj, &_object["hello"].asObject());
|
||||
EXPECT_EQ(&obj, &_object["hello"].asObject()); // DEPRECATED
|
||||
EXPECT_EQ(&obj, &_object["hello"].as<JsonObject&>());
|
||||
EXPECT_EQ(&obj, &_object["hello"].as<JsonObject>()); // <- short hand
|
||||
EXPECT_EQ(&obj, &_object["hello"].as<const JsonObject&>());
|
||||
EXPECT_EQ(&obj, &_object["hello"].as<const JsonObject>()); // <- short hand
|
||||
EXPECT_TRUE(_object["hello"].is<JsonObject&>());
|
||||
EXPECT_TRUE(_object["hello"].is<JsonObject>());
|
||||
EXPECT_TRUE(_object["hello"].is<const JsonObject&>());
|
||||
EXPECT_TRUE(_object["hello"].is<const JsonObject>());
|
||||
EXPECT_FALSE(_object["hello"].is<JsonArray&>());
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,9 @@ class JsonParser_Variant_Test : public testing::Test {
|
||||
EXPECT_TRUE(_result.is<T>());
|
||||
}
|
||||
|
||||
void resultMustBeInvalid() { EXPECT_FALSE(_result.success()); }
|
||||
void resultMustBeValid() { EXPECT_TRUE(_result.success()); }
|
||||
|
||||
private:
|
||||
DynamicJsonBuffer _jsonBuffer;
|
||||
JsonVariant _result;
|
||||
@ -37,40 +40,52 @@ class JsonParser_Variant_Test : public testing::Test {
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, EmptyObject) {
|
||||
whenInputIs("{}");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<JsonObject>();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, EmptyArray) {
|
||||
whenInputIs("[]");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<JsonArray>();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, Integer) {
|
||||
whenInputIs("42");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<int>();
|
||||
resultMustEqual(42);
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, Double) {
|
||||
whenInputIs("3.14");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<double>();
|
||||
resultMustEqual(3.14);
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, String) {
|
||||
whenInputIs("\"hello world\"");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<char*>();
|
||||
resultMustEqual("hello world");
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, True) {
|
||||
whenInputIs("true");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<bool>();
|
||||
resultMustEqual(true);
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, False) {
|
||||
whenInputIs("false");
|
||||
resultMustBeValid();
|
||||
resultTypeMustBe<bool>();
|
||||
resultMustEqual(false);
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Variant_Test, Invalid) {
|
||||
whenInputIs("{");
|
||||
resultMustBeInvalid();
|
||||
}
|
||||
|
@ -214,3 +214,21 @@ TEST(JsonVariant_As_Tests, ArrayAsString) {
|
||||
JsonVariant variant = arr;
|
||||
ASSERT_EQ(String("[4,2]"), variant.as<String>());
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, ArrayAsJsonArray) {
|
||||
DynamicJsonBuffer buffer;
|
||||
JsonArray& arr = buffer.createArray();
|
||||
|
||||
JsonVariant variant = arr;
|
||||
ASSERT_EQ(&arr, &variant.as<JsonArray&>());
|
||||
ASSERT_EQ(&arr, &variant.as<JsonArray>()); // <- shorthand
|
||||
}
|
||||
|
||||
TEST(JsonVariant_As_Tests, ObjectAsJsonObject) {
|
||||
DynamicJsonBuffer buffer;
|
||||
JsonObject& arr = buffer.createObject();
|
||||
|
||||
JsonVariant variant = arr;
|
||||
ASSERT_EQ(&arr, &variant.as<JsonObject&>());
|
||||
ASSERT_EQ(&arr, &variant.as<JsonObject>()); // <- shorthand
|
||||
}
|
||||
|
@ -6,9 +6,7 @@
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ArduinoJson/JsonVariant.hpp>
|
||||
|
||||
using namespace ArduinoJson;
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class JsonVariant_Comparison_Tests : public ::testing::Test {
|
||||
protected:
|
||||
|
@ -5,8 +5,8 @@
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#define SUITE JsonVariant_Is_Tests
|
||||
|
||||
@ -34,75 +34,222 @@ void assertIs(JsonArray& 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, 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, 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, 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, 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, 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, UnparsedTrueIsArra) { assertIsNot<JsonArray&>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsBool) { assertIs<bool>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsDouble) { assertIsNot<double>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsFloat) { assertIsNot<float>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsInt) { assertIsNot<int>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsLong) { assertIsNot<long>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsString) { assertIsNot<const char*>(RawJson("true")); }
|
||||
TEST(SUITE, UnparsedTrueIsArray) {
|
||||
assertIsNot<JsonArray&>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsBool) {
|
||||
assertIs<bool>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsDouble) {
|
||||
assertIsNot<double>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsFloat) {
|
||||
assertIsNot<float>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsInt) {
|
||||
assertIsNot<int>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsLong) {
|
||||
assertIsNot<long>(RawJson("true"));
|
||||
}
|
||||
TEST(SUITE, UnparsedTrueIsString) {
|
||||
assertIsNot<const char*>(RawJson("true"));
|
||||
}
|
||||
|
||||
TEST(SUITE, UnparsedFalseIsArra) { assertIsNot<JsonArray&>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsBool) { assertIs<bool>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsDouble) { assertIsNot<double>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsFloat) { assertIsNot<float>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsInt) { assertIsNot<int>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsLong) { assertIsNot<long>(RawJson("false")); }
|
||||
TEST(SUITE, UnparsedFalseIsArray) {
|
||||
assertIsNot<JsonArray&>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsBool) {
|
||||
assertIs<bool>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsDouble) {
|
||||
assertIsNot<double>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsFloat) {
|
||||
assertIsNot<float>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsInt) {
|
||||
assertIsNot<int>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsLong) {
|
||||
assertIsNot<long>(RawJson("false"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFalseIsString) {
|
||||
assertIsNot<const char*>(RawJson("false"));
|
||||
}
|
||||
|
||||
TEST(SUITE, UnparsedIntIsArra) { assertIsNot<JsonArray&>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsBool) { assertIsNot<bool>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsDouble) { assertIsNot<double>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsFloat) { assertIsNot<float>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsInt) { assertIs<int>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsLong) { assertIs<long>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsString) { assertIsNot<const char*>(RawJson("42")); }
|
||||
TEST(SUITE, UnparsedIntIsArray) {
|
||||
assertIsNot<JsonArray&>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsBool) {
|
||||
assertIsNot<bool>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsDouble) {
|
||||
assertIsNot<double>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsFloat) {
|
||||
assertIsNot<float>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsInt) {
|
||||
assertIs<int>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsLong) {
|
||||
assertIs<long>(RawJson("42"));
|
||||
}
|
||||
TEST(SUITE, UnparsedIntIsString) {
|
||||
assertIsNot<const char*>(RawJson("42"));
|
||||
}
|
||||
|
||||
TEST(SUITE, UnparsedFloatIsBool) { assertIsNot<bool>(RawJson("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsDouble) { assertIs<double>(RawJson("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsFloat) { assertIs<float>(RawJson("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsInt) { assertIsNot<int>(RawJson("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsLong) { assertIsNot<long>(RawJson("4.2e-10")); }
|
||||
TEST(SUITE, UnparsedFloatIsStr) { assertIsNot<const char*>(RawJson("4.2")); }
|
||||
TEST(SUITE, UnparsedFloatIsBool) {
|
||||
assertIsNot<bool>(RawJson("4.2e-10"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFloatIsDouble) {
|
||||
assertIs<double>(RawJson("4.2e-10"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFloatIsFloat) {
|
||||
assertIs<float>(RawJson("4.2e-10"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFloatIsInt) {
|
||||
assertIsNot<int>(RawJson("4.2e-10"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFloatIsLong) {
|
||||
assertIsNot<long>(RawJson("4.2e-10"));
|
||||
}
|
||||
TEST(SUITE, UnparsedFloatIsStr) {
|
||||
assertIsNot<const char*>(RawJson("4.2"));
|
||||
}
|
||||
|
||||
TEST(SUITE, UnparsedNullIsArray) {
|
||||
assertIsNot<JsonArray&>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsBool) {
|
||||
assertIsNot<bool>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsDouble) {
|
||||
assertIsNot<double>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsFloat) {
|
||||
assertIsNot<float>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsInt) {
|
||||
assertIsNot<int>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsLong) {
|
||||
assertIsNot<long>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsConstCharPtr) {
|
||||
assertIs<const char*>(RawJson("null"));
|
||||
}
|
||||
TEST(SUITE, UnparsedNullIsCharPtr) {
|
||||
assertIs<char*>(RawJson("null"));
|
||||
}
|
||||
|
113
test/JsonWriter_WriteFloat_Tests.cpp
Normal file
113
test/JsonWriter_WriteFloat_Tests.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright Benoit Blanchon 2014-2016
|
||||
// MIT License
|
||||
//
|
||||
// Arduino JSON library
|
||||
// https://github.com/bblanchon/ArduinoJson
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <limits>
|
||||
|
||||
#include <ArduinoJson/Internals/JsonWriter.hpp>
|
||||
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>
|
||||
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
class JsonWriter_WriteFloat_Tests : public testing::Test {
|
||||
protected:
|
||||
void whenInputIs(double input, uint8_t digits = 2) {
|
||||
StaticStringBuilder sb(buffer, sizeof(buffer));
|
||||
JsonWriter writer(sb);
|
||||
writer.writeFloat(input, digits);
|
||||
returnValue = writer.bytesWritten();
|
||||
}
|
||||
|
||||
void outputMustBe(const char *expected) {
|
||||
EXPECT_STREQ(expected, buffer);
|
||||
EXPECT_EQ(strlen(expected), returnValue);
|
||||
}
|
||||
|
||||
private:
|
||||
char buffer[1024];
|
||||
size_t returnValue;
|
||||
};
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, NaN) {
|
||||
whenInputIs(std::numeric_limits<double>::signaling_NaN());
|
||||
outputMustBe("NaN");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, PositiveInfinity) {
|
||||
whenInputIs(std::numeric_limits<double>::infinity());
|
||||
outputMustBe("Infinity");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, NegativeInfinity) {
|
||||
whenInputIs(-std::numeric_limits<double>::infinity());
|
||||
outputMustBe("-Infinity");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, Zero) {
|
||||
whenInputIs(0);
|
||||
outputMustBe("0.00");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_Rounding) {
|
||||
whenInputIs(9.5, 0);
|
||||
outputMustBe("10");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_NoRounding) {
|
||||
whenInputIs(9.4, 0);
|
||||
outputMustBe("9");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_Rounding) {
|
||||
whenInputIs(9.95, 1);
|
||||
outputMustBe("10.0");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_NoRounding) {
|
||||
whenInputIs(9.94, 1);
|
||||
outputMustBe("9.9");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_Rounding) {
|
||||
whenInputIs(9.995, 2);
|
||||
outputMustBe("10.00");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_NoRounding) {
|
||||
whenInputIs(9.994, 2);
|
||||
outputMustBe("9.99");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_Rounding) {
|
||||
whenInputIs(9.9995, 3);
|
||||
outputMustBe("10.000");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_NoRounding) {
|
||||
whenInputIs(9.9994, 3);
|
||||
outputMustBe("9.999");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_Rounding) {
|
||||
whenInputIs(9.99995, 4);
|
||||
outputMustBe("10.0000");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_NoRounding) {
|
||||
whenInputIs(9.99994, 4);
|
||||
outputMustBe("9.9999");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_Rounding) {
|
||||
whenInputIs(9.999995, 5);
|
||||
outputMustBe("10.00000");
|
||||
}
|
||||
|
||||
TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_NoRounding) {
|
||||
whenInputIs(9.999994, 5);
|
||||
outputMustBe("9.99999");
|
||||
}
|
@ -6,11 +6,7 @@
|
||||
// If you like this project, please add a star!
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#define protected public
|
||||
#include <ArduinoJson/StaticJsonBuffer.hpp>
|
||||
|
||||
using namespace ArduinoJson;
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
class StaticJsonBuffer_Basic_Tests : public testing::Test {
|
||||
protected:
|
||||
|
@ -10,9 +10,13 @@
|
||||
|
||||
class StaticJsonBuffer_ParseArray_Tests : public testing::Test {
|
||||
protected:
|
||||
void with(JsonBuffer& jsonBuffer) { _jsonBuffer = &jsonBuffer; }
|
||||
void with(JsonBuffer& jsonBuffer) {
|
||||
_jsonBuffer = &jsonBuffer;
|
||||
}
|
||||
|
||||
void whenInputIs(const char* json) { strcpy(_jsonString, json); }
|
||||
void whenInputIs(const char* json) {
|
||||
strcpy(_jsonString, json);
|
||||
}
|
||||
|
||||
void parseMustSucceed() {
|
||||
EXPECT_TRUE(_jsonBuffer->parseArray(_jsonString).success());
|
||||
@ -73,9 +77,12 @@ TEST_F(StaticJsonBuffer_ParseArray_Tests,
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_ParseArray_Tests, CharPtrNull) {
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((char*)0).success());
|
||||
ASSERT_FALSE(
|
||||
StaticJsonBuffer<100>().parseArray(static_cast<char*>(0)).success());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_ParseArray_Tests, ConstCharPtrNull) {
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>().parseArray((const char*)0).success());
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>()
|
||||
.parseArray(static_cast<const char*>(0))
|
||||
.success());
|
||||
}
|
||||
|
@ -10,9 +10,13 @@
|
||||
|
||||
class StaticJsonBuffer_ParseObject_Tests : public testing::Test {
|
||||
protected:
|
||||
void with(JsonBuffer& jsonBuffer) { _jsonBuffer = &jsonBuffer; }
|
||||
void with(JsonBuffer& jsonBuffer) {
|
||||
_jsonBuffer = &jsonBuffer;
|
||||
}
|
||||
|
||||
void whenInputIs(const char* json) { strcpy(_jsonString, json); }
|
||||
void whenInputIs(const char* json) {
|
||||
strcpy(_jsonString, json);
|
||||
}
|
||||
|
||||
void parseMustSucceed() {
|
||||
EXPECT_TRUE(_jsonBuffer->parseObject(_jsonString).success());
|
||||
@ -74,9 +78,12 @@ TEST_F(StaticJsonBuffer_ParseObject_Tests,
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_ParseObject_Tests, CharPtrNull) {
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((char*)0).success());
|
||||
ASSERT_FALSE(
|
||||
StaticJsonBuffer<100>().parseObject(static_cast<char*>(0)).success());
|
||||
}
|
||||
|
||||
TEST_F(StaticJsonBuffer_ParseObject_Tests, ConstCharPtrNull) {
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>().parseObject((const char*)0).success());
|
||||
ASSERT_FALSE(StaticJsonBuffer<100>()
|
||||
.parseObject(static_cast<const char*>(0))
|
||||
.success());
|
||||
}
|
||||
|
24
test/gtest.cmake
Normal file
24
test/gtest.cmake
Normal file
@ -0,0 +1,24 @@
|
||||
set(GTEST_DIR ../third-party/gtest-1.7.0)
|
||||
|
||||
add_library(gtest
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
${GTEST_DIR}/src/gtest_main.cc
|
||||
)
|
||||
|
||||
target_include_directories(gtest
|
||||
PUBLIC
|
||||
${GTEST_DIR}
|
||||
${GTEST_DIR}/include
|
||||
)
|
||||
|
||||
|
||||
target_compile_definitions(gtest PUBLIC -DGTEST_HAS_PTHREAD=0)
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC_VERSION EQUAL 1700)
|
||||
# Workaround for Visual Studio 2012
|
||||
target_compile_definitions(gtest PUBLIC -D_VARIADIC_MAX=10)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(gtest PUBLIC -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
@ -1,3 +1,8 @@
|
||||
// clang-format off
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// This file was GENERATED by command:
|
||||
// pump.py gtest-param-test.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
@ -1,3 +1,8 @@
|
||||
// clang-format off
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -1,3 +1,8 @@
|
||||
// clang-format off
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -1,3 +1,8 @@
|
||||
// clang-format off
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// Copyright 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
|
Reference in New Issue
Block a user