Compare commits

..

161 Commits
v2.0 ... v3.4

Author SHA1 Message Date
a1b6c2df75 Merge branch 'parse-escaped-chars' 2014-09-09 21:33:12 +02:00
feb6060887 Updated change-log 2014-09-09 21:32:27 +02:00
49d2b4b2a2 Updated code size 2014-09-09 21:25:25 +02:00
286a514fbe Minor clean up 2014-09-09 21:23:37 +02:00
9d3b522e7b Reduced code size (-6 bytes) 2014-09-07 20:11:33 +02:00
c32642e130 Reduced code size (-6 bytes) 2014-09-07 19:55:54 +02:00
7a3fa35bd8 Added LICENSE.md 2014-09-06 12:04:09 +02:00
0154fc15cb Added escaped char replacement 2014-09-04 21:49:43 +02:00
24d173c3b9 Added tests of escaped chars 2014-09-04 21:30:50 +02:00
d4c1b6f2c2 Extracted a class to test strings 2014-09-04 21:20:40 +02:00
58c051f564 Added comments 2014-09-01 21:36:09 +02:00
763aa7fe37 Added an overload of prettyPrintTo() 2014-09-01 21:22:56 +02:00
cd88fb0882 Added prettyPrintTo() 2014-09-01 21:22:34 +02:00
ec843659d8 Updated CHANGELOG.md 2014-09-01 21:14:09 +02:00
2997a405a0 Added IndentedPrint example 2014-08-26 12:48:59 +02:00
57f28c2017 Reduced code size 2014-08-26 12:11:17 +02:00
b3b70b78cf Fixed build error in Arduino IDE 2014-08-26 12:03:50 +02:00
48018bd6e6 Set default tab size to 2 2014-08-26 11:59:41 +02:00
61952a9bcd Added setTabSize() 2014-08-26 11:58:33 +02:00
602cc104f9 Set line ending to CR LF, like in Arduino source code 2014-08-26 11:52:12 +02:00
d71a39211d Fixed prettyPrintTo calling printTo 2014-08-26 10:26:40 +02:00
f77a8b02e3 Fixed file names 2014-08-26 10:26:12 +02:00
aa2cd0db00 Moved IndentedPrint into the namespace ArduinoJson::Generator 2014-08-26 10:16:13 +02:00
f127ef6019 Refactoring... 2014-08-26 10:13:49 +02:00
3ae7327687 Renamed PrettyPrintDecorator into JsonPrettyPrint 2014-08-26 10:08:54 +02:00
23e61cc0f7 Renamed IndentedPrintDecorator into IndentedPrint 2014-08-26 09:56:05 +02:00
b5002265cf Refactoring... 2014-08-26 09:53:32 +02:00
e48ea94789 Refactoring... 2014-08-26 09:49:59 +02:00
6539c6982c Extracted class IndentedPrintDecorator from PrettyPrintDecorator 2014-08-26 09:28:41 +02:00
d877d77b63 Moved PrettyPrintDecorator into the namespace ArduinoJson::Generator 2014-08-25 13:19:07 +02:00
1df6cde026 Refactoring... 2014-08-25 13:14:09 +02:00
fafae8181b Refactoring... 2014-08-25 12:51:56 +02:00
151fc52c1c Refactoring... 2014-08-25 12:48:38 +02:00
ea79340dc7 Refactoring... 2014-08-25 12:41:49 +02:00
9e88514700 Refactoring.... 2014-08-25 12:28:58 +02:00
752378a8cb Fixed bug when a string contains a brace 2014-08-25 12:23:08 +02:00
8465cc0c83 Refactoring... 2014-08-25 11:46:42 +02:00
2ddf8f1619 Renamed IndentedPrintDecorator to PrettyPrintDecorator 2014-08-25 11:42:07 +02:00
f7aa0f89e3 Added JsonPrintable.prettyPrintTo(Print&) 2014-08-25 11:39:04 +02:00
3d322fdb28 Test nested arrays 2014-08-25 11:02:38 +02:00
981adf1989 Test empty nested arrays 2014-08-25 11:01:22 +02:00
dbc3bee3a0 Test array with 2 elements 2014-08-25 10:55:48 +02:00
3f2b7b706a Test an array with one element 2014-08-25 10:55:09 +02:00
c243417585 Test nested objects 2014-08-25 10:46:43 +02:00
514a6c0879 Splitted the indentation tests into 3 files 2014-08-25 10:42:00 +02:00
76f9ecce75 Tests empty nested objects in objects 2014-08-25 10:36:25 +02:00
410ca55e88 Added a space before the object's values 2014-08-25 10:34:28 +02:00
66c05041e8 Test an object with comma, quote and column in the value 2014-08-25 10:31:03 +02:00
aafabd8e8d Test an object with two memebrs 2014-08-25 10:22:42 +02:00
eb1a774778 Fixed empty object output 2014-08-25 09:56:51 +02:00
75c89e7b35 Test an object with one member 2014-08-25 09:52:42 +02:00
e31a2136fc Test with an empty array 2014-08-25 09:24:31 +02:00
380722402f Added a test of an empty object 2014-08-25 09:23:41 +02:00
030c8542e7 Now also test the return value 2014-08-25 09:19:26 +02:00
1f25d4434e Added test of an empty string 2014-08-25 09:17:32 +02:00
f29904e217 Added skeleton of class IndentedPrintDecorator 2014-08-25 09:06:46 +02:00
7246db7691 Added a note to avoid issue #10 2014-08-04 15:12:09 +02:00
4bdbc6c1fc Updated CHANGELOG.md 2014-08-04 14:59:09 +02:00
8e6fdb20eb Added tag in filename 2014-08-04 14:56:19 +02:00
016d0d699e Added a script to create Arduino package 2014-08-04 14:47:32 +02:00
6771603a05 Simplified JsonArray tests 2014-08-04 12:18:17 +02:00
d067cf0e84 Fixed tests 2014-08-04 09:35:57 +02:00
13593d73a3 Fixed nested object in arrays bug 2014-08-04 09:30:57 +02:00
bc86ae800a Changed JsonArray tests to show the issue 2014-08-04 09:22:45 +02:00
df52dceaa1 Added tests for issue #10 2014-08-04 09:21:04 +02:00
d460b59b50 Fixed CHANGELOG.md 2014-08-03 15:54:16 +02:00
8e5ea91f8d Updated README 2014-08-03 13:48:22 +02:00
4a8b7d0cb4 Updated code size 2014-08-03 13:23:40 +02:00
96c9b5deee Updated changelog. 2014-08-03 13:18:59 +02:00
8e81b9bb26 Added JsonObjectBase::remove() 2014-08-03 13:16:35 +02:00
817cc09975 Added typedef JsonKey 2014-08-03 13:09:07 +02:00
1bc45f1fd7 Extracted method getMatchingPair() 2014-08-02 16:25:18 +02:00
d2fe9ddf49 Added JsonObjectBase::containsKey() 2014-08-02 16:11:02 +02:00
5cc06180e6 Removed JsonValue::null(), moved the instance to JsonObjectBase 2014-08-02 15:55:46 +02:00
65e8b6d405 Optimized size of JsonObjectBase indexer (-58 bytes) 2014-08-02 15:37:01 +02:00
09294cb5e6 Made EscapedString pure static 2014-08-01 15:32:05 +02:00
158f4600fb Added static EscapedString::printTo 2014-08-01 15:27:58 +02:00
0d28612507 Fixed casting JsonValue to string 2014-08-01 15:23:14 +02:00
7c99d4d63d Reduced usages of EscapedString 2014-08-01 15:22:30 +02:00
1a01800782 Test casting a JsonValue to a JsonArray 2014-08-01 15:06:31 +02:00
6384bc414a Test casting a JsonValue to a float 2014-08-01 14:58:16 +02:00
c10bcee324 Test casting a JsonValue to a double 2014-08-01 14:56:46 +02:00
028ff6676e Test casting a JsonValue to a bool 2014-08-01 14:54:34 +02:00
23b5237f74 Test casting a JsonValue to a long 2014-08-01 14:53:05 +02:00
88510705be Test casting a JsonValue to an int 2014-08-01 14:52:15 +02:00
15d3068d78 Test casting a JsonValue to a string 2014-08-01 14:47:48 +02:00
ae6beb9340 Cleaned JsonValue tests 2014-08-01 14:38:28 +02:00
c1f4128ccd Added a failng test 2014-08-01 14:35:54 +02:00
5fb6edfc91 Cleaned JsonObject unit tests 2014-08-01 14:25:55 +02:00
2771b830b7 Replace the examples with the new API 2014-07-31 20:33:12 +02:00
84aa627038 Updated changelog 2014-07-31 20:28:52 +02:00
4528b8fc95 Use operator[] in example (-68 bytes) 2014-07-31 20:16:14 +02:00
60c6f2db47 Added operator[] 2014-07-31 20:11:55 +02:00
13c386c7a3 Moved JsonValue to namespace ArduinoJson::Generator 2014-07-31 19:57:52 +02:00
7877ee1b4c Replaced set() by operator=() 2014-07-31 19:48:51 +02:00
2c29327ebd Return a JsonValue& instead of a KeyValuePair* (+40 bytes) 2014-07-31 19:42:09 +02:00
85ffb83aa6 Fixed failing test 2014-07-31 18:50:01 +02:00
1ce6661fa6 Created a failing test 2014-07-31 18:16:04 +02:00
68a2ca905e Updated README.md 2014-07-23 20:18:59 +02:00
7e4ab9f31c Added code size 2014-07-23 13:45:07 +02:00
44e5549456 Added code size 2014-07-23 13:29:56 +02:00
3e36831cdc Updated README.md 2014-07-23 12:56:42 +02:00
5129f3400c Added key() and value() shortcuts 2014-07-23 12:56:29 +02:00
0449ee4fd3 Updated README.md 2014-07-23 12:14:59 +02:00
6e4eb45210 Renamed JsonHashTable into JsonObject 2014-07-22 21:02:16 +02:00
abef85218e Renamed ARDUINO_JSON_NO_DEPRECATED_WARNING into ARDUINO_JSON_NO_DEPRECATION_WARNING 2014-07-22 20:33:17 +02:00
649f292ea7 Added comments 2014-07-22 20:28:59 +02:00
805c0741e6 Added comments 2014-07-22 20:14:25 +02:00
0fc54ba54c Added comments 2014-07-21 20:38:08 +02:00
df72419f09 Added comments 2014-07-21 15:20:02 +02:00
d3d0da2d7f Added comments 2014-07-21 14:17:27 +02:00
407d536e06 Added comments 2014-07-21 14:14:31 +02:00
c22473cf37 Removed unused stuff 2014-07-21 11:08:39 +02:00
3e8861b1a0 Moved implemntation of operator[] into JsonObject 2014-07-21 10:52:35 +02:00
f565a9b1b7 Created a Visual Studio project for JsonGenerator 2014-07-21 09:59:47 +02:00
06026cc7d4 Created a Visual Studio project for JsonParser 2014-07-21 09:54:26 +02:00
04f52733c2 Added a test with 3 strings 2014-07-19 16:15:57 +02:00
c06f42659a Updated README.md 2014-07-19 16:05:42 +02:00
e619b8f5bd Updated README.md 2014-07-19 15:57:03 +02:00
1e28217393 Merged parse() and parseToken() 2014-07-19 15:36:01 +02:00
a1e8c8800a Removed uneeded cast operators 2014-07-19 15:34:44 +02:00
00ad540f4e Updated CHANGELOG.md 2014-07-19 15:23:40 +02:00
cd7a7b1533 Fixed bug in JsonArray::begin() and end() 2014-07-19 14:55:16 +02:00
0fe77176e1 Fixed bug in JsonObject::begin() and end() 2014-07-19 14:49:59 +02:00
e94575b4b8 Replaced public inheritance by protected and private 2014-07-19 14:41:29 +02:00
b278d7711b Replaced composition by inheritance 2014-07-19 12:44:27 +02:00
851d21e08c Added JsonObjectIterator 2014-07-18 22:40:50 +02:00
b75d32e980 Renamed JsonHashTable into JsonObject 2014-07-18 16:46:01 +02:00
daa62b3737 Simplified nextSibling() 2014-07-18 16:22:09 +02:00
ed497df9d6 Added JsonToken.cpp 2014-07-18 16:19:14 +02:00
79953730fc Merged nestedTokenCount() and nextSibling() 2014-07-18 16:18:03 +02:00
5d2ffc49fd Fixed JsonArrayIterator unit test 2014-07-18 16:11:21 +02:00
714a37bd59 Replaced JsonToken operators by meaningful methods 2014-07-18 15:54:49 +02:00
4a1d8483cc Added class JsonToken 2014-07-18 15:43:20 +02:00
0d4d77a7cd Updated example 2014-07-17 14:02:51 +02:00
c329572d24 Added JsonArrayIterator (tests are failing) 2014-07-17 13:58:30 +02:00
ca01ecfb49 Added a flag to ignore deprecation warnings 2014-07-17 13:27:40 +02:00
78249a0ada Updated example 2014-07-17 13:23:32 +02:00
45c9ba1191 Renamed JsonObjectBase into JsonPrintable 2014-07-17 13:16:14 +02:00
5e1697f47b JsonArray is now a simple wrapper on top of JsonValue 2014-07-17 13:12:12 +02:00
f2579397d6 JsonHashTable is now a wrapper on to of JsonValue 2014-07-17 12:59:26 +02:00
b6e3a37ad9 Added JsonParserBase::parse() that returns a JsonValue 2014-07-17 12:37:35 +02:00
73eda08dd4 Updated example 2014-07-16 21:10:18 +02:00
6164328892 Renamed JsonArray::getLength() into size() to match std::vector 2014-07-16 14:01:04 +02:00
7487b8cbb7 Defined the DEPRECATED macro 2014-07-16 13:53:56 +02:00
6a868e46bd Made JsonValue inherit from JsonObjectBase 2014-07-16 13:42:36 +02:00
d189bd7140 Added class JsonValue.
Added subscript operator on JsonArray and JsonHashTable
2014-07-16 13:26:11 +02:00
9f07cdcabf Updated CHANGELOG.md 2014-07-15 20:04:21 +02:00
41b5bba939 Updated CHANGELOG.md 2014-07-15 13:50:49 +02:00
7ac4a91591 Added include of JsonParserBase.cpp 2014-07-15 12:56:14 +02:00
5534635feb Fixed case of jsmn.cpp (issue #6) 2014-07-15 12:54:01 +02:00
2e5b959e8b Fixed GCC warnings 2014-07-14 16:13:58 +02:00
9ee3dc638d Update parser size 2014-07-14 16:02:34 +02:00
ccb97fc6e0 Fixed bug JsonObjectBase::getNestedTokenCount() that reads uninitialized token 2014-07-14 15:52:26 +02:00
39c185ae67 Fixed bug in JsonObjectBase::getBoolFromToken() 2014-07-14 14:50:43 +02:00
cf1324c09b Added a test with too few tokens 2014-07-14 14:46:46 +02:00
0b087b7bdb Added a test when token count is too small 2014-07-14 14:35:51 +02:00
dde5a2510b Extracted class JsonParserBase 2014-07-14 13:17:30 +02:00
a42b03ec26 Rewrote tests on hash tables 2014-07-14 12:29:57 +02:00
2f98e59fc6 Cleaned the array tests 2014-07-14 11:48:46 +02:00
f58a8b0ca5 Renamed unit test classes 2014-07-14 10:33:24 +02:00
80 changed files with 3460 additions and 1440 deletions

View File

@ -7,6 +7,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonGeneratorTests", "JsonG
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonParserTests", "JsonParserTests\JsonParserTests.vcxproj", "{4DD596EF-0185-4AB4-A3C2-F20C496F7806}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonParser", "JsonParser\JsonParser.vcxproj", "{C15274DE-2695-4DFE-8520-4424223FE6DA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonGenerator", "JsonGenerator\JsonGenerator.vcxproj", "{C6536D27-738D-4CEB-A2BC-E13C8897D894}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -21,6 +25,14 @@ Global
{4DD596EF-0185-4AB4-A3C2-F20C496F7806}.Debug|Win32.Build.0 = Debug|Win32
{4DD596EF-0185-4AB4-A3C2-F20C496F7806}.Release|Win32.ActiveCfg = Release|Win32
{4DD596EF-0185-4AB4-A3C2-F20C496F7806}.Release|Win32.Build.0 = Release|Win32
{C15274DE-2695-4DFE-8520-4424223FE6DA}.Debug|Win32.ActiveCfg = Debug|Win32
{C15274DE-2695-4DFE-8520-4424223FE6DA}.Debug|Win32.Build.0 = Debug|Win32
{C15274DE-2695-4DFE-8520-4424223FE6DA}.Release|Win32.ActiveCfg = Release|Win32
{C15274DE-2695-4DFE-8520-4424223FE6DA}.Release|Win32.Build.0 = Release|Win32
{C6536D27-738D-4CEB-A2BC-E13C8897D894}.Debug|Win32.ActiveCfg = Debug|Win32
{C6536D27-738D-4CEB-A2BC-E13C8897D894}.Debug|Win32.Build.0 = Debug|Win32
{C6536D27-738D-4CEB-A2BC-E13C8897D894}.Release|Win32.ActiveCfg = Release|Win32
{C6536D27-738D-4CEB-A2BC-E13C8897D894}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

13
BuildArduinoPackage.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
ZIP="C:\Program Files\7-Zip\7z.exe"
TAG=$(git describe)
OUTPUT="ArduinoJson-$TAG.zip"
cd ..
INPUT=$(find ArduinoJson -regex ".*\.\(cpp\|h\|md\|txt\|ino\)$" -not -regex ".*Tests/.*")
rm -f $OUTPUT
"$ZIP" a $OUTPUT $INPUT

View File

@ -1,10 +1,85 @@
Arduino JSON library: change log
================================
Arduino JSON: change log
========================
v3.4
----
* Fixed escaped char parsing (issue #16)
v3.3
----
* Added indented output for the JSON generator (issue #11), see example bellow.
* Added `IndentedPrint`, a decorator for `Print` to allow indented output
Example:
JsonOject<2> json;
json["key"] = "value";
json.prettyPrintTo(Serial);
v3.2
----
* Fixed a bug when adding nested object in `JsonArray` (bug introduced in v3.1).
v3.1
----
* Calling `Generator::JsonObject::add()` twice with the same `key` now replaces the `value`
* Added `Generator::JsonObject::operator[]`, see bellow the new API
* Added `Generator::JsonObject::remove()` (issue #9)
Old generator API:
JsonObject<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
New generator API:
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
v3.0
----
* New parser API, see bellow
* Renamed `JsonHashTable` into `JsonObject`
* Added iterators for `JsonArray` and `JsonObject` (issue #4)
Old parser API:
JsonHashTable root = parser.parseHashTable(json);
char* sensor = root.getString("sensor");
long time = root.getLong("time");
double latitude = root.getArray("data").getDouble(0);
double longitude = root.getArray("data").getDouble(1);
New parser API:
JsonObject root = parser.parse(json);
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
v2.1
----
* Fixed case `#include "jsmn.cpp"` which caused an error in Linux (issue #6)
* Fixed a buffer overrun in JSON Parser (issue #5)
v2.0
----
* Added JSON encoding.
* Added JSON encoding (issue #2)
* Renamed the library `ArduinoJsonParser` becomes `ArduinoJson`
**Breaking change**: you need to add the following line at the top of your program.
@ -14,7 +89,7 @@ v2.0
v1.2
----
* Example: changed `char[] json` into `char json[]`. Damn it C# !
* Fixed error in JSON parser example (issue #1)
v1.1
----

View File

@ -6,7 +6,10 @@
// This file is here to help the Arduino IDE find the .cpp files
#include "JsonGenerator/EscapedString.cpp"
#include "JsonGenerator/IndentedPrint.cpp"
#include "JsonGenerator/JsonArrayBase.cpp"
#include "JsonGenerator/JsonObjectBase.cpp"
#include "JsonGenerator/JsonValue.cpp"
#include "JsonGenerator/JsonHashTableBase.cpp"
#include "JsonGenerator/JsonPrettyPrint.cpp"
#include "JsonGenerator/JsonPrintable.cpp"
#include "JsonGenerator/StringBuilder.cpp"

View File

@ -4,4 +4,4 @@
*/
#include "JsonGenerator/JsonArray.h"
#include "JsonGenerator/JsonHashTable.h"
#include "JsonGenerator/JsonObject.h"

View File

@ -30,10 +30,8 @@ static inline size_t printCharTo(char c, Print& p)
: p.write(c);
}
size_t EscapedString::printTo(Print& p) const
size_t EscapedString::printTo(const char* s, Print& p)
{
const char* s = rawString;
if (!s) return p.print("null");
size_t n = p.write('\"');

View File

@ -14,16 +14,7 @@ namespace ArduinoJson
class EscapedString
{
public:
void set(const char* s)
{
rawString = s;
}
size_t printTo(Print&) const;
private:
const char* rawString;
static size_t printTo(const char*, Print&);
};
}
}

View File

@ -0,0 +1,45 @@
#include "IndentedPrint.h"
using namespace ArduinoJson::Generator;
void IndentedPrint::indent()
{
if (level < MAX_LEVEL)
level++;
}
void IndentedPrint::unindent()
{
if (level > 0)
level--;
}
void IndentedPrint::setTabSize(uint8_t n)
{
if (n < MAX_TAB_SIZE)
tabSize = n;
}
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;
}

View File

@ -0,0 +1,53 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "Print.h"
namespace ArduinoJson
{
namespace Generator
{
// Decorator on top of Print to allow indented output.
// This class is used by JsonPrintable::prettyPrintTo() but can also be used
// for your own purpose, like logging.
class IndentedPrint : public Print
{
public:
IndentedPrint(Print& p)
: sink(p)
{
level = 0;
tabSize = 2;
isNewLine = true;
}
virtual size_t write(uint8_t);
// Adds one level of indentation
void indent();
// Removes one level of indentation
void unindent();
// Set the number of space printed for each level of indentation
void setTabSize(uint8_t n);
private:
Print& sink;
uint8_t level : 4;
uint8_t tabSize : 3;
bool isNewLine : 1;
size_t writeTabs();
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
};
}
}

View File

@ -22,7 +22,7 @@ namespace ArduinoJson
}
private:
Internals::JsonValue items[N];
JsonValue items[N];
};
}
}

View File

@ -5,27 +5,50 @@
#pragma once
#include "JsonObjectBase.h"
#include "JsonPrintable.h"
#include "JsonValue.h"
namespace ArduinoJson
{
namespace Generator
{
class JsonArrayBase : public JsonObjectBase
class JsonArrayBase : public JsonPrintable
{
public:
JsonArrayBase(Internals::JsonValue* items, int capacity)
JsonArrayBase(JsonValue* items, int capacity)
: items(items), capacity(capacity), count(0)
{
}
template<typename T>
void add(T value)
void add(const Printable& value)
{
if (count >= capacity) return;
addIfPossible<const Printable&>(value);
}
items[count++].set(value);
void add(bool value)
{
addIfPossible<bool>(value);
}
void add(int value)
{
addIfPossible<long>(value);
}
void add(long value)
{
addIfPossible<long>(value);
}
void add(double value)
{
addIfPossible<double>(value);
}
void add(const char* value)
{
addIfPossible<const char*>(value);
}
template<int DIGITS>
@ -33,17 +56,24 @@ namespace ArduinoJson
{
if (count >= capacity) return;
Internals::JsonValue& v = items[count++];
JsonValue& v = items[count++];
v.set<DIGITS>(value);
}
virtual size_t printTo(Print& p) const;
using JsonObjectBase::printTo;
using JsonPrintable::printTo;
private:
Internals::JsonValue* items;
int count, capacity;
JsonValue* items;
int capacity, count;
template<typename T>
void addIfPossible(T value)
{
if (count < capacity)
items[count++] = value;
}
};
}
}

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="EscapedString.h" />
<ClInclude Include="IndentedPrint.h" />
<ClInclude Include="JsonPrettyPrint.h" />
<ClInclude Include="JsonArray.h" />
<ClInclude Include="JsonArrayBase.h" />
<ClInclude Include="JsonObject.h" />
<ClInclude Include="JsonObjectBase.h" />
<ClInclude Include="JsonPrintable.h" />
<ClInclude Include="JsonValue.h" />
<ClInclude Include="Print.h" />
<ClInclude Include="Printable.h" />
<ClInclude Include="StringBuilder.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="EscapedString.cpp" />
<ClCompile Include="IndentedPrint.cpp" />
<ClCompile Include="JsonPrettyPrint.cpp" />
<ClCompile Include="JsonArrayBase.cpp" />
<ClCompile Include="JsonObjectBase.cpp" />
<ClCompile Include="JsonPrintable.cpp" />
<ClCompile Include="JsonValue.cpp" />
<ClCompile Include="Print.cpp" />
<ClCompile Include="StringBuilder.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C6536D27-738D-4CEB-A2BC-E13C8897D894}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>JsonGenerator</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="EscapedString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonArray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonArrayBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonPrintable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonValue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Print.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Printable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StringBuilder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonObjectBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonObject.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IndentedPrint.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonPrettyPrint.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="EscapedString.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonArrayBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StringBuilder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Print.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObjectBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IndentedPrint.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonPrettyPrint.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonPrintable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,27 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonHashTableBase.h"
namespace ArduinoJson
{
namespace Generator
{
template<int N>
class JsonHashTable : public JsonHashTableBase
{
public:
JsonHashTable()
: JsonHashTableBase(items, N)
{
}
private:
KeyValuePair items[N];
};
}
}

View File

@ -1,36 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonHashTable.h"
using namespace ArduinoJson::Generator;
size_t JsonHashTableBase::printTo(Print& p) const
{
size_t n = 0;
n += p.write('{');
// NB: the code has been optimized for a small size on a 8-bit AVR
const KeyValuePair* current = items;
for (int i = count; i > 0; i--)
{
n += current->key.printTo(p);
n += p.write(':');
n += current->value.printTo(p);
current++;
if (i > 1)
{
n += p.write(',');
}
}
n += p.write('}');
return n;
}

View File

@ -1,62 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonObjectBase.h"
#include "EscapedString.h"
namespace ArduinoJson
{
namespace Generator
{
class JsonHashTableBase : public JsonObjectBase
{
public:
template<typename T>
void add(const char* key, T value)
{
if (count >= capacity) return;
items[count].key.set(key);
items[count].value.set(value);
count++;
}
template<int DIGITS>
void add(const char* key, double value)
{
if (count >= capacity) return;
items[count].key.set(key);
items[count].value.set<DIGITS>(value);
count++;
}
using JsonObjectBase::printTo;
virtual size_t printTo(Print& p) const;
protected:
struct KeyValuePair
{
Internals::EscapedString key;
Internals::JsonValue value;
};
JsonHashTableBase(KeyValuePair* items, int capacity)
: items(items), capacity(capacity), count(0)
{
}
private:
KeyValuePair* items;
int count;
int capacity;
};
}
}

View File

@ -0,0 +1,44 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonObjectBase.h"
#ifndef ARDUINO_JSON_NO_DEPRECATION_WARNING
#ifdef __GNUC__
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#endif
#else
#define DEPRECATED
#endif
namespace ArduinoJson
{
namespace Generator
{
template <int N>
class JsonObject : public JsonObjectBase
{
public:
JsonObject()
: JsonObjectBase(items, N)
{
}
private:
KeyValuePair items[N];
};
// Obsolete: use JsonObject instead
template <int N>
class DEPRECATED JsonHashTable : public JsonObject<N>
{
};
}
}

View File

@ -0,0 +1,92 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonObjectBase.h"
#include <string.h> // for strcmp
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
JsonValue JsonObjectBase::nullValue;
size_t JsonObjectBase::printTo(Print& p) const
{
size_t n = 0;
n += p.write('{');
// NB: the code has been optimized for a small size on a 8-bit AVR
const KeyValuePair* current = items;
for (int i = count; i > 0; i--)
{
n += EscapedString::printTo(current->key, p);
n += p.write(':');
n += current->value.printTo(p);
current++;
if (i > 1)
{
n += p.write(',');
}
}
n += p.write('}');
return n;
}
JsonObjectBase::KeyValuePair* JsonObjectBase::getMatchingPair(JsonKey key) const
{
KeyValuePair* p = items;
for (int i = count; i > 0; --i)
{
if (!strcmp(p->key, key))
return p;
p++;
}
return 0;
}
JsonValue& JsonObjectBase::operator[](JsonKey key)
{
KeyValuePair* match = getMatchingPair(key);
if (match)
return match->value;
JsonValue* value;
if (count < capacity)
{
items[count].key = key;
value = &items[count].value;
count++;
}
else
{
value = &nullValue;
}
value->reset();
return *value;
}
bool JsonObjectBase::containsKey(JsonKey key) const
{
return getMatchingPair(key) != 0;
}
void JsonObjectBase::remove(JsonKey key)
{
KeyValuePair* match = getMatchingPair(key);
if (match == 0) return;
*match = items[--count];
}

View File

@ -1,31 +1,62 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonPrintable.h"
#include "JsonValue.h"
#include "Print.h"
#include "Printable.h"
#include "EscapedString.h"
namespace ArduinoJson
{
namespace Generator
{
class JsonObjectBase : public Printable
typedef const char* JsonKey;
class JsonObjectBase : public JsonPrintable
{
public:
JsonValue& operator[](JsonKey);
bool containsKey(JsonKey) const;
void remove(JsonKey key);
size_t printTo(char* buffer, size_t bufferSize)
template<typename T>
void add(JsonKey key, T value)
{
using namespace Internals;
StringBuilder sb(buffer, bufferSize);
return printTo(sb);
operator[](key) = value;
}
virtual size_t printTo(Print& p) const = 0;
template<int DIGITS>
void add(JsonKey key, double value)
{
operator[](key).set<DIGITS>(value);
}
using JsonPrintable::printTo;
virtual size_t printTo(Print& p) const;
protected:
struct KeyValuePair
{
JsonKey key;
JsonValue value;
};
JsonObjectBase(KeyValuePair* items, int capacity)
: items(items), capacity(capacity), count(0)
{
}
private:
KeyValuePair* items;
int capacity, count;
static JsonValue nullValue;
KeyValuePair* getMatchingPair(JsonKey key) const;
};
}
}

View File

@ -0,0 +1,97 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonPrettyPrint.h"
using namespace ArduinoJson::Generator;
size_t JsonPrettyPrint::write(uint8_t c)
{
size_t n = inString ? handleStringChar(c) : handleMarkupChar(c);
previousChar = c;
return n;
}
inline size_t JsonPrettyPrint::handleStringChar(uint8_t c)
{
bool isQuote = c == '"' && previousChar != '\\';
if (isQuote) inString = false;
return sink.write(c);
}
inline size_t JsonPrettyPrint::handleMarkupChar(uint8_t c)
{
switch (c)
{
case '{':
case '[':
return handleBlockOpen(c);
case '}':
case ']':
return handleBlockClose(c);
case ':':
return handleColumn();
case ',':
return handleComma();
case '"':
return handleQuoteOpen();
default:
return handleNormalChar(c);
}
}
inline size_t JsonPrettyPrint::handleBlockOpen(uint8_t c)
{
return indentIfNeeded() + sink.write(c);
}
inline size_t JsonPrettyPrint::handleBlockClose(uint8_t c)
{
return unindentIfNeeded() + sink.write(c);
}
inline size_t JsonPrettyPrint::handleColumn()
{
return sink.write(':') + sink.write(' ');
}
inline size_t JsonPrettyPrint::handleComma()
{
return sink.write(',') + sink.println();
}
inline size_t JsonPrettyPrint::handleQuoteOpen()
{
inString = true;
return indentIfNeeded() + sink.write('"');
}
inline size_t JsonPrettyPrint::handleNormalChar(uint8_t c)
{
return indentIfNeeded() + sink.write(c);
}
size_t JsonPrettyPrint::indentIfNeeded()
{
if (!inEmptyBlock()) return 0;
sink.indent();
return sink.println();
}
size_t JsonPrettyPrint::unindentIfNeeded()
{
if (inEmptyBlock()) return 0;
sink.unindent();
return sink.println();
}

View File

@ -0,0 +1,52 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "Print.h"
#include "IndentedPrint.h"
namespace ArduinoJson
{
namespace Generator
{
// Converts a compact JSON string into an indented one.
class JsonPrettyPrint : public Print
{
public:
JsonPrettyPrint(IndentedPrint& p)
: sink(p)
{
previousChar = 0;
inString = false;
}
virtual size_t write(uint8_t);
private:
uint8_t previousChar;
IndentedPrint& sink;
bool inString;
bool inEmptyBlock()
{
return previousChar == '{' || previousChar == '[';
}
size_t handleStringChar(uint8_t);
size_t handleMarkupChar(uint8_t);
size_t handleBlockClose(uint8_t);
size_t handleBlockOpen(uint8_t);
size_t handleColumn();
size_t handleComma();
size_t handleQuoteOpen();
size_t handleNormalChar(uint8_t);
size_t indentIfNeeded();
size_t unindentIfNeeded();
};
}
}

View File

@ -0,0 +1,35 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonPrintable.h"
#include "JsonPrettyPrint.h"
#include "StringBuilder.h"
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
size_t JsonPrintable::printTo(char* buffer, size_t bufferSize) const
{
StringBuilder sb(buffer, bufferSize);
return printTo(sb);
}
size_t JsonPrintable::prettyPrintTo(char* buffer, size_t bufferSize) const
{
StringBuilder sb(buffer, bufferSize);
return prettyPrintTo(sb);
}
size_t JsonPrintable::prettyPrintTo(IndentedPrint& p) const
{
JsonPrettyPrint prettyPrint(p);
return printTo(prettyPrint);
}
size_t JsonPrintable::prettyPrintTo(Print& p) const
{
IndentedPrint indentedPrint(p);
return prettyPrintTo(indentedPrint);
}

View File

@ -0,0 +1,40 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "Print.h"
#include "Printable.h"
#include "IndentedPrint.h"
namespace ArduinoJson
{
namespace Generator
{
// Contains methods to generate a JSON string.
// Implemented by both JsonObject and JsonArray
class JsonPrintable : public Printable
{
public:
// Generates the compact JSON string and sends it to a Print stream
virtual size_t printTo(Print& p) const = 0;
// Generates the compact JSON string and writes it in a buffer
size_t printTo(char* buffer, size_t bufferSize) const;
// Generates the indented JSON string and sends it to a Print stream
size_t prettyPrintTo(Print& p) const;
// Generates the indented JSON string and sends it to a IndentedPrint stream
// This overload allows a finer control of the output because you can customize
// the IndentedPrint.
size_t prettyPrintTo(IndentedPrint& p) const;
// Generates the indented JSON string and writes it in a buffer
size_t prettyPrintTo(char* buffer, size_t bufferSize) const;
};
}
}

View File

@ -6,6 +6,7 @@
#include "EscapedString.h"
#include "JsonValue.h"
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
size_t JsonValue::printBoolTo(const Content& c, Print& p)
@ -28,5 +29,5 @@ size_t JsonValue::printPrintableTo(const Content& c, Print& p)
size_t JsonValue::printStringTo(const Content& c, Print& p)
{
return c.asString.printTo(p);
return EscapedString::printTo(c.asString, p);
}

View File

@ -11,68 +11,109 @@
namespace ArduinoJson
{
namespace Internals
namespace Generator
{
class JsonValue
{
public:
void set(bool value)
void operator=(bool value)
{
printToImpl = &printBoolTo;
content.asBool = value;
}
void set(long value)
void operator=(long value)
{
printToImpl = &printLongTo;
content.asLong = value;
}
void set(int value)
void operator=(int value)
{
printToImpl = &printLongTo;
content.asLong = value;
}
void set(Printable& value)
void operator=(const Printable& value)
{
printToImpl = &printPrintableTo;
content.asPrintable = &value;
}
void set(const char* value)
void operator=(const char* value)
{
printToImpl = &printStringTo;
content.asString.set(value);
content.asString = value;
}
void set(double value)
void operator=(double value)
{
set<2>(value);
}
template<int DIGITS>
template <int DIGITS>
void set(double value)
{
printToImpl = &printDoubleTo<DIGITS>;
printToImpl = &printDoubleTo < DIGITS > ;
content.asDouble = value;
}
operator bool()
{
return content.asBool;
}
operator const char*()
{
return content.asString;
}
operator double()
{
return content.asDouble;
}
operator float()
{
return (float)content.asDouble;
}
operator int()
{
return content.asLong;
}
operator long()
{
return content.asLong;
}
operator const Printable&()
{
return *content.asPrintable;
}
size_t printTo(Print& p) const
{
// handmade polymorphism
return printToImpl(content, p);
}
void reset()
{
content.asDouble = 0;
printToImpl = printStringTo;
}
private:
union Content
{
bool asBool;
long asLong;
Printable* asPrintable;
EscapedString asString;
double asDouble;
bool asBool;
double asDouble;
long asLong;
const Printable* asPrintable;
const char* asString;
};
Content content;
@ -84,7 +125,7 @@ namespace ArduinoJson
static size_t printPrintableTo(const Content&, Print&);
static size_t printStringTo(const Content&, Print&);
template<int DIGITS>
template <int DIGITS>
static size_t printDoubleTo(const Content& c, Print& p)
{
return p.print(c.asDouble, DIGITS);

View File

@ -32,4 +32,9 @@ size_t Print::print(long value)
return print(tmp);
}
size_t Print::println()
{
return write('\r') + write('\n');
}
#endif

View File

@ -19,6 +19,7 @@ public:
size_t print(const char[]);
size_t print(double, int = 2);
size_t print(long);
size_t println();
};
#else

View File

@ -1,9 +1,9 @@
Arduino JSON library - Generator
================================
This library is a simple JSON encoder for embedded systems.
*An elegant and efficient JSON encoder for embedded systems.*
It's design to be very lightweight, works without any allocation on the heap (no malloc) and supports nested objects.
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
@ -11,11 +11,12 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari
Features
--------
* Supports nested objects
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
* Implements Arduino's Printable interface
* Supports nested objects
* Supports indented output
* Implements Arduino's `Printable interface
* MIT License
@ -23,13 +24,13 @@ Example
-------
JsonArray<2> array;
array.add<6>(48.756080);
array.add<6>(2.302038);
array.add<6>(48.756080); // <6> specifies the number of digits in the output
array.add<6>(2.302038); // (the default is 2)
JsonHashTable<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
@ -50,12 +51,19 @@ Just add the following lines at the top of your `.ino` file:
#include <JsonGenerator.h>
using namespace ArduinoJson::Generator;
> ##### Having a namespace conflict?
> To be able to use both `ArduinoJson::Generator` and `ArduinoJson::Parser` in the same file, you need to do one of the followings:
>
> * Put the `using` statements into different functions
> * `using namespace ArduinoJson`, then prefix the type names by `Generator::` or `Parser::`
> * Create aliases for the namespaces or the types (C++11 only)
### 3. Create object tree
In order to generate a JSON string, you need to build the equivalent object tree. You usually start by the root which can be either an array or an hash-table.
In order to generate a JSON string, you need to build the equivalent object tree. You usually start by the root which can be either a JSON Array or a JSON Object.
#### Array
#### JSON Array
You create an array with the following line:
@ -73,7 +81,7 @@ Then you can add strings, integer, booleans, etc:
array.add(42);
array.add(true);
There are two syntaxes for the floating point values:
There are two syntaxes for floating point values:
array.add<4>(3.1415); // 4 digits: "3.1415"
array.add(3.14); // 2 digits: "3.14"
@ -91,37 +99,69 @@ Finally you can add nested object to the array:
or
JsonHashTable<8> nestedHash;
array.add(nestedHash);
JsonObject<8> nestedObject;
array.add(nestedObject);
#### Hash-table
> ##### CAUTION! Nested objects must be in memory
> Calling `add()` makes the `JsonArray` store a pointer to the nested object.
> This is designed to avoid memory duplication.
> But it can only work if the object is in memory when `printTo()` is executed.
> For instance, don't do this:
>
> void addNestedObject()
> {
> JsonObject<2> nestedObject;
> // ...
> array.add(nestedObject); // <- DON'T !!
>
> // array now contains a pointer to a local variable that will be
> // discarded as soon as the function exits
> }
>
> For the same reason, don't do this either:
>
> for( int i=0; i<100; i++)
> {
> JsonObject<2> nestedObject;
> // ...
> array.add(nestedObject); // <- DON'T !!
> }
> // array now contains 100 pointers to the same a local variable
> // that is out of the scope anyway
You create a hash-table with the following line:
#### JSON Object
JsonHashTable<8> hash;
You create a JSON object (ie hash-table/dictionary) with the following line:
Like with the array class, there is a template parameter that gives the capacity of the hash-table.
JsonObject<8> object;
Like with the array class, there is a template parameter that gives the capacity of the object.
Then you can add strings, integer, booleans, etc:
hash.add("key1", "bazinga!");
hash.add("key2", 42);
hash.add("key3", true);
object["key1"] = "bazinga!";
object["key2"] = 42;
object["key3"] = true;
As for the arrays, there are two syntaxes for the floating point values:
array.add<4>("key4", 3.1415); // 4 digits: "3.1415"
array.add("key5", 3.14); // 2 digits: "3.14"
object["key4"].set<4>(3.1415); // 4 digits "3.1415"
object["key5"] = 3.1415; // default: 2 digits "3.14"
Finally you can add nested objects:
JsonArray<8> nestedArray;
hash.add("key6", nestedArray);
object["key6"] = nestedArray;
or
JsonHashTable<8> nestedHash;
hash.add("key7", nestedHash);
JsonObject<8> nestedObject;
object["key7"] = nestedObject;
> ##### Other JsonObject functions
> * `object.add(key, value)` is a synonym for `object[key] = value`
> * `object.containsKey(key)` returns `true` is the `key` is present in `object`
> * `object.remove(key)` removes the `value` associated with `key`
### 4. Get the JSON string
@ -133,11 +173,18 @@ Both ways are the easy way :-)
#### Use a classic `char[]`
Whether you have a `JsonArray` or a `JsonHashTable`, simply call `printTo()` with the destination buffer, like so:
Whether you have a `JsonArray` or a `JsonObject`, simply call `printTo()` with the destination buffer, like so:
char buffer[256];
array.printTo(buffer, sizeof(buffer));
> ##### Want an indented output?
> By default the generated JSON is as small as possible. It contains no extra space, nor line break.
> But if you want an indented, more readable output, you can.
> Simply call `prettyPrintTo` instead of `printTo()`:
>
> array.prettyPrintTo(buffer, sizeof(buffer));
#### Send to a stream
It's very likely that the generated JSON will end up in a stream like `Serial` or `EthernetClient `, so you can save some time and memory by doing this:
@ -149,9 +196,9 @@ or
array.printTo(Serial);
> ##### About the Printable interface
> `JsonArray` and `JsonHashTable` implement Arduino's `Printable` interface.
> `JsonArray` and `JsonObject` implement Arduino's `Printable` interface.
> This is why you can call `Serial.print()` like in the example above.
> You can do the same with any other implementation of `Print`: `HardwareSerial`, `SoftwareSerial`, `LiquidCrystal`, `EthernetClient`, `WiFiClient`...
> You can do the same with any other implementation of `Print`: `HardwareSerial`, `SoftwareSerial`, `LiquidCrystal`, `EthernetClient`, `WiFiClient`, `Wire`...
Memory usage
@ -161,7 +208,40 @@ Here are the size of the main classes of the library.
This table is for an 8-bit Arduino, types would be bigger on a 32-bit processor.
| Type | Size in bytes |
| ---------------------- | ------------- |
| JsonArray&lt;N&gt; | 8 + 6 x N |
| JsonHashTable&lt;N&gt; | 8 + 8 x N |
| Type | Size in bytes |
| --------------------| ------------- |
| JsonArray&lt;N&gt; | 8 + 6 x N |
| JsonObject&lt;N&gt; | 8 + 8 x N |
Code size
---------
The following values has been obtained with Arduino IDE 1.0.5, targeting an Arduino Duelmilanove with an ATmega 328.
### Minimum setup
| Function | Size |
| ----------------------------------- | ---- |
| `JsonObjectBase::printTo()` | 234 |
| `EscapedString::printTo()` | 196 |
| `JsonArrayBase::printTo()` | 164 |
| `Print::print(char const*)` | 146 |
| `JsonObjectBase::operator[]` | 114 |
| `JsonObjectBase::getMatchingPair()` | 72 |
| `JsonValue::printPrintableTo()` | 40 |
| `JsonValue::printStringTo()` | 12 |
### Additional space for integers
| Function | Size |
| ---------------------------- | ---- |
| `Print::print(long, int)` | 328 |
| `JsonValue::printLongTo()` | 22 |
### Additional space for floating point
| Function | Size |
| ------------------------------ | ---- |
| `Print::print(double, int)` | 1548 |
| `JsonValue::printDouleTo<2>()` | 22 |

View File

@ -16,8 +16,7 @@ namespace JsonGeneratorTests
{
char buffer[1024];
size_t returnValue;
EscapedString escapedString;
public:
TEST_METHOD(Null)
@ -83,9 +82,8 @@ namespace JsonGeneratorTests
private:
void whenInputIs(const char* input)
{
StringBuilder sb(buffer, sizeof(buffer));
escapedString.set(input);
returnValue = escapedString.printTo(sb);
StringBuilder sb(buffer, sizeof(buffer));
returnValue = EscapedString::printTo(input, sb);
}
void outputMustBe(const char* expected)

View File

@ -0,0 +1,73 @@
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace ArduinoJson::Generator;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace JsonGeneratorTests
{
TEST_CLASS(Issue10)
{
struct Person {
int id;
char name[32];
};
Person persons[2];
public:
TEST_METHOD_INITIALIZE(Initialize)
{
Person boss;
boss.id = 1;
strcpy(boss.name, "Jeff");
Person employee;
employee.id = 2;
strcpy(employee.name, "John");
persons[0] = boss;
persons[1] = employee;
}
TEST_METHOD(WrongWayToAddObjectInAnArray)
{
JsonArray<2> json;
for (int i = 0; i < 2; i++)
{
JsonObject<2> object;
object["id"] = persons[i].id;
object["name"] = persons[i].name;
json.add(object); // <- Adding a reference to a temporary variable
}
char buffer[256];
json.printTo(buffer, sizeof(buffer));
// the same values are repeated, that's normal
Assert::AreEqual("[{\"id\":2,\"name\":\"John\"},{\"id\":2,\"name\":\"John\"}]", buffer);
}
TEST_METHOD(RightWayToAddObjectInAnArray)
{
JsonArray<2> json;
JsonObject<2> object[2];
for (int i = 0; i < 2; i++)
{
object[i]["id"] = persons[i].id;
object[i]["name"] = persons[i].name;
json.add(object[i]);
}
char buffer[256];
json.printTo(buffer, sizeof(buffer));
Assert::AreEqual("[{\"id\":1,\"name\":\"Jeff\"},{\"id\":2,\"name\":\"John\"}]", buffer);
}
};
}

View File

@ -5,7 +5,7 @@
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonHashTable.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
@ -14,7 +14,7 @@ namespace JsonGeneratorTests
{
TEST_CLASS(JsonArrayTests)
{
JsonArray<2> arr;
JsonArray<2> array;
char buffer[256];
public:
@ -26,111 +26,117 @@ namespace JsonGeneratorTests
TEST_METHOD(Null)
{
add((char*)0);
array.add((char*) 0);
outputMustBe("[null]");
}
TEST_METHOD(OneString)
{
add("hello");
array.add("hello");
outputMustBe("[\"hello\"]");
}
TEST_METHOD(TwoStrings)
{
add("hello");
add("world");
array.add("hello");
array.add("world");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneStringOverCapacity)
{
add("hello");
add("world");
add("lost");
array.add("hello");
array.add("world");
array.add("lost");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
add(3.14159265358979323846);
array.add(3.14159265358979323846);
outputMustBe("[3.14]");
}
TEST_METHOD(OneDoubleFourDigits)
{
add<4>(3.14159265358979323846);
array.add<4>(3.14159265358979323846);
outputMustBe("[3.1416]");
}
TEST_METHOD(OneInteger)
{
add(1);
array.add(1);
outputMustBe("[1]");
}
TEST_METHOD(TwoIntegers)
{
add(1);
add(2);
array.add(1);
array.add(2);
outputMustBe("[1,2]");
}
TEST_METHOD(OneIntegerOverCapacity)
{
add(1);
add(2);
add(3);
array.add(1);
array.add(2);
array.add(3);
outputMustBe("[1,2]");
}
TEST_METHOD(OneTrue)
{
add(true);
array.add(true);
outputMustBe("[true]");
}
TEST_METHOD(OneFalse)
{
add(false);
array.add(false);
outputMustBe("[false]");
}
TEST_METHOD(TwoBooleans)
{
add(false);
add(true);
array.add(false);
array.add(true);
outputMustBe("[false,true]");
}
TEST_METHOD(OneBooleanOverCapacity)
{
add(false);
add(true);
add(false);
array.add(false);
array.add(true);
array.add(false);
outputMustBe("[false,true]");
}
TEST_METHOD(OneEmptyNestedArray)
{
addNested(JsonArray<1>());
JsonArray<1> nestedArray;
array.add(nestedArray);
outputMustBe("[[]]");
}
TEST_METHOD(OneEmptyNestedHash)
{
addNested(JsonHashTable<1>());
JsonObject<1> nestedObject;
array.add(nestedObject);
outputMustBe("[{}]");
}
@ -139,33 +145,16 @@ namespace JsonGeneratorTests
JsonArray<1> nestedArray;
nestedArray.add(1);
addNested(nestedArray);
array.add(nestedArray);
outputMustBe("[[1]]");
}
private:
void addNested(JsonObjectBase& value)
{
arr.add<JsonObjectBase&>(value);
}
template<typename T>
void add(T value)
{
arr.add(value);
}
template<int DIGITS>
void add(double value)
{
arr.add<DIGITS>(value);
}
void outputMustBe(const char* expected)
{
size_t n = arr.printTo(buffer, sizeof(buffer));
size_t n = array.printTo(buffer, sizeof(buffer));
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), n);
}

View File

@ -55,7 +55,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>ARDUINO_JSON_NO_DEPRECATION_WARNING;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
@ -84,29 +84,22 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\JsonGenerator\EscapedString.cpp" />
<ClCompile Include="..\JsonGenerator\JsonArrayBase.cpp" />
<ClCompile Include="..\JsonGenerator\JsonHashTableBase.cpp" />
<ClCompile Include="..\JsonGenerator\JsonValue.cpp" />
<ClCompile Include="..\JsonGenerator\StringBuilder.cpp" />
<ClCompile Include="EscapedStringTests.cpp" />
<ClCompile Include="PrettyPrint_Array_Tests.cpp" />
<ClCompile Include="PrettyPrint_Object_Tests.cpp" />
<ClCompile Include="PrettyPrint_String_Tests.cpp" />
<ClCompile Include="Issue10.cpp" />
<ClCompile Include="JsonArrayTests.cpp" />
<ClCompile Include="JsonHashTableTests.cpp" />
<ClCompile Include="JsonValueTests.cpp" />
<ClCompile Include="Print.cpp" />
<ClCompile Include="JsonObject_Indexer_Tests.cpp" />
<ClCompile Include="JsonObject_PrintTo_Tests.cpp" />
<ClCompile Include="JsonValue_Cast_Tests.cpp" />
<ClCompile Include="JsonValue_PrintTo_Tests.cpp" />
<ClCompile Include="StringBuilderTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\JsonGenerator\EscapedString.h" />
<ClInclude Include="..\JsonGenerator\JsonArray.h" />
<ClInclude Include="..\JsonGenerator\JsonArrayBase.h" />
<ClInclude Include="..\JsonGenerator\JsonHashTable.h" />
<ClInclude Include="..\JsonGenerator\JsonHashTableBase.h" />
<ClInclude Include="..\JsonGenerator\JsonObjectBase.h" />
<ClInclude Include="..\JsonGenerator\JsonValue.h" />
<ClInclude Include="..\JsonGenerator\Print.h" />
<ClInclude Include="..\JsonGenerator\Printable.h" />
<ClInclude Include="..\JsonGenerator\StringBuilder.h" />
<ProjectReference Include="..\JsonGenerator\JsonGenerator.vcxproj">
<Project>{c6536d27-738d-4ceb-a2bc-e13c8897d894}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -18,67 +18,35 @@
<ClCompile Include="JsonArrayTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonHashTableTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValueTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonGenerator\JsonValue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonGenerator\StringBuilder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StringBuilderTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Print.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonGenerator\EscapedString.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonGenerator\JsonHashTableBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonGenerator\JsonArrayBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EscapedStringTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\JsonGenerator\JsonArray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\JsonHashTable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\JsonObjectBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\JsonValue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\Print.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\Printable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\StringBuilder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\EscapedString.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\JsonHashTableBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonGenerator\JsonArrayBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClCompile Include="JsonObject_PrintTo_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObject_Indexer_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue_PrintTo_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue_Cast_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Issue10.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PrettyPrint_Array_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PrettyPrint_Object_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PrettyPrint_String_Tests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,124 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonHashTable.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonHashTableTests)
{
JsonHashTable<2> hash;
char buffer[256];
public:
TEST_METHOD(Empty)
{
outputMustBe("{}");
}
TEST_METHOD(OneString)
{
add("key", "value");
outputMustBe("{\"key\":\"value\"}");
}
TEST_METHOD(TwoStrings)
{
add("key1", "value1");
add("key2", "value2");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneStringOverCapacity)
{
add("key1", "value1");
add("key2", "value2");
add("key3", "value3");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneInteger)
{
add("key", 1);
outputMustBe("{\"key\":1}");
}
TEST_METHOD(OneDoubleFourDigits)
{
add<4>("key", 3.14159265358979323846);
outputMustBe("{\"key\":3.1416}");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
add("key", 3.14159265358979323846);
outputMustBe("{\"key\":3.14}");
}
TEST_METHOD(OneNull)
{
add("key", (char*) 0);
outputMustBe("{\"key\":null}");
}
TEST_METHOD(OneTrue)
{
add("key", true);
outputMustBe("{\"key\":true}");
}
TEST_METHOD(OneFalse)
{
add("key", false);
outputMustBe("{\"key\":false}");
}
TEST_METHOD(OneEmptyNestedArray)
{
addNested("key", JsonArray<1>());
outputMustBe("{\"key\":[]}");
}
TEST_METHOD(OneEmptyNestedHash)
{
addNested("key", JsonHashTable<1>());
outputMustBe("{\"key\":{}}");
}
private:
void addNested(const char* key, JsonObjectBase& value)
{
hash.add<JsonObjectBase&>(key, value);
}
template<typename T>
void add(const char* key, T value)
{
hash.add(key, value);
}
template<int DIGITS>
void add(const char* key, double value)
{
hash.add<DIGITS>(key, value);
}
void outputMustBe(const char* expected)
{
size_t actual = hash.printTo(buffer, sizeof(buffer));
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), actual);
}
};
}

View File

@ -0,0 +1,73 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonObject_Indexer_Tests)
{
JsonObject<2> object;
public:
TEST_METHOD(Empty)
{
mustNotContain("key");
}
TEST_METHOD(TwoStrings)
{
object["key1"] = "value1";
object["key2"] = "value2";
mustContain("key1", "value1");
mustContain("key2", "value2");
}
TEST_METHOD(RemoveFirst)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key1");
mustNotContain("key1");
mustContain("key2", "value2");
}
TEST_METHOD(RemoveLast)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key2");
mustContain("key1", "value1");
mustNotContain("key2");
}
private:
void mustContain(const char* key, const char* expected)
{
Assert::IsTrue(object.containsKey(key));
const char* actual = object[key];
Assert::AreEqual(expected, actual);
}
void mustNotContain(const char* key)
{
Assert::IsFalse(object.containsKey(key));
const char* actual = object[key];
Assert::IsNull(actual);
}
};
}

View File

@ -0,0 +1,152 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonArray.h"
#include "JsonObject.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonObject_PrintTo_Tests)
{
JsonObject<2> object;
public:
TEST_METHOD(Empty)
{
outputMustBe("{}");
}
TEST_METHOD(OneString)
{
object["key"] = "value";
outputMustBe("{\"key\":\"value\"}");
}
TEST_METHOD(TwoStrings)
{
object["key1"] = "value1";
object["key2"] = "value2";
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(RemoveFirst)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key1");
outputMustBe("{\"key2\":\"value2\"}");
}
TEST_METHOD(RemoveLast)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key2");
outputMustBe("{\"key1\":\"value1\"}");
}
TEST_METHOD(RemoveUnexistingKey)
{
object["key1"] = "value1";
object["key2"] = "value2";
object.remove("key3");
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(ReplaceExistingKey)
{
object["key"] = "value1";
object["key"] = "value2";
outputMustBe("{\"key\":\"value2\"}");
}
TEST_METHOD(OneStringOverCapacity)
{
object["key1"] = "value1";
object["key2"] = "value2";
object["key3"] = "value3";
outputMustBe("{\"key1\":\"value1\",\"key2\":\"value2\"}");
}
TEST_METHOD(OneInteger)
{
object["key"] = 1;
outputMustBe("{\"key\":1}");
}
TEST_METHOD(OneDoubleFourDigits)
{
object["key"].set<4>(3.14159265358979323846);
outputMustBe("{\"key\":3.1416}");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
object["key"] = 3.14159265358979323846;
outputMustBe("{\"key\":3.14}");
}
TEST_METHOD(OneNull)
{
object["key"] = (char*) 0;
outputMustBe("{\"key\":null}");
}
TEST_METHOD(OneTrue)
{
object["key"] = true;
outputMustBe("{\"key\":true}");
}
TEST_METHOD(OneFalse)
{
object["key"] = false;
outputMustBe("{\"key\":false}");
}
TEST_METHOD(OneEmptyNestedArray)
{
auto nestedArray = JsonArray<1>();
object["key"] = nestedArray;
outputMustBe("{\"key\":[]}");
}
TEST_METHOD(OneEmptyNestedObject)
{
auto nestedObject = JsonObject<1>();
object["key"] = nestedObject;
outputMustBe("{\"key\":{}}");
}
private:
void outputMustBe(const char* expected)
{
char buffer[256];
size_t result;
result = object.printTo(buffer, sizeof(buffer));
Assert::AreEqual(strlen(expected), result);
Assert::AreEqual(expected, buffer);
}
};
}

View File

@ -0,0 +1,78 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "StringBuilder.h"
#include "JsonValue.h"
#include "JsonArray.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonValue_Cast_Tests)
{
JsonValue value;
public:
TEST_METHOD(Bool)
{
setValueAndCheckCast(true);
setValueAndCheckCast(false);
}
TEST_METHOD(Double)
{
setValueAndCheckCast(3.14156);
}
TEST_METHOD(Float)
{
setValueAndCheckCast(3.14f);
}
TEST_METHOD(Integer)
{
setValueAndCheckCast(42);
}
TEST_METHOD(Long)
{
setValueAndCheckCast(42L);
}
TEST_METHOD(Array)
{
JsonArray<2> array;
setValueAndCheckCast(array);
}
TEST_METHOD(String)
{
setValueAndCheckCast("hello");
}
private:
template<typename T>
void setValueAndCheckCast(T expected)
{
value = expected;
T actual = value;
Assert::AreEqual(expected, actual);
}
template<int N>
void setValueAndCheckCast(JsonArray<N>& expected)
{
value = expected;
const Printable& actual = value;
Assert::AreEqual((void*) &expected, (void*) &actual);
}
};
}

View File

@ -8,11 +8,12 @@
#include "JsonValue.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonValueTests)
TEST_CLASS(JsonValue_PrintTo_Tests)
{
char buffer[1024];
size_t returnValue;
@ -21,62 +22,62 @@ namespace JsonGeneratorTests
TEST_METHOD(String)
{
whenInputIs("hello");
setValueTo("hello");
outputMustBe("\"hello\"");
}
TEST_METHOD(Float)
{
whenInputIs(3.1415f);
setValueTo(3.1415f);
outputMustBe("3.14");
}
TEST_METHOD(DoubleZeroDigits)
{
whenInputIs<0>(3.14159265358979323846);
setValueTo<0>(3.14159265358979323846);
outputMustBe("3");
}
TEST_METHOD(DoubleOneDigit)
{
whenInputIs<1>(3.14159265358979323846);
setValueTo<1>(3.14159265358979323846);
outputMustBe("3.1");
}
TEST_METHOD(DoubleTwoDigits)
{
whenInputIs<2>(3.14159265358979323846);
setValueTo<2>(3.14159265358979323846);
outputMustBe("3.14");
}
TEST_METHOD(Integer)
{
whenInputIs(314);
setValueTo(314);
outputMustBe("314");
}
TEST_METHOD(Char)
{
whenInputIs('A');
setValueTo('A');
outputMustBe("65");
}
TEST_METHOD(Short)
{
whenInputIs((short)314);
setValueTo((short)314);
outputMustBe("314");
}
TEST_METHOD(Long)
{
whenInputIs(314159265L);
setValueTo(314159265L);
outputMustBe("314159265");
}
private:
template<int DIGITS>
void whenInputIs(double value)
void setValueTo(double value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
@ -85,11 +86,11 @@ namespace JsonGeneratorTests
}
template<typename T>
void whenInputIs(T value)
void setValueTo(T value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
jsonValue.set(value);
jsonValue = value;
returnValue = jsonValue.printTo(sb);
}

View File

@ -0,0 +1,91 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonPrettyPrint.h"
#include "StringBuilder.h"
using namespace ArduinoJson::Internals;
using namespace ArduinoJson::Generator;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace JsonGeneratorTests
{
TEST_CLASS(PrettyPrint_Array_Tests)
{
char buffer[1024];
size_t returnValue;
public:
TEST_METHOD(EmptyArray)
{
whenInputIs("[]");
outputMustBe("[]");
}
TEST_METHOD(OneElement)
{
whenInputIs("[1]");
outputMustBe(
"[\r\n"
" 1\r\n"
"]");
}
TEST_METHOD(TwoElements)
{
whenInputIs("[1,2]");
outputMustBe(
"[\r\n"
" 1,\r\n"
" 2\r\n"
"]");
}
TEST_METHOD(EmptyNestedArrays)
{
whenInputIs("[[],[]]");
outputMustBe(
"[\r\n"
" [],\r\n"
" []\r\n"
"]");
}
TEST_METHOD(NestedArrays)
{
whenInputIs("[[1,2],[3,4]]");
outputMustBe(
"[\r\n"
" [\r\n"
" 1,\r\n"
" 2\r\n"
" ],\r\n"
" [\r\n"
" 3,\r\n"
" 4\r\n"
" ]\r\n"
"]");
}
private:
void whenInputIs(const char input[])
{
StringBuilder sb(buffer, sizeof(buffer));
IndentedPrint indentedPrint(sb);
JsonPrettyPrint decorator(indentedPrint);
returnValue = decorator.print(input);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), returnValue);
}
};
}

View File

@ -0,0 +1,89 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonPrettyPrint.h"
#include "StringBuilder.h"
using namespace ArduinoJson::Internals;
using namespace ArduinoJson::Generator;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace JsonGeneratorTests
{
TEST_CLASS(PrettyPrint_Object_Tests)
{
char buffer[1024];
size_t returnValue;
public:
TEST_METHOD(EmptyObject)
{
whenInputIs("{}");
outputMustBe("{}");
}
TEST_METHOD(OneMember)
{
whenInputIs("{\"key\":\"value\"}");
outputMustBe(
"{\r\n"
" \"key\": \"value\"\r\n"
"}");
}
TEST_METHOD(TwoMembers)
{
whenInputIs("{\"key1\":\"value1\",\"key2\":\"value2\"}");
outputMustBe(
"{\r\n"
" \"key1\": \"value1\",\r\n"
" \"key2\": \"value2\"\r\n"
"}");
}
TEST_METHOD(EmptyNestedObjects)
{
whenInputIs("{\"key1\":{},\"key2\":{}}");
outputMustBe(
"{\r\n"
" \"key1\": {},\r\n"
" \"key2\": {}\r\n"
"}");
}
TEST_METHOD(NestedObjects)
{
whenInputIs("{\"key1\":{\"a\":1},\"key2\":{\"b\":2}}");
outputMustBe(
"{\r\n"
" \"key1\": {\r\n"
" \"a\": 1\r\n"
" },\r\n"
" \"key2\": {\r\n"
" \"b\": 2\r\n"
" }\r\n"
"}");
}
private:
void whenInputIs(const char input[])
{
StringBuilder sb(buffer, sizeof(buffer));
IndentedPrint indentedPrint(sb);
JsonPrettyPrint decorator(indentedPrint);
returnValue = decorator.print(input);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), returnValue);
}
};
}

View File

@ -0,0 +1,76 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonPrettyPrint.h"
#include "StringBuilder.h"
using namespace ArduinoJson::Internals;
using namespace ArduinoJson::Generator;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace JsonGeneratorTests
{
TEST_CLASS(PrettyPrint_String_Tests)
{
char buffer[1024];
size_t returnValue;
public:
TEST_METHOD(EmptyString)
{
whenInputIs("");
outputMustBe("");
}
TEST_METHOD(TrickyCharacters)
{
whenInputIs ("\":\\\"',\"");
outputMustBe("\":\\\"',\"");
}
TEST_METHOD(OpeningCurlyBrace)
{
whenInputIs ("\"{\"");
outputMustBe("\"{\"");
}
TEST_METHOD(OpeningSquareBrace)
{
whenInputIs("\"[\"");
outputMustBe("\"[\"");
}
TEST_METHOD(ClosingCurlyBrace)
{
whenInputIs("\"}\"");
outputMustBe("\"}\"");
}
TEST_METHOD(ClosingSquareBrace)
{
whenInputIs("\"]\"");
outputMustBe("\"]\"");
}
private:
void whenInputIs(const char input[])
{
StringBuilder sb(buffer, sizeof(buffer));
IndentedPrint indentedPrint(sb);
JsonPrettyPrint decorator(indentedPrint);
returnValue = decorator.print(input);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), returnValue);
}
};
}

View File

@ -1,11 +1,13 @@
/*
* malloc-free JSON parser for Arduino
* Benoit Blanchon 2014 - MIT License
*/
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
// This file is here to help the Arduino IDE find the .cpp files
#include "JsonParser/JsonArray.cpp"
#include "JsonParser/JsonHashTable.cpp"
#include "JsonParser/JsonObjectBase.cpp"
#include "JsonParser/Jsmn.cpp"
#include "JsonParser/JsonObject.cpp"
#include "JsonParser/JsonParserBase.cpp"
#include "JsonParser/JsonValue.cpp"
#include "JsonParser/JsonToken.cpp"
#include "JsonParser/jsmn.cpp"

View File

@ -4,66 +4,11 @@
*/
#include "JsonArray.h"
#include "JsonHashTable.h"
#include "JsonObject.h"
using namespace ArduinoJson::Parser;
JsonArray::JsonArray(char* json, jsmntok_t* tokens)
: JsonObjectBase(json, tokens)
DEPRECATED JsonObject JsonArray::getHashTable(int index)
{
if (tokens == 0 || tokens[0].type != JSMN_ARRAY)
makeInvalid();
}
/*
* Returns the token for the value at the specified index
*/
jsmntok_t* JsonArray::getToken(int index)
{
// sanity check
if (json == 0 || tokens == 0 || index < 0 || index >= tokens[0].size)
return 0;
// skip first token, it's the whole object
jsmntok_t* currentToken = tokens + 1;
// skip all tokens before the specified index
for (int i = 0; i < index; i++)
{
// move forward: current + nested tokens
currentToken += 1 + getNestedTokenCount(currentToken);
}
return currentToken;
}
JsonArray JsonArray::getArray(int index)
{
return JsonArray(json, getToken(index));
}
bool JsonArray::getBool(int index)
{
return getBoolFromToken(getToken(index));
}
double JsonArray::getDouble(int index)
{
return getDoubleFromToken(getToken(index));
}
JsonHashTable JsonArray::getHashTable(int index)
{
return JsonHashTable(json, getToken(index));
}
long JsonArray::getLong(int index)
{
return getLongFromToken(getToken(index));
}
char* JsonArray::getString(int index)
{
return getStringFromToken(getToken(index));
return operator[](index);
}

View File

@ -5,41 +5,99 @@
#pragma once
#include "JsonObjectBase.h"
#include "JsonValue.h"
#include "JsonArrayIterator.h"
namespace ArduinoJson
{
namespace Parser
{
class JsonHashTable;
class JsonArray : public JsonObjectBase
{
template <int N>
friend class JsonParser;
friend class JsonHashTable;
class JsonObject;
// A JSON array
class JsonArray : JsonValue
{
public:
JsonArray() {}
int getLength()
// Create an invalid array
JsonArray()
{
}
// Convert a JsonValue into a JsonArray
JsonArray(JsonValue value)
: JsonValue(value)
{
return tokens != 0 ? tokens[0].size : 0;
}
// Tell if the array is valid
bool success()
{
return isArray();
}
// Get the JsonValue at specified index
JsonValue operator[](int index)
{
return JsonValue::operator[](index);
}
// Get the size of the array
int size()
{
return isArray() ? childrenCount() : 0;
}
// Get an iterator pointing to the beginning of the array
JsonArrayIterator begin()
{
return isArray() ? firstChild() : null();
}
// Gets an iterator pointing to the end of the array
JsonArrayIterator end()
{
return isArray() ? nextSibling() : null();
}
// Obsolete: Use size() instead
DEPRECATED int getLength()
{
return size();
}
// Obsolete: Use operator[] instead
DEPRECATED JsonArray getArray(int index)
{
return operator[](index);
}
JsonArray getArray(int index);
bool getBool(int index);
double getDouble(int index);
JsonHashTable getHashTable(int index);
long getLong(int index);
char* getString(int index);
// Obsolete: Use operator[] instead
DEPRECATED bool getBool(int index)
{
return operator[](index);
}
private:
// Obsolete: Use operator[] instead
DEPRECATED double getDouble(int index)
{
return operator[](index);
}
JsonArray(char* json, jsmntok_t* tokens);
jsmntok_t* getToken(int index);
// Obsolete: Use operator[] instead
DEPRECATED JsonObject getHashTable(int index);
// Obsolete: Use operator[] instead
DEPRECATED long getLong(int index)
{
return operator[](index);
}
// Obsolete: Use operator[] instead
DEPRECATED char* getString(int index)
{
return operator[](index);
}
};
}
}

View File

@ -0,0 +1,46 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonValue.h"
#include "JsonToken.h"
namespace ArduinoJson
{
namespace Parser
{
// An iterator for JsonArray
class JsonArrayIterator : JsonToken
{
public:
// Create an iterator pointing at the specified JsonToken
JsonArrayIterator(JsonToken token)
: JsonToken(token)
{
}
// Move iterator forward
void operator++()
{
*this = JsonArrayIterator(nextSibling());
}
// Get the value pointed by the iterator
JsonValue operator*() const
{
return JsonValue(*this);
}
// Test iterator equality
bool operator!= (const JsonArrayIterator& other) const
{
return JsonToken::operator!=(other);
}
};
}
}

View File

@ -1,85 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include <string.h> // for strcmp()
#include "JsonArray.h"
#include "JsonHashTable.h"
using namespace ArduinoJson::Parser;
JsonHashTable::JsonHashTable(char* json, jsmntok_t* tokens)
: JsonObjectBase(json, tokens)
{
if (tokens == 0 || tokens[0].type != JSMN_OBJECT)
makeInvalid();
}
/*
* Returns the token for the value associated with the specified key
*/
jsmntok_t* JsonHashTable::getToken(const char* desiredKey)
{
// sanity check
if (json == 0 || tokens == 0 || desiredKey == 0)
return 0;
// skip first token, it's the whole object
jsmntok_t* currentToken = tokens + 1;
// scan each keys
for (int i = 0; i < tokens[0].size / 2 ; i++)
{
// get key token string
char* key = getStringFromToken(currentToken);
// compare with desired name
if (strcmp(desiredKey, key) == 0)
{
// return the value token that follows the key token
return currentToken + 1;
}
// move forward: key + value + nested tokens
currentToken += 2 + getNestedTokenCount(currentToken + 1);
}
// nothing found, return NULL
return 0;
}
bool JsonHashTable::containsKey(const char* key)
{
return getToken(key) != 0;
}
JsonArray JsonHashTable::getArray(const char* key)
{
return JsonArray(json, getToken(key));
}
bool JsonHashTable::getBool(const char* key)
{
return getBoolFromToken(getToken(key));
}
double JsonHashTable::getDouble(const char* key)
{
return getDoubleFromToken(getToken(key));
}
JsonHashTable JsonHashTable::getHashTable(const char* key)
{
return JsonHashTable(json, getToken(key));
}
long JsonHashTable::getLong(const char* key)
{
return getLongFromToken(getToken(key));
}
char* JsonHashTable::getString(const char* key)
{
return getStringFromToken(getToken(key));
}

View File

@ -1,42 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonObjectBase.h"
namespace ArduinoJson
{
namespace Parser
{
class JsonArray;
class JsonHashTable : public JsonObjectBase
{
template <int N>
friend class JsonParser;
friend class JsonArray;
public:
JsonHashTable() {}
bool containsKey(const char* key);
JsonArray getArray(const char* key);
bool getBool(const char* key);
double getDouble(const char* key);
JsonHashTable getHashTable(const char* key);
long getLong(const char* key);
char* getString(const char* key);
private:
JsonHashTable(char* json, jsmntok_t* tokens);
jsmntok_t* getToken(const char* key);
};
}
}

15
JsonParser/JsonObject.cpp Normal file
View File

@ -0,0 +1,15 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonArray.h"
#include "JsonObject.h"
#include "JsonValue.h"
using namespace ArduinoJson::Parser;
DEPRECATED JsonArray JsonObject::getArray(const char* key)
{
return operator[](key);
}

102
JsonParser/JsonObject.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonValue.h"
#include "JsonObjectIterator.h"
namespace ArduinoJson
{
namespace Parser
{
class JsonArray;
// A JSON Object (ie hash-table/dictionary)
class JsonObject : JsonValue
{
public:
// Create an invalid JsonObject
JsonObject()
{
}
// Convert a JsonValue into a JsonObject
JsonObject(JsonValue value)
: JsonValue(value)
{
}
// Tell if the object is valid
bool success()
{
return isObject();
}
// Get the value associated with the specified key.
JsonValue operator[](const char* key)
{
return JsonValue::operator[](key);
}
// Tell if the specified key exists in the object.
bool containsKey(const char* key)
{
return operator[](key).success();
}
// Get an iterator pointing at the beginning of the object
JsonObjectIterator begin()
{
return isObject() ? firstChild() : null();
}
// Get an iterator pointing at the end of the object
JsonObjectIterator end()
{
return isObject() ? nextSibling() : null();
}
// Obsolete: Use operator[] instead
DEPRECATED JsonArray getArray(const char* key);
// Obsolete: Use operator[] instead
DEPRECATED bool getBool(const char* key)
{
return operator[](key);
}
// Obsolete: Use operator[] instead
DEPRECATED double getDouble(const char* key)
{
return operator[](key);
}
// Obsolete: Use operator[] instead
DEPRECATED JsonObject getHashTable(const char* key)
{
return operator[](key);
}
// Obsolete: Use operator[] instead
DEPRECATED long getLong(const char* key)
{
return operator[](key);
}
// Obsolete: Use operator[] instead
DEPRECATED char* getString(const char* key)
{
return operator[](key);
}
};
// Obsolete: Use JsonObject instead
DEPRECATED typedef JsonObject JsonHashTable;
}
}

View File

@ -1,67 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include <stdlib.h> // for strtol, strtod
#include "JsonObjectBase.h"
using namespace ArduinoJson::Parser;
int JsonObjectBase::getNestedTokenCount(jsmntok_t* token)
{
int end = token->end;
int count = 0;
token++;
while (token->start < end)
{
token++;
count++;
}
return count;
}
bool JsonObjectBase::getBoolFromToken(jsmntok_t* token)
{
if (token->type != JSMN_PRIMITIVE) return 0;
// "true"
if (json[token->start] == 't') return true;
// "false"
if (json[token->start] == 'f') return false;
// "null"
if (json[token->start] == 'n') return false;
// number
return strtol(json + token->start, 0, 0) != 0;
}
double JsonObjectBase::getDoubleFromToken(jsmntok_t* token)
{
if (token == 0 || token->type != JSMN_PRIMITIVE) return 0;
return strtod(json + token->start, 0);
}
long JsonObjectBase::getLongFromToken(jsmntok_t* token)
{
if (token == 0 || token->type != JSMN_PRIMITIVE) return 0;
return strtol(json + token->start, 0, 0);
}
char* JsonObjectBase::getStringFromToken(jsmntok_t* token)
{
if (token == 0 || token->type != JSMN_PRIMITIVE && token->type != JSMN_STRING)
return 0;
// add null terminator to the string
json[token->end] = 0;
return json + token->start;
}

View File

@ -1,53 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "jsmn.h"
namespace ArduinoJson
{
namespace Parser
{
class JsonObjectBase
{
public:
JsonObjectBase()
{
makeInvalid();
}
bool success()
{
return json != 0 && tokens != 0;
}
protected:
JsonObjectBase(char* json, jsmntok_t* tokens)
{
this->json = json;
this->tokens = tokens;
}
void makeInvalid()
{
json = 0;
tokens = 0;
}
static int getNestedTokenCount(jsmntok_t* token);
bool getBoolFromToken(jsmntok_t* token);
double getDoubleFromToken(jsmntok_t* token);
long getLongFromToken(jsmntok_t* token);
char* getStringFromToken(jsmntok_t* token);
char* json;
jsmntok_t* tokens;
};
}
}

View File

@ -0,0 +1,58 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonValue.h"
#include "JsonPair.h"
#include "JsonToken.h"
namespace ArduinoJson
{
namespace Parser
{
// An iterator for JsonObject
class JsonObjectIterator : JsonToken
{
public:
// Create an iterator pointing at the specified token
JsonObjectIterator(JsonToken token)
: JsonToken(token)
{
}
// Move to the next JsonPair
void operator++()
{
*this = JsonObjectIterator(nextSibling().nextSibling());
}
// Get the JsonPair pointed by the iterator
JsonPair operator*() const
{
return JsonPair(*this);
}
// Test iterator equality
bool operator!= (const JsonObjectIterator& other) const
{
return JsonToken::operator!=(other);
}
// Get the key of the JsonPair pointed by the iterator
const char* key() const
{
return operator*().key();
}
// Get the key of the JsonPair pointed by the iterator
JsonValue value() const
{
return operator*().value();
}
};
}
}

37
JsonParser/JsonPair.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonValue.h"
namespace ArduinoJson
{
namespace Parser
{
// A JSON key-value pair, as a part of a JSON object
class JsonPair : JsonToken
{
public:
// Convert a JsonToken to a JsonPair
JsonPair(JsonToken token)
: JsonToken(token)
{
}
// Get the key
const char* key()
{
return getText();
}
// Get the value
JsonValue value()
{
return nextSibling();
}
};
}
}

View File

@ -1,70 +1,34 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
*/
#pragma once
#include "JsonHashTable.h"
#include "JsonArray.h"
#include "JsonParserBase.h"
namespace ArduinoJson
{
namespace Parser
{
/*
* The JSON parser.
*
* You need to specifiy the number of token to be allocated for that parser.
* Values from 16 to 32 are recommended.
* The parser size will be MAX_TOKEN*8 bytes.
* Don't forget that the memory size of standard Arduino board is only 2KB
*
* CAUTION: JsonArray and JsonHashTable contain pointers to tokens of the
* JsonParser, so they need the JsonParser to be in memory to work.
* As a result, you must not create JsonArray and JsonHashTable that have a
* longer life that the JsonParser.
*/
// The JSON parser.
//
// You need to specifiy the number of token to be allocated for that parser.
//
// CAUTION: JsonArray, JsonObject and JsonValue contain pointers to tokens of the
// JsonParser, so they need the JsonParser to be in memory to work.
// As a result, you must not create JsonArray, JsonObject or JsonValue that have a
// longer life that the JsonParser.
template <int MAX_TOKENS>
class JsonParser
class JsonParser : public JsonParserBase
{
public:
/*
* Parse the JSON string and return a array.
*
* The content of the string may be altered to add '\0' at the
* end of string tokens
*/
JsonArray parseArray(char* json)
JsonParser()
: JsonParserBase(tokens, MAX_TOKENS)
{
return JsonArray(json, parse(json));
}
/*
* Parse the JSON string and return a array.
*
* The content of the string may be altered to add '\0' at the
* end of string tokens
*/
JsonHashTable parseHashTable(char* json)
{
return JsonHashTable(json, parse(json));
}
private:
jsmntok_t* parse(char* json)
{
jsmn_parser parser;
jsmn_init(&parser);
if (JSMN_SUCCESS != jsmn_parse(&parser, json, tokens, MAX_TOKENS))
return 0;
return tokens;
}
jsmntok_t tokens[MAX_TOKENS];
};
}

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C15274DE-2695-4DFE-8520-4424223FE6DA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>JsonParser</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="jsmn.h" />
<ClInclude Include="JsonArray.h" />
<ClInclude Include="JsonArrayIterator.h" />
<ClInclude Include="JsonObject.h" />
<ClInclude Include="JsonObjectIterator.h" />
<ClInclude Include="JsonPair.h" />
<ClInclude Include="JsonParser.h" />
<ClInclude Include="JsonParserBase.h" />
<ClInclude Include="JsonToken.h" />
<ClInclude Include="JsonValue.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="jsmn.cpp" />
<ClCompile Include="JsonArray.cpp" />
<ClCompile Include="JsonObject.cpp" />
<ClCompile Include="JsonParserBase.cpp" />
<ClCompile Include="JsonToken.cpp" />
<ClCompile Include="JsonValue.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="JsonParserBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonToken.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonValue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonParser.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="jsmn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonArray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonArrayIterator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonObject.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonObjectIterator.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="JsonPair.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="jsmn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonArray.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObject.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonParserBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonToken.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonValue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,20 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonParserBase.h"
#include "JsonToken.h"
using namespace ArduinoJson::Parser;
JsonValue JsonParserBase::parse(char* json)
{
jsmn_parser parser;
jsmn_init(&parser);
if (JSMN_SUCCESS != jsmn_parse(&parser, json, tokens, maxTokens))
return JsonToken::null();
return JsonToken(json, tokens);
}

View File

@ -0,0 +1,49 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonArray.h"
#include "JsonObject.h"
namespace ArduinoJson
{
namespace Parser
{
// Base class for the JSON parser, in case you want to provide your own buffer
class JsonParserBase
{
public:
// Create a JSON parser using the provided buffer
JsonParserBase(jsmntok_t* tokens, int maxTokens)
: tokens(tokens), maxTokens(maxTokens)
{
}
// Parse the JSON string and return a array
//
// The content of the string may be altered to add '\0' at the
// end of string tokens
JsonValue parse(char* json);
// Obsolete: use parse() instead
DEPRECATED JsonArray parseArray(char* json)
{
return parse(json);
}
// Obsolete: use parse() instead
DEPRECATED JsonObject parseHashTable(char* json)
{
return parse(json);
}
private:
jsmntok_t* tokens;
int maxTokens;
};
}
}

71
JsonParser/JsonToken.cpp Normal file
View File

@ -0,0 +1,71 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonToken.h"
using namespace ArduinoJson::Parser;
char* JsonToken::getText()
{
char* s = json + token->start;
json[token->end] = 0;
unescapeString(s);
return s;
}
inline void JsonToken::unescapeString(char* s)
{
char* readPtr = s;
char* writePtr = s;
char c;
do
{
c = *readPtr++;
if (c == '\\')
{
c = unescapeChar(*readPtr++);
}
*writePtr++ = c;
} while (c != 0);
}
inline char JsonToken::unescapeChar(char c)
{
// Optimized for code size on a 8-bit AVR
const char* p = "b\bf\fn\nr\rt\t";
while (true)
{
if (p[0] == 0) return c;
if (p[0] == c) return p[1];
p += 2;
}
}
JsonToken JsonToken::nextSibling() const
{
// start with current token
jsmntok_t* t = token;
// count the number of token to skip
int yetToVisit = 1;
// skip all nested tokens
while (yetToVisit)
{
yetToVisit += t->size - 1;
t++;
}
// build a JsonToken at the new location
return JsonToken(json, t);
}

99
JsonParser/JsonToken.h Normal file
View File

@ -0,0 +1,99 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "jsmn.h"
namespace ArduinoJson
{
namespace Parser
{
// A pointer to a JSON token
class JsonToken
{
public:
// Create a "null" pointer
JsonToken()
: token(0)
{
}
// Create a pointer to the specified JSON token
JsonToken(char* json, jsmntok_t* token)
: json(json), token(token)
{
}
// Get content of the JSON token
char* getText();
// Get the number of children tokens
int childrenCount()
{
return token->size;
}
// Get a pointer to the first child of the current token
JsonToken firstChild() const
{
return JsonToken(json, token + 1);
}
// Get a pointer to the next sibling token (ie skiping the children tokens)
JsonToken nextSibling() const;
// Test equality
bool operator!=(const JsonToken& other) const
{
return token != other.token;
}
// Tell if the pointer is "null"
bool isValid()
{
return token != 0;
}
// Tell if the JSON token is a JSON object
bool isObject()
{
return token != 0 && token->type == JSMN_OBJECT;
}
// Tell if the JSON token is a JSON array
bool isArray()
{
return token != 0 && token->type == JSMN_ARRAY;
}
// Tell if the JSON token is a primitive
bool isPrimitive()
{
return token != 0 && token->type == JSMN_PRIMITIVE;
}
// Tell if the JSON token is a string
bool isString()
{
return token != 0 && token->type == JSMN_STRING;
}
// Explicit wait to create a "null" JsonToken
static JsonToken null()
{
return JsonToken();
}
private:
char* json;
jsmntok_t* token;
static char unescapeChar(char c);
static void unescapeString(char* s);
};
}
}

110
JsonParser/JsonValue.cpp Normal file
View File

@ -0,0 +1,110 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include <stdlib.h> // for strtol, strtod
#include <string.h> // for strcmp()
#include "JsonArray.h"
#include "JsonObject.h"
#include "JsonValue.h"
using namespace ArduinoJson::Parser;
// Convert the JsonValue to a bool.
// Returns false if the JsonValue is not a primitve.
JsonValue::operator bool()
{
if (!isPrimitive()) return 0;
char *text = getText();
// "true"
if (text[0] == 't') return true;
// "false"
if (text[0] == 'f') return false;
// "null"
if (text[0] == 'n') return false;
// number
return strtol(text, 0, 0) != 0;
}
// Convert the JsonValue to a floating point value.
// Returns false if the JsonValue is not a number.
JsonValue::operator double()
{
return isPrimitive() ? strtod(getText(), 0) : 0;
}
// Convert the JsonValue to a floating point value.
// Returns false if the JsonValue is not a number.
JsonValue::operator long()
{
return isPrimitive() ? strtol(getText(), 0, 0) : 0;
}
// Convert the JsonValue to a string.
// Returns 0 if the JsonValue is not a string.
JsonValue::operator char*()
{
return isString() || isPrimitive() ? getText() : 0;
}
// Get the nested value at the specified index.
// Returns an invalid JsonValue if the current value is not an array.
JsonValue JsonValue::operator[](int index)
{
// sanity check
if (index < 0 || !isArray() || index >= childrenCount())
return null();
// skip first token, it's the whole object
JsonToken runningToken = firstChild();
// skip all tokens before the specified index
for (int i = 0; i < index; i++)
{
// move forward: current + nested tokens
runningToken = runningToken.nextSibling();
}
return runningToken;
}
// Get the nested value matching the specified index.
// Returns an invalid JsonValue if the current value is not an object.
JsonValue JsonValue::operator[](const char* desiredKey)
{
// sanity check
if (desiredKey == 0 || !isObject())
return null();
// skip first token, it's the whole object
JsonToken runningToken = firstChild();
// scan each keys
for (int i = 0; i < childrenCount() / 2; i++)
{
// get 'key' token string
char* key = runningToken.getText();
// move to the 'value' token
runningToken = runningToken.nextSibling();
// compare with desired name
if (strcmp(desiredKey, key) == 0)
{
// return the value token that follows the key token
return runningToken;
}
// skip nested tokens
runningToken = runningToken.nextSibling();
}
// nothing found, return NULL
return null();
}

72
JsonParser/JsonValue.h Normal file
View File

@ -0,0 +1,72 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonToken.h"
#ifndef ARDUINO_JSON_NO_DEPRECATION_WARNING
#ifdef __GNUC__
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#endif
#else
#define DEPRECATED
#endif
namespace ArduinoJson
{
namespace Parser
{
// A JSON value
// Can be converted to string, double, bool, array or object.
class JsonValue : protected JsonToken
{
public:
// Create a invalid value
JsonValue()
{
}
// Convert a JsonToken to a JsonValue
JsonValue(JsonToken token)
: JsonToken(token)
{
}
// Tell is the JsonValue is valid
bool success()
{
return isValid();
}
// Convert the JsonValue to a bool.
// Returns false if the JsonValue is not a primitve.
operator bool();
// Convert the JsonValue to a floating point value.
// Returns false if the JsonValue is not a number.
operator double();
// Convert the JsonValue to a long integer.
// Returns 0 if the JsonValue is not a number.
operator long();
// Convert the JsonValue to a string.
// Returns 0 if the JsonValue is not a string.
operator char*();
// Get the nested value at the specified index.
// Returns an invalid JsonValue if the current value is not an array.
JsonValue operator[](int index);
// Get the nested value matching the specified index.
// Returns an invalid JsonValue if the current value is not an object.
JsonValue operator[](const char* key);
};
}
}

View File

@ -22,17 +22,15 @@ Features
Example
-------
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonParser<32> parser;
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonParser<32> parser;
JsonObject root = parser.parse(json);
JsonHashTable root = parser.parseHashTable(json);
char* sensor = root.getString("sensor");
long time = root.getLong("time");
JsonArray coords = root.getArray("data");
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
How to use ?
@ -51,6 +49,13 @@ Just add the following lines at the top of your `.ino` file:
#include <JsonParser.h>
using namespace ArduinoJson::Parser;
> ##### Having a namespace conflict?
> To be able to use both `ArduinoJson::Generator` and `ArduinoJson::Parser` in the same file, you need to do one of the followings:
>
> * Put the `using` statements into different functions
> * `using namespace ArduinoJson`, then prefix the type names by `Generator::` or `Parser::`
> * Create aliases for the namespaces or the types (C++11 only)
### 3. Create a parser
@ -60,7 +65,7 @@ To extract data from the JSON string, you need to create a `JsonParser`, and spe
> #### How to choose the number of tokens ?
> A token is an element of the JSON object: either a key, a value, an hash-table or an array.
> A token is an element of the JSON object: either a key, a value, an object or an array.
> As an example the `char json[]` on the top of this page contains 12 tokens (don't forget to count 1 for the whole object and 1 more for the array itself).
> The more tokens you allocate, the more complex the JSON can be, but also the more memory is occupied.
@ -73,28 +78,24 @@ To extract data from the JSON string, you need to create a `JsonParser`, and spe
To use this library, you need to know beforehand what is the type of data contained in the JSON string, which is very likely.
The root object has to be either a hash-table (like `{"key":"value"}`) or an array (like `[1,2]`).
The root object has to be either an object (like `{"key":"value"}`) or an array (like `[1,2]`).
The nested objects can be either arrays, booleans, hash-tables, numbers or strings.
The nested objects can be either arrays, booleans, objects, numbers or strings.
If you need other type, you can get the string value and parse it yourself.
#### Hash-table
#### Object
Consider we have a `char json[]` containing to the following JSON string:
{
"Name":"Blanchon",
"Skills":[
"C",
"C++",
"C#"],
"Age":32,
"Online":true
"sensor":"gps",
"time":1351824120,
"data":[48.756080,2.302038]
}
In this case the root object of the JSON string is a hash-table, so you need to extract a `JsonHashTable`:
In this case the string contains a JSON object, so you need to extract a `JsonObject`:
JsonHashTable root = parser.parseHashTable(json);
JsonObject root = parser.parse(json);
To check if the parsing was successful, you must check:
@ -105,13 +106,18 @@ To check if the parsing was successful, you must check:
And then extract the member you need:
char* name = hashTable.getString("Name");
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
JsonArray skills = hashTable.getArray("Skills");
You can also iterate through the key-value pairs of the object:
int age = hashTable.getLong("Age");
bool online = hashTable.getBool("Online");
for (JsonObjectIterator i=root.begin(); i!=root.end(); ++i)
{
Serial.println(i.key());
Serial.println((char*)i.value());
}
#### Array
@ -124,7 +130,7 @@ Consider we have a `char json[]` containing to the following JSON string:
In this case the root object of the JSON string is an array, so you need to extract a `JsonArray`:
JsonArray root = parser.parseArray(json);
JsonArray root = parser.parse(json);
To check if the parsing was successful, you must check:
@ -135,20 +141,24 @@ To check if the parsing was successful, you must check:
And then extract the content by its index in the array:
JsonArray row0 = root.getArray(0);
double a = row0.getDouble(0);
or simply:
double a = root.getArray(0).getDouble(0);
double a = root[0][0];
double b = root[0][1];
double c = root[1][0];
double d = root[1][1];
You can also iterate through the key-value pairs of the object:
for (JsonArrayIterator i=array.begin(); i!=array.end(); ++i)
{
Serial.println((char*)*i);
}
Common pitfalls
---------------
### 1. Not enough tokens
By design, the library has no way to tell you why `JsonParser::parseArray()` or `JsonParser::parseHashTable()` failed.
By design, the library has no way to tell you why `JsonParser::parse()` failed.
There are basically two reasons why they may fail:
@ -175,7 +185,7 @@ That is why an 8-bit processor is not able to parse long and complex JSON string
### 3. JsonParser not in memory
To reduce the memory consumption, `JsonArray` and `JsonHashTable` contains pointer to the token that are inside the `JsonParser`. This can only work if the `JsonParser` is still in memory.
To reduce the memory consumption, `JsonValue`, `JsonArray` and `JsonObject` contains pointer to the token that are inside the `JsonParser`. This can only work if the `JsonParser` is still in memory.
For example, don't do this:
@ -191,7 +201,7 @@ because the local variable `parser` will be *removed* from memory when the funct
This will probably never be an issue, but you need to be aware of this feature.
When you pass a `char[]` to `JsonParser::parseArray()` or `JsonParser::parseHashTable()`, the content of the string will be altered to add `\0` at the end of the tokens.
When you pass a `char[]` to `JsonParser::parse()`, the content of the string will be altered to add `\0` at the end of the tokens.
This is because we want functions like `JsonArray::getString()` to return a null-terminating string without any memory allocation.
@ -203,202 +213,38 @@ Here are the size of the main classes of the library.
This table is for an 8-bit Arduino, types would be bigger on a 32-bit processor.
<table>
<tr>
<th>Type</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>Parser&lt;N&gt;</td>
<td>8 x N</td>
</tr>
<tr>
<td>JsonArray</td>
<td>4</td>
</tr>
<tr>
<td>JsonHashTable</td>
<td>4</td>
</tr>
</table>
| Type | Size in bytes |
| ------------ | ------------- |
| `Parser<N>` | 4 + 8 x N |
| `JsonArray` | 4 |
| `JsonObject` | 4 |
| `JsonValue` | 4 |
Code size
---------
Theses tables has been created by analyzing the map file generated by AVR-GCC after adding `-Wl,-Map,foo.map` to the command line.
As you'll see the code size is between 1680 and 3528 bytes, depending on the features you use.
The sizes have been obtained with Arduino IDE 1.0.5 for a Duemilanove.
### Minimum setup
<table>
<tr>
<th>Function</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>strcmp(char*,char*)</td>
<td>18</td>
</tr>
<tr>
<td>jsmn_init(jsmn_parser*)</td>
<td>20</td>
</tr>
<tr>
<td>jsmn_parse(jsmn_parser*, char const*, jsmntok_t*, unsigned int)</td>
<td>960</td>
</tr>
<tr>
<td>JsonParser::parse(char*)</td>
<td>106</td>
</tr>
<tr>
<td>JsonObjectBase::getNestedTokenCount(jsmntok_t*)</td>
<td>84</td>
</tr>
<tr>
<td>JsonObjectBase::getStringFromToken(jsmntok_t*)</td>
<td>68</td>
</tr>
<tr>
<td>JsonArray::JsonArray(char*, jsmntok_t*)</td>
<td>42</td>
</tr>
<tr>
<td>JsonArray::getToken(int)</td>
<td>112</td>
</tr>
<tr>
<td>JsonArray::getString(int)</td>
<td>18</td>
</tr>
<tr>
<td>JsonHashTable::JsonHashTable(char*, jsmntok_t*)</td>
<td>42</td>
</tr>
<tr>
<td>JsonHashTable::getToken(char*)</td>
<td>180</td>
</tr>
<tr>
<td>JsonHashTable::getString(char*)</td>
<td>18</td>
</tr>
<tr>
<td>TOTAL</td>
<td>1680</td>
</tr>
</table>
| Function | Size |
| ------------------------------------ | ---- |
| `jsmn_parse()` | 962 |
| `JsonValue::operator[](char const*)` | 218 |
| `JsonParserBase::parse()` | 116 |
| `JsonValue::operator[](int)` | 108 |
| `strcmp()` | 18 |
### Additional space to parse nested objects
### Additional space for integers
<table>
<tr>
<th>Function</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>JsonArray::getArray(int)</td>
<td>42</td>
</tr>
<tr>
<td>JsonArray::getHashTable(int)</td>
<td>64</td>
</tr>
<tr>
<td>JsonHashTable::getArray(char*)</td>
<td>64</td>
</tr>
<tr>
<td>JsonHashTable::getHashTable(char*)</td>
<td>42</td>
</tr>
<tr>
<td>TOTAL</td>
<td>212</td>
</tr>
</table>
| Function | Size |
| ---------------------------- | ---- |
| `strtol()` | 606 |
| `JsonValue::operator long()` | 94 |
### Additional space to parse `bool` values
### Additional space for floating points
<table>
<tr>
<th>Function</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>JsonObjectBase::getBoolFromToken(jsmntok_t*)</td>
<td>82</td>
</tr>
<tr>
<td>JsonArray::getBool(int)</td>
<td>18</td>
</tr>
<tr>
<td>JsonHashTable::getBool(char*)</td>
<td>18</td>
</tr>
<tr>
<td>TOTAL</td>
<td>130</td>
</tr>
</table>
### Additional space to parse `double` values
<table>
<tr>
<th>Function</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>strtod(char*,int)</td>
<td>704</td>
</tr>
<tr>
<td>JsonObjectBase::getDoubleFromToken(jsmntok_t*)</td>
<td>44</td>
</tr>
<tr>
<td>JsonArray::getDouble(int)</td>
<td>18</td>
</tr>
<tr>
<td>JsonHashTable::getDouble(char*)</td>
<td>18</td>
</tr>
<tr>
<td>TOTAL</td>
<td>796</td>
</tr>
</table>
### Additional space to parse `long` values
<table>
<tr>
<th>Function</th>
<th>Size in bytes</th>
</tr>
<tr>
<td>strtol(char*,char**,int)</td>
<td>606</td>
</tr>
<tr>
<td>JsonObjectBase::getLongFromToken(jsmntok_t*)</td>
<td>56</td>
</tr>
<tr>
<td>JsonArray::getLong(int)</td>
<td>18</td>
</tr>
<tr>
<td>JsonHashTable::getLong(char*)</td>
<td>18</td>
</tr>
<tr>
<td>TOTAL</td>
<td>710</td>
</tr>
</table>
| Function | Size |
| -------------------------------- | ----- |
| `strtod()` | 1369 |
| `JsonValue::operator double()` | 82 |

View File

@ -13,7 +13,7 @@ using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(TestGbathreeSample1)
TEST_CLASS(GbathreeBug)
{
char json[1024];
JsonParser<200> parser;

View File

@ -0,0 +1,67 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace JsonParserTests
{
TEST_CLASS(JsonArrayIteratorTests)
{
public:
TEST_METHOD(EmptyJson)
{
char json[] = "";
JsonParser<1> parser;
JsonArray a = parser.parse(json);
int loopCount = 0;
for (long i : a)
{
loopCount++;
}
Assert::AreEqual(0, loopCount);
}
TEST_METHOD(ThreeIntegers)
{
char json [] = "[1,2,3]";
long expected [] = {1, 2, 3};
JsonParser<4> parser;
JsonArray a = parser.parse(json);
int index = 0;
for (long i : a)
{
Assert::AreEqual(expected[index++], i);
}
}
TEST_METHOD(ThreeStrings)
{
char json[] = "[\"1\",\"2\",\"3\"]";
char* expected[] = {"1", "2", "3"};
JsonParser<4> parser;
JsonArray a = parser.parse(json);
int index = 0;
for (const char* i : a)
{
Assert::AreEqual(expected[index++], i);
}
}
};
}

View File

@ -0,0 +1,189 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(JsonArrayTests)
{
JsonArray array;
char json[256];
jsmntok_t tokens[32];
JsonParserBase parser = JsonParserBase(tokens, 32);
public:
TEST_METHOD(TooFewClosingBrackets)
{
whenInputIs("[[]");
parseMustFail();
}
TEST_METHOD(TooManyClosingBrackets)
{
whenInputIs("[]]");
parseMustFail();
}
TEST_METHOD(EmptyArray)
{
whenInputIs("[]");
parseMustSucceed();
lengthMustBe(0);
}
TEST_METHOD(NotEnoughTokens)
{
setTokenCountTo(2);
whenInputIs("[1,2]");
parseMustFail();
itemMustNotExist(0);
}
TEST_METHOD(TwoIntegers)
{
setTokenCountTo(3);
whenInputIs("[1,2]");
parseMustSucceed();
lengthMustBe(2);
itemMustBe(0, 1L);
itemMustBe(1, 2L);
itemMustNotExist(2);
}
TEST_METHOD(TwoBooleans)
{
setTokenCountTo(3);
whenInputIs("[true,false]");
parseMustSucceed();
lengthMustBe(2);
itemMustBe(0, true);
itemMustBe(1, false);
itemMustNotExist(2);
}
TEST_METHOD(TwoStrings)
{
setTokenCountTo(3);
whenInputIs("[\"hello\",\"world\"]");
parseMustSucceed();
lengthMustBe(2);
itemMustBe(0, "hello");
itemMustBe(1, "world");
itemMustNotExist(2);
}
TEST_METHOD(TwoDimensionsArray)
{
setTokenCountTo(7);
whenInputIs("[[1,2],[3,4]]");
parseMustSucceed();
lengthMustBe(2);
itemMustBe(0, 0, 1L);
itemMustBe(0, 1, 2L);
itemMustBe(1, 0, 3L);
itemMustBe(1, 1, 4L);
itemMustNotExist(2);
}
TEST_METHOD(ThreeDimensionsArray)
{
setTokenCountTo(15);
whenInputIs("[[[1,2],[3,4]],[[5,6],[7,8]]]");
parseMustSucceed();
lengthMustBe(2);
itemMustBe(0, 0, 0, 1L);
itemMustBe(0, 0, 1, 2L);
itemMustBe(0, 1, 0, 3L);
itemMustBe(0, 1, 1, 4L);
itemMustBe(1, 0, 0, 5L);
itemMustBe(1, 0, 1, 6L);
itemMustBe(1, 1, 0, 7L);
itemMustBe(1, 1, 1, 8L);
itemMustNotExist(2);
}
private:
void setTokenCountTo(int n)
{
parser = JsonParserBase(tokens, n);
}
void whenInputIs(const char* input)
{
strcpy(json, input);
array = parser.parseArray(json);
}
void parseMustFail()
{
Assert::IsFalse(array.success());
lengthMustBe(0);
}
void parseMustSucceed()
{
Assert::IsTrue(array.success());
}
void lengthMustBe(int expected)
{
Assert::AreEqual(expected, array.getLength());
}
void itemMustBe(int index, long expected)
{
Assert::AreEqual(expected, array.getLong(index));
}
void itemMustBe(int index, bool expected)
{
Assert::AreEqual(expected, array.getBool(index));
}
void itemMustBe(int index, const char* expected)
{
Assert::AreEqual(expected, array.getString(index));
}
void itemMustBe(int index0, int index1, long expected)
{
Assert::AreEqual(expected, array.getArray(index0).getLong(index1));
}
void itemMustBe(int index0, int index1, int index2, long expected)
{
Assert::AreEqual(expected, array.getArray(index0).getArray(index1).getLong(index2));
}
void itemMustNotExist(int index)
{
Assert::IsFalse(array.getHashTable(index).success());
Assert::IsFalse(array.getArray(index).success());
Assert::IsFalse(array.getBool(index));
Assert::AreEqual(0.0, array.getDouble(index));
Assert::AreEqual(0L, array.getLong(index));
Assert::IsNull(array.getString(index));
}
};
}

View File

@ -0,0 +1,71 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace JsonParserTests
{
TEST_CLASS(JsonObjectIteratorTests)
{
public:
TEST_METHOD(EmptyObject)
{
char json [] = "{}";
JsonParser<1> parser;
JsonHashTable a = parser.parse(json);
int loopCount = 0;
for (auto i : a)
{
loopCount++;
}
Assert::AreEqual(0, loopCount);
}
TEST_METHOD(EmptyJson)
{
char json[] = "";
JsonParser<1> parser;
JsonHashTable a = parser.parse(json);
int loopCount = 0;
for (auto i : a)
{
loopCount++;
}
Assert::AreEqual(0, loopCount);
}
TEST_METHOD(ThreeStrings)
{
char json[] = "{\"key1\":\"value1\",\"key2\":\"value2\",\"key3\":\"value3\"}";
char* expectedKeys[] = {"key1", "key2", "key3"};
char* expectedValues[] = {"value1", "value2", "value3"};
JsonParser<7> parser;
JsonHashTable a = parser.parse(json);
int index = 0;
for (auto i : a)
{
Assert::AreEqual(expectedKeys[index], i.key());
Assert::AreEqual(expectedValues[index], (const char*) i.value());
index++;
}
}
};
}

View File

@ -0,0 +1,165 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
#include <string>
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(JsonHashTableTests)
{
JsonHashTable hashTable;
JsonArray nestedArray;
char json[256];
jsmntok_t tokens[32];
JsonParserBase parser = JsonParserBase(tokens, 32);
public:
TEST_METHOD(EmptyHashTable)
{
whenInputIs("{}");
parseMustSucceed();
}
TEST_METHOD(NotEnoughTokens)
{
setTokenCountTo(2);
whenInputIs("{\"key\":0}");
parseMustFail();
itemMustNotExist("key");
}
TEST_METHOD(TwoIntegers)
{
setTokenCountTo(5);
whenInputIs("{\"key1\":1,\"key2\":2}");
parseMustSucceed();
itemMustBe("key1", 1L);
itemMustBe("key2", 2L);
itemMustNotExist("key3");
}
TEST_METHOD(TwoBooleans)
{
setTokenCountTo(5);
whenInputIs("{\"key1\":true,\"key2\":false}");
parseMustSucceed();
itemMustBe("key1", true);
itemMustBe("key2", false);
itemMustNotExist("key3");
}
TEST_METHOD(TwoStrings)
{
setTokenCountTo(5);
whenInputIs("{\"key1\":\"hello\",\"key2\":\"world\"}");
parseMustSucceed();
itemMustBe("key1", "hello");
itemMustBe("key2", "world");
itemMustNotExist("key3");
}
TEST_METHOD(TwoNestedArrays)
{
setTokenCountTo(9);
whenInputIs("{\"key1\":[1,2],\"key2\":[3,4]}");
parseMustSucceed();
itemMustBeAnArray("key1");
arrayLengthMustBe(2);
arrayItemMustBe(0, 1L);
arrayItemMustBe(1, 2L);
arrayItemMustBe(2, 0L);
itemMustBeAnArray("key2");
arrayLengthMustBe(2);
arrayItemMustBe(0, 3L);
arrayItemMustBe(1, 4L);
arrayItemMustBe(2, 0L);
itemMustNotExist("key3");
}
private:
void setTokenCountTo(int n)
{
parser = JsonParserBase(tokens, n);
}
void whenInputIs(const char* input)
{
strcpy(json, input);
hashTable = parser.parseHashTable(json);
}
void parseMustFail()
{
Assert::IsFalse(hashTable.success());
}
void parseMustSucceed()
{
Assert::IsTrue(hashTable.success());
}
void itemMustBe(const char* key, long expected)
{
Assert::AreEqual(expected, hashTable.getLong(key));
}
void itemMustBe(const char* key, bool expected)
{
Assert::AreEqual(expected, hashTable.getBool(key));
}
void itemMustBe(const char* key, const char* expected)
{
Assert::AreEqual(expected, hashTable.getString(key));
}
void itemMustNotExist(const char* key)
{
Assert::IsFalse(hashTable.containsKey(key));
Assert::IsFalse(hashTable.getHashTable(key).success());
Assert::IsFalse(hashTable.getArray(key).success());
Assert::IsFalse(hashTable.getBool(key));
Assert::AreEqual(0.0, hashTable.getDouble(key));
Assert::AreEqual(0L, hashTable.getLong(key));
Assert::IsNull(hashTable.getString(key));
}
void itemMustBeAnArray(const char* key)
{
nestedArray = hashTable.getArray(key);
Assert::IsTrue(nestedArray.success());
}
void arrayLengthMustBe(int expected)
{
Assert::AreEqual(expected, nestedArray.getLength());
}
void arrayItemMustBe(int index, long expected)
{
Assert::AreEqual(expected, nestedArray.getLong(index));
}
};
}

View File

@ -56,7 +56,7 @@
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>ARDUINO_JSON_NO_DEPRECATION_WARNING;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
@ -85,21 +85,17 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\JsonParser\jsmn.cpp" />
<ClCompile Include="..\JsonParser\JsonArray.cpp" />
<ClCompile Include="..\JsonParser\JsonHashTable.cpp" />
<ClCompile Include="..\JsonParser\JsonObjectBase.cpp" />
<ClCompile Include="TestArrayExample.cpp" />
<ClCompile Include="TestArrays.cpp" />
<ClCompile Include="TestHashTableExample.cpp" />
<ClCompile Include="TestGbathreeStrings.cpp" />
<ClCompile Include="JsonObjectIteratorTests.cpp" />
<ClCompile Include="JsonArrayTests.cpp" />
<ClCompile Include="JsonArrayIteratorTests.cpp" />
<ClCompile Include="JsonObjectTests.cpp" />
<ClCompile Include="GbathreeBug.cpp" />
<ClCompile Include="JsonStringTests.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\JsonParser\jsmn.h" />
<ClInclude Include="..\JsonParser\JsonArray.h" />
<ClInclude Include="..\JsonParser\JsonHashTable.h" />
<ClInclude Include="..\JsonParser\JsonObjectBase.h" />
<ClInclude Include="..\JsonParser\JsonParser.h" />
<ProjectReference Include="..\JsonParser\JsonParser.vcxproj">
<Project>{c15274de-2695-4dfe-8520-4424223fe6da}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -15,46 +15,23 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="TestHashTableExample.cpp">
<ClCompile Include="GbathreeBug.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TestArrayExample.cpp">
<ClCompile Include="JsonObjectTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TestGbathreeStrings.cpp">
<ClCompile Include="JsonArrayIteratorTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TestArrays.cpp">
<ClCompile Include="JsonObjectIteratorTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonParser\jsmn.cpp">
<ClCompile Include="JsonArrayTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonParser\JsonArray.cpp">
<ClCompile Include="JsonStringTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonParser\JsonHashTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\JsonParser\JsonObjectBase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\JsonParser\jsmn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonParser\JsonArray.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonParser\JsonHashTable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonParser\JsonObjectBase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\JsonParser\JsonParser.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,107 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(JsonStringTests)
{
const char* actual;
char json[256];
JsonParser<32> parser;
public:
TEST_METHOD(EmptyString)
{
whenInputIs("");
outputMustBe(0);
}
TEST_METHOD(JustOneQuote)
{
whenInputIs("\"");
outputMustBe(0);
}
TEST_METHOD(SimpleString)
{
whenInputIs("\"Hi!\"");
outputMustBe("Hi!");
}
TEST_METHOD(EscapedQuote)
{
whenInputIs("\"12\\\"34\""); // ie 12\"34
outputMustBe("12\"34");
}
TEST_METHOD(EscapedReverseSolidus)
{
whenInputIs("\"12\\\\34\""); // ie 12\\34
outputMustBe("12\\34");
}
TEST_METHOD(EscapedSolidus)
{
whenInputIs("\"12\\/34\"");
outputMustBe("12/34");
}
TEST_METHOD(EscapedBackspace)
{
whenInputIs("\"12\\b34\"");
outputMustBe("12\b34");
}
TEST_METHOD(EscapedFormfeed)
{
whenInputIs("\"12\\f34\"");
outputMustBe("12\f34");
}
TEST_METHOD(EscapedNewline)
{
whenInputIs("\"12\\n34\"");
outputMustBe("12\n34");
}
TEST_METHOD(EscapedCarriageReturn)
{
whenInputIs("\"12\\r34\"");
outputMustBe("12\r34");
}
TEST_METHOD(EscapedTab)
{
whenInputIs("\"12\\t34\"");
outputMustBe("12\t34");
}
TEST_METHOD(AllEscapedCharsTogether)
{
whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
outputMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
}
private:
void whenInputIs(const char* input)
{
strcpy(json, input);
actual = parser.parse(json);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, actual);
}
};
}

View File

@ -1,56 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(TestArrayExample)
{
char json[128];
JsonParser<32> parser;
JsonArray array;
public:
TEST_METHOD_INITIALIZE(Initialize)
{
strcpy(json, "[[1.2,3.4],[5.6,7.8]]");
array = parser.parseArray(json);
}
TEST_METHOD(Array_Success_ReturnsTrue)
{
Assert::IsTrue(array.success());
}
TEST_METHOD(Array_GetLength_Returns2)
{
Assert::AreEqual(2, array.getLength());
}
TEST_METHOD(Array_GetArray0_ReturnsInnerArray0)
{
JsonArray innerArray = array.getArray(0);
Assert::AreEqual(2, innerArray.getLength());
Assert::AreEqual(1.2, innerArray.getDouble(0));
Assert::AreEqual(3.4, innerArray.getDouble(1));
}
TEST_METHOD(Array_GetArray1_ReturnsInnerArray1)
{
JsonArray innerArray = array.getArray(1);
Assert::AreEqual(2, innerArray.getLength());
Assert::AreEqual(5.6, innerArray.getDouble(0));
Assert::AreEqual(7.8, innerArray.getDouble(1));
}
};
}

View File

@ -1,147 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(TestArrays)
{
JsonParser<32> parser;
public:
TEST_METHOD(EmptyString)
{
char json[] = "";
JsonArray array = parser.parseArray(json);
Assert::IsFalse(array.success());
}
TEST_METHOD(EmptyArray)
{
char json[] = "[]";
JsonArray array = parser.parseArray(json);
Assert::IsTrue(array.success());
}
TEST_METHOD(TooFewClosingBrackets)
{
char json[] = "[[]";
JsonArray array = parser.parseArray(json);
Assert::IsFalse(array.success());
}
TEST_METHOD(TooManyClosingBrackets)
{
char json[] = "[]]";
JsonArray array = parser.parseArray(json);
Assert::IsFalse(array.success());
}
TEST_METHOD(OneDimensionArray)
{
char json [] = "[0,0]";
JsonArray array = parser.parseArray(json);
Assert::IsTrue(array.success());
Assert::AreEqual(2, array.getLength());
for (int i = 0; i < 2; i++)
{
Assert::AreEqual(0L, array.getLong(i));
}
}
TEST_METHOD(TwoDimensionsArray)
{
char json[] = "[[0,0],[0,0]]";
JsonArray array1 = parser.parseArray(json);
Assert::IsTrue(array1.success());
Assert::AreEqual(2, array1.getLength());
for (int i = 0; i < 2; i++)
{
JsonArray array2 = array1.getArray(i);
Assert::AreEqual(2, array2.getLength());
for (int j = 0; j < 2; j++)
{
Assert::AreEqual(0L, array2.getLong(j));
}
}
}
TEST_METHOD(TreeDimensionsArray)
{
char json[] = "[[[0,0],[0,0]],[[0,0],[0,0]]]";
JsonArray array1 = parser.parseArray(json);
Assert::IsTrue(array1.success());
Assert::AreEqual(2, array1.getLength());
for (int i = 0; i < 2; i++)
{
JsonArray array2 = array1.getArray(i);
Assert::AreEqual(2, array2.getLength());
for (int j = 0; j < 2; j++)
{
JsonArray array3 = array2.getArray(j);
Assert::AreEqual(2, array3.getLength());
for (int k = 0; k < 2; k++)
{
Assert::AreEqual(0L, array3.getLong(k));
}
}
}
}
TEST_METHOD(OneDimensionArrayInHashTable)
{
char json[] = "{a:[0,0],b:[0,0]}";
JsonHashTable root = parser.parseHashTable(json);
Assert::IsTrue(root.success());
JsonArray arrayA = root.getArray("a");
Assert::IsTrue(arrayA.success());
Assert::AreEqual(2, arrayA.getLength());
JsonArray arrayB = root.getArray("b");
Assert::IsTrue(arrayB.success());
Assert::AreEqual(2, arrayB.getLength());
}
TEST_METHOD(TwoDimensionsArrayInHashTable)
{
char json[] = "{a:[[0],[0]],b:[[0],[0]]}";
JsonHashTable root = parser.parseHashTable(json);
Assert::IsTrue(root.success());
JsonArray arrayA = root.getArray("a");
Assert::IsTrue(arrayA.success());
Assert::AreEqual(2, arrayA.getLength());
JsonArray arrayB = root.getArray("b");
Assert::IsTrue(arrayB.success());
Assert::AreEqual(2, arrayB.getLength());
}
};
}

View File

@ -1,67 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "JsonParser.h"
#include <string>
using namespace std;
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Parser;
namespace ArduinoJsonParserTests
{
TEST_CLASS(TestHashTableExample)
{
char json[128];
JsonParser<32> parser;
JsonHashTable hashTable;
public:
TEST_METHOD_INITIALIZE(Initialize)
{
strcpy(json, "{\"Name\":\"Blanchon\",\"Skills\":[\"C\",\"C++\",\"C#\"],\"Age\":32,\"Online\":true}");
hashTable = parser.parseHashTable(json);
}
TEST_METHOD(HashTable_Success_ReturnsTrue)
{
Assert::IsTrue(hashTable.success());
}
TEST_METHOD(HashTable_GetString_ReturnsExpectedValue)
{
string name = hashTable.getString("Name");
Assert::AreEqual(name, string("Blanchon"));
}
TEST_METHOD(HashTable_GetArray_ReturnsExpectedValue)
{
JsonArray skills = hashTable.getArray("Skills");
string skill0 = skills.getString(0);
Assert::AreEqual(skill0, string("C"));
string skill1 = skills.getString(1);
Assert::AreEqual(skill1, string("C++"));
string skill2 = skills.getString(2);
Assert::AreEqual(skill2, string("C#"));
}
TEST_METHOD(HashTable_GetLong_ReturnsExpectedValue)
{
int age = hashTable.getLong("Age");
Assert::AreEqual(32, age);
}
TEST_METHOD(HashTable_GetBool_ReturnsExpectedValue)
{
bool online = hashTable.getBool("Online");
Assert::AreEqual(true, online);
}
};
}

10
LICENSE.md Normal file
View File

@ -0,0 +1,10 @@
The MIT License (MIT)
---------------------
Copyright © 2014 Benoit BLANCHON
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,17 +1,17 @@
Arduino JSON library
====================
*A simple and efficient JSON library for embedded systems.*
*An elegant and efficient JSON library for embedded systems.*
It's design to be very lightweight, works without any allocation on the heap (no malloc).
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
It has been written with Arduino in mind, but it isn't linked to Arduino libraries so you can use this library in any other C++ project.
Features
--------
* JSON decoding: [more details here](/JsonParser/)
* JSON encoding: [more details here](/JsonGenerator/)
* JSON decoding: [see documentation here](/JsonParser/)
* JSON encoding: [see documentation here](/JsonGenerator/)
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
@ -22,9 +22,9 @@ Feature comparison
| Library | Memory allocation | Nested objects | Parser size | Encoder size |
| ------------ | ----------------- | -------------- | ----------- | ------------- |
| Arduino JSON | static | yes | 2616 Bytes | 628 bytes |
| json-arduino | dynamic | no | 3348 (+28%) | not supported |
| aJson | dynamic | yes | 5088 (+94%) | 4678 (+640%) |
| Arduino JSON | static | yes | 2760 Bytes | 862 bytes |
| json-arduino | dynamic | no | 3348 (+21%) | not supported |
| aJson | dynamic | yes | 5088 (+84%) | 4678 (+540%) |
"Parser size" was measured with a program parsing `{"sensor":"outdoor","value":25.6}`.
For each library, I wrote a program that extracts a string and a float. I subtracted the size of a program doing the same without any JSON parsing involved. [Source files are here](https://gist.github.com/bblanchon/e8ba914a7109f3642c0f).
@ -49,8 +49,10 @@ From Arduino's Forum user `gbathree`:
From StackOverflow user `thegreendroid`:
> It has a really elegant, simple API and it works like a charm on embedded and Windows/Linux platforms. We recently started using this on an embedded project and I can vouch for its quality.
Links
Related blog posts
-----
* [The project for which I made me this library](http://blog.benoitblanchon.fr/rfid-payment-terminal/)
* [Blog post on the motivation for this library](http://blog.benoitblanchon.fr/arduino-json-parser/)
* [The project I originally wrote this library for](http://blog.benoitblanchon.fr/rfid-payment-terminal/)
* [Motivation for this library](http://blog.benoitblanchon.fr/arduino-json-parser/)
* [Release of version 2](http://blog.benoitblanchon.fr/arduino-json-v2-0/)
* [Release of version 3](http://blog.benoitblanchon.fr/arduino-json-v3-0/)

View File

@ -0,0 +1,43 @@
/*
* Arduino JSON library - IndentedPrint example
* Benoit Blanchon 2014 - MIT License
*/
#include <JsonGenerator.h>
using namespace ArduinoJson::Generator;
void setup()
{
Serial.begin(9600);
JsonObject<1> json;
json["key"] = "value";
IndentedPrint serial(Serial);
serial.setTabSize(4);
serial.println("This is at indentation 0");
serial.indent();
serial.println("This is at indentation 1");
serial.println("This is also at indentation 1");
serial.indent();
serial.println("This is at indentation 2");
serial.println("You can print JSON here, as usual:");
serial.println(json);
serial.println();
serial.println("But you can also prettyPrint JSON here:");
json.prettyPrintTo(serial);
serial.println();
serial.unindent();
serial.unindent();
serial.println("This is back at indentation 0");
}
void loop()
{
}

View File

@ -15,12 +15,15 @@ void setup()
array.add<6>(48.756080); // 6 is the number of decimals to print
array.add<6>(2.302038); // if not specified, 2 digits are printed
JsonHashTable<3> root;
root.add("sensor", "gps");
root.add("time", 1351824120);
root.add("data", array);
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Serial.println();
root.prettyPrintTo(Serial); // same string indented
}
void loop()

View File

@ -11,31 +11,27 @@ void setup()
{
Serial.begin(9600);
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
char json [] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonParser<16> parser;
JsonHashTable root = parser.parseHashTable(json);
JsonObject root = parser.parse(json);
if (!root.success())
{
Serial.println("JsonParser.parseHashTable() failed");
Serial.println("JsonParser.parse() failed");
return;
}
char* sensor = root.getString("sensor");
Serial.println(sensor);
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
long time = root.getLong("time");
Serial.println(sensor);
Serial.println(time);
JsonArray coords = root.getArray("data");
for (int i = 0; i < coords.getLength(); i++)
{
double value = coords.getDouble(i);
Serial.println(value, 6);
}
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
void loop()

View File

@ -1,10 +1,6 @@
JsonParser KEYWORD1
JsonArray KEYWORD1
JsonHashTable KEYWORD1
getArray KEYWORD2
getBool KEYWORD2
getDouble KEYWORD2
getHashTableKEYWORD2
getLong KEYWORD2
parseArray KEYWORD2
parseHashTable KEYWORD2
JsonObject KEYWORD1
add KEYWORD2
parse KEYWORD2
success KEYWORD2