Merge branch '4.0'

Conflicts:
	JsonGenerator.cpp
	JsonGenerator.h
	JsonGenerator/EscapedString.cpp
	JsonGenerator/EscapedString.h
	JsonGenerator/IndentedPrint.cpp
	JsonGenerator/IndentedPrint.h
	JsonGenerator/JsonArray.h
	JsonGenerator/JsonArrayBase.cpp
	JsonGenerator/JsonArrayBase.h
	JsonGenerator/JsonObject.h
	JsonGenerator/JsonObjectBase.cpp
	JsonGenerator/JsonObjectBase.h
	JsonGenerator/JsonPrettyPrint.cpp
	JsonGenerator/JsonPrettyPrint.h
	JsonGenerator/JsonPrintable.cpp
	JsonGenerator/JsonPrintable.h
	JsonGenerator/JsonValue.cpp
	JsonGenerator/JsonValue.h
	JsonGenerator/Print.cpp
	JsonGenerator/Print.h
	JsonGenerator/Printable.h
	JsonGenerator/StringBuilder.cpp
	JsonGenerator/StringBuilder.h
	JsonGeneratorTests/EscapedStringTests.cpp
	JsonGeneratorTests/Issue10.cpp
	JsonGeneratorTests/JsonArrayTests.cpp
	JsonGeneratorTests/JsonObject_Indexer_Tests.cpp
	JsonGeneratorTests/JsonObject_PrintTo_Tests.cpp
	JsonGeneratorTests/JsonValue_Cast_Tests.cpp
	JsonGeneratorTests/JsonValue_PrintTo_Tests.cpp
	JsonGeneratorTests/PrettyPrint_Array_Tests.cpp
	JsonGeneratorTests/PrettyPrint_Object_Tests.cpp
	JsonGeneratorTests/PrettyPrint_String_Tests.cpp
	JsonGeneratorTests/StringBuilderTests.cpp
	JsonParser.cpp
	JsonParser.h
	JsonParser/JsonArray.cpp
	JsonParser/JsonArray.h
	JsonParser/JsonArrayIterator.h
	JsonParser/JsonObject.cpp
	JsonParser/JsonObject.h
	JsonParser/JsonObjectIterator.h
	JsonParser/JsonPair.h
	JsonParser/JsonParser.h
	JsonParser/JsonParserBase.cpp
	JsonParser/JsonParserBase.h
	JsonParser/JsonToken.cpp
	JsonParser/JsonToken.h
	JsonParser/JsonValue.cpp
	JsonParser/JsonValue.h
	JsonParser/README.md
	JsonParserTests/GbathreeBug.cpp
	JsonParserTests/JsonArrayIteratorTests.cpp
	JsonParserTests/JsonArrayTests.cpp
	JsonParserTests/JsonObjectIteratorTests.cpp
	JsonParserTests/JsonObjectTests.cpp
	JsonParserTests/JsonStringTests.cpp
	JsonParserTests/TestHashGenerator.cpp
	README.md
	library.json
This commit is contained in:
Benoit Blanchon
2014-11-29 14:29:45 +01:00
346 changed files with 150144 additions and 5512 deletions

11
.gitignore vendored
View File

@ -1,6 +1,5 @@
*.sdf
*.user
*.suo
Debug
ipch
*.opensdf
.DS_Store
/.idea
/build
/bin
/lib

6
.travis.yml Normal file
View File

@ -0,0 +1,6 @@
language: c++
compiler:
- gcc
- clang
before_script: cmake .
script: make && make test

View File

@ -1,40 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JsonGeneratorTests", "JsonGeneratorTests\JsonGeneratorTests.vcxproj", "{B9545D97-E084-4A19-8E48-929157064360}"
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
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B9545D97-E084-4A19-8E48-929157064360}.Debug|Win32.ActiveCfg = Debug|Win32
{B9545D97-E084-4A19-8E48-929157064360}.Debug|Win32.Build.0 = Debug|Win32
{B9545D97-E084-4A19-8E48-929157064360}.Release|Win32.ActiveCfg = Release|Win32
{B9545D97-E084-4A19-8E48-929157064360}.Release|Win32.Build.0 = Release|Win32
{4DD596EF-0185-4AB4-A3C2-F20C496F7806}.Debug|Win32.ActiveCfg = Debug|Win32
{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
EndGlobalSection
EndGlobal

View File

@ -1,13 +0,0 @@
#!/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,6 +1,15 @@
Arduino JSON: change log
========================
v4.0
----
* Unified parser and generator API (issue #23)
* Updated library layout, now requires Arduino 1.0.6 or newer
**BREAKING CHANGE**: API changed significantly, see `doc/Migrating to the new API.md`.
v3.4
----

15
CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 2.8.4)
project(ArduinoJson)
enable_testing()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -W4)
endif()
add_subdirectory(src)
add_subdirectory(test)

View File

@ -1 +0,0 @@
find \( -iname '*.cpp' -o -iname '*.h' \) -exec sed -i -e '$a\' {} \;

View File

@ -1,15 +0,0 @@
/*
* malloc-free JSON parser for Arduino
* Benoit Blanchon 2014 - MIT License
*/
// 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/JsonPrettyPrint.cpp"
#include "JsonGenerator/JsonPrintable.cpp"
#include "JsonGenerator/StringBuilder.cpp"

View File

@ -1,7 +0,0 @@
/*
* malloc-free JSON parser for Arduino
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonGenerator/JsonArray.h"
#include "JsonGenerator/JsonObject.h"

View File

@ -1,45 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "EscapedString.h"
using namespace ArduinoJson::Internals;
static inline char getSpecialChar(char c)
{
// Optimized for code size on a 8-bit AVR
const char* p = "\"\"\\\\\bb\ff\nn\rr\tt\0";
while (p[0] && p[0] != c)
{
p += 2;
}
return p[1];
}
static inline size_t printCharTo(char c, Print& p)
{
char specialChar = getSpecialChar(c);
return specialChar != 0
? p.write('\\') + p.write(specialChar)
: p.write(c);
}
size_t EscapedString::printTo(const char* s, Print& p)
{
if (!s) return p.print("null");
size_t n = p.write('\"');
while (*s)
{
n += printCharTo(*s++, p);
}
return n + p.write('\"');
}

View File

@ -1,20 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "Print.h"
namespace ArduinoJson
{
namespace Internals
{
class EscapedString
{
public:
static size_t printTo(const char*, Print&);
};
}
}

View File

@ -1,45 +0,0 @@
#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

@ -1,53 +0,0 @@
/*
* 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

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

View File

@ -1,34 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonArrayBase.h"
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
size_t JsonArrayBase::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 JsonValue* current = _items;
for (int i = _count; i > 0; i--)
{
n += current->printTo(p);
current++;
if (i > 1)
{
n += p.write(',');
}
}
n += p.write(']');
return n;
}

View File

@ -1,79 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonPrintable.h"
#include "JsonValue.h"
namespace ArduinoJson
{
namespace Generator
{
class JsonArrayBase : public JsonPrintable
{
public:
JsonArrayBase(JsonValue* items, int capacity)
: _items(items), _capacity(capacity), _count(0)
{
}
void add(const Printable& value)
{
addIfPossible<const Printable&>(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>
void add(double value)
{
if (_count >= _capacity) return;
JsonValue& v = _items[_count++];
v.set<DIGITS>(value);
}
virtual size_t printTo(Print& p) const;
using JsonPrintable::printTo;
private:
JsonValue* _items;
int _capacity, _count;
template<typename T>
void addIfPossible(T value)
{
if (_count < _capacity)
_items[_count++] = value;
}
};
}
}

View File

@ -1,101 +0,0 @@
<?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

@ -1,84 +0,0 @@
<?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,44 +0,0 @@
/*
* 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

@ -1,92 +0,0 @@
/*
* 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,62 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonPrintable.h"
#include "JsonValue.h"
#include "EscapedString.h"
namespace ArduinoJson
{
namespace Generator
{
typedef const char* JsonKey;
class JsonObjectBase : public JsonPrintable
{
public:
JsonValue& operator[](JsonKey);
bool containsKey(JsonKey) const;
void remove(JsonKey key);
template<typename T>
void add(JsonKey key, T value)
{
operator[](key) = value;
}
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

@ -1,97 +0,0 @@
/*
* 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

@ -1,52 +0,0 @@
/*
* 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

@ -1,35 +0,0 @@
/*
* 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

@ -1,40 +0,0 @@
/*
* 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

@ -1,33 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "EscapedString.h"
#include "JsonValue.h"
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
size_t JsonValue::printBoolTo(const Content& c, Print& p)
{
return p.print(c.asBool ? "true" : "false");
}
size_t JsonValue::printLongTo(const Content& c, Print& p)
{
return p.print(c.asLong);
}
size_t JsonValue::printPrintableTo(const Content& c, Print& p)
{
if (c.asPrintable)
return c.asPrintable->printTo(p);
else
return p.print("null");
}
size_t JsonValue::printStringTo(const Content& c, Print& p)
{
return EscapedString::printTo(c.asString, p);
}

View File

@ -1,135 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "EscapedString.h"
#include "Printable.h"
#include "StringBuilder.h"
namespace ArduinoJson
{
namespace Generator
{
class JsonValue
{
public:
void operator=(bool value)
{
_printToImpl = &printBoolTo;
_content.asBool = value;
}
void operator=(long value)
{
_printToImpl = &printLongTo;
_content.asLong = value;
}
void operator=(int value)
{
_printToImpl = &printLongTo;
_content.asLong = value;
}
void operator=(const Printable& value)
{
_printToImpl = &printPrintableTo;
_content.asPrintable = &value;
}
void operator=(const char* value)
{
_printToImpl = &printStringTo;
_content.asString = value;
}
void operator=(double value)
{
set<2>(value);
}
template <int DIGITS>
void set(double value)
{
_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 static_cast<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;
double asDouble;
long asLong;
const Printable* asPrintable;
const char* asString;
};
Content _content;
size_t(*_printToImpl)(const Content&, Print&);
static size_t printBoolTo(const Content&, Print&);
static size_t printLongTo(const Content&, Print&);
static size_t printPrintableTo(const Content&, Print&);
static size_t printStringTo(const Content&, Print&);
template <int DIGITS>
static size_t printDoubleTo(const Content& c, Print& p)
{
return p.print(c.asDouble, DIGITS);
}
};
}
}

View File

@ -1,56 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#ifndef ARDUINO
#include "Print.h"
#include <string> // for sprintf, strchr and strcat
size_t Print::print(const char s[])
{
size_t n = 0;
while (*s)
{
n += write(*s++);
}
return n;
}
static inline void ensureStringContainsPoint(char* s)
{
// Ensures that the decimal point is present.
// For example, we don't want "0" but "0.0".
// Otherwise, the value would be considered as an integer by some parsers
// See issue #22
if (!strchr(s, '.'))
strcat(s, ".0");
}
size_t Print::print(double value, int digits)
{
char tmp[32];
sprintf(tmp, "%.*lg", digits+1, value);
if (digits>0)
ensureStringContainsPoint(tmp);
return print(tmp);
}
size_t Print::print(long value)
{
char tmp[32];
sprintf(tmp, "%ld", value);
return print(tmp);
}
size_t Print::println()
{
return write('\r') + write('\n');
}
#endif

View File

@ -1,30 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#ifndef ARDUINO
#include <stddef.h>
#include <stdint.h>
// This class reproduces Arduino's Print
class Print
{
public:
virtual size_t write(uint8_t) = 0;
size_t print(const char[]);
size_t print(double, int = 2);
size_t print(long);
size_t println();
};
#else
#include <Print.h>
#endif

View File

@ -1,23 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#ifndef ARDUINO
class Print;
class Printable
{
public:
virtual size_t printTo(Print& p) const = 0;
};
#else
#include <Printable.h>
#endif

View File

@ -1,247 +0,0 @@
Arduino JSON library - Generator
================================
*An elegant and efficient JSON encoder for embedded systems.*
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
It 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
--------
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
* Supports nested objects
* Supports indented output
* Implements Arduino's `Printable interface
* MIT License
Example
-------
JsonArray<2> array;
array.add<6>(48.756080); // <6> specifies the number of digits in the output
array.add<6>(2.302038); // (the default is 2)
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
How to use?
------------
### 1. Install the library
Download the library and extract it to:
<your Arduino Sketch folder>/libraries/ArduinoJson
### 2. Import in your sketch
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 a JSON Array or a JSON Object.
#### JSON Array
You create an array with the following line:
JsonArray<8> array;
See the little `<8>`? It's a template parameter that gives the capacity of the array, it's the maximum number of elements you can put in it.
> ##### About the capacity
> As stated in the feature list, this library works with a fixed memory allocation.
> This means that the size of the object must be know at the compilation time, therefore you can **not** use a variable to set the capacity of the array.
Then you can add strings, integer, booleans, etc:
array.add("bazinga!");
array.add(42);
array.add(true);
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"
> ##### About floating point precision
> The overload of `add()` with 2 parameters allows you to specify the number of decimals to save in the JSON string.
> When you use the overload with one parameter, you use the default number of decimals which is two.
> Note that this behavior is the exact same as Arduino's `Print::print(double,int);` which is implemented by `Serial`.
> So you may already be familiar with it.
Finally you can add nested object to the array:
JsonArray<8> nestedArray;
array.add(nestedArray);
or
JsonObject<8> nestedObject;
array.add(nestedObject);
> ##### 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
#### JSON Object
You create a JSON object (ie hash-table/dictionary) with the following line:
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:
object["key1"] = "bazinga!";
object["key2"] = 42;
object["key3"] = true;
As for the arrays, there are two syntaxes for the floating point values:
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;
object["key6"] = nestedArray;
or
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
There are two ways tho get the resulting JSON string.
Depending on your project, you may need to dump the string in a classic `char[]` or send it to a stream like `Serial` or `EthernetClient `.
Both ways are the easy way :-)
#### Use a classic `char[]`
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:
Serial.print(array);
or
array.printTo(Serial);
> ##### About the 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`, `Wire`...
Memory usage
------------
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 |
| 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

@ -1,17 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "StringBuilder.h"
using namespace ArduinoJson::Internals;
size_t StringBuilder::write(uint8_t c)
{
if (_length >= _capacity) return 0;
_buffer[_length++] = c;
_buffer[_length] = 0;
return 1;
}

View File

@ -1,31 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "Print.h"
namespace ArduinoJson
{
namespace Internals
{
class StringBuilder : public Print
{
public:
StringBuilder(char* buf, int size)
: _buffer(buf), _capacity(size - 1), _length(0)
{
_buffer[0] = 0;
}
virtual size_t write(uint8_t c);
private:
char* _buffer;
int _capacity;
int _length;
};
}
}

View File

@ -1,95 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "EscapedString.h"
#include "StringBuilder.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(EscapedStringTests)
{
char buffer[1024];
size_t returnValue;
public:
TEST_METHOD(Null)
{
whenInputIs(0);
outputMustBe("null");
}
TEST_METHOD(EmptyString)
{
whenInputIs("");
outputMustBe("\"\"");
}
TEST_METHOD(QuotationMark)
{
whenInputIs("\"");
outputMustBe("\"\\\"\"");
}
TEST_METHOD(ReverseSolidus)
{
whenInputIs("\\");
outputMustBe("\"\\\\\"");
}
TEST_METHOD(Solidus)
{
whenInputIs("/");
outputMustBe("\"/\""); // but the JSON format allows \/
}
TEST_METHOD(Backspace)
{
whenInputIs("\b");
outputMustBe("\"\\b\"");
}
TEST_METHOD(Formfeed)
{
whenInputIs("\f");
outputMustBe("\"\\f\"");
}
TEST_METHOD(Newline)
{
whenInputIs("\n");
outputMustBe("\"\\n\"");
}
TEST_METHOD(CarriageReturn)
{
whenInputIs("\r");
outputMustBe("\"\\r\"");
}
TEST_METHOD(HorizontalTab)
{
whenInputIs("\t");
outputMustBe("\"\\t\"");
}
private:
void whenInputIs(const char* input)
{
StringBuilder sb(buffer, sizeof(buffer));
returnValue = EscapedString::printTo(input, sb);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), returnValue);
}
};
}

View File

@ -1,73 +0,0 @@
#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

@ -1,162 +0,0 @@
/*
* 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(JsonArrayTests)
{
JsonArray<2> array;
char buffer[256];
public:
TEST_METHOD(Empty)
{
outputMustBe("[]");
}
TEST_METHOD(Null)
{
array.add(static_cast<char*>(0));
outputMustBe("[null]");
}
TEST_METHOD(OneString)
{
array.add("hello");
outputMustBe("[\"hello\"]");
}
TEST_METHOD(TwoStrings)
{
array.add("hello");
array.add("world");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneStringOverCapacity)
{
array.add("hello");
array.add("world");
array.add("lost");
outputMustBe("[\"hello\",\"world\"]");
}
TEST_METHOD(OneDoubleDefaultDigits)
{
array.add(3.14159265358979323846);
outputMustBe("[3.14]");
}
TEST_METHOD(OneDoubleFourDigits)
{
array.add<4>(3.14159265358979323846);
outputMustBe("[3.1416]");
}
TEST_METHOD(OneInteger)
{
array.add(1);
outputMustBe("[1]");
}
TEST_METHOD(TwoIntegers)
{
array.add(1);
array.add(2);
outputMustBe("[1,2]");
}
TEST_METHOD(OneIntegerOverCapacity)
{
array.add(1);
array.add(2);
array.add(3);
outputMustBe("[1,2]");
}
TEST_METHOD(OneTrue)
{
array.add(true);
outputMustBe("[true]");
}
TEST_METHOD(OneFalse)
{
array.add(false);
outputMustBe("[false]");
}
TEST_METHOD(TwoBooleans)
{
array.add(false);
array.add(true);
outputMustBe("[false,true]");
}
TEST_METHOD(OneBooleanOverCapacity)
{
array.add(false);
array.add(true);
array.add(false);
outputMustBe("[false,true]");
}
TEST_METHOD(OneEmptyNestedArray)
{
JsonArray<1> nestedArray;
array.add(nestedArray);
outputMustBe("[[]]");
}
TEST_METHOD(OneEmptyNestedHash)
{
JsonObject<1> nestedObject;
array.add(nestedObject);
outputMustBe("[{}]");
}
TEST_METHOD(OneNestedArrayWithOneInteger)
{
JsonArray<1> nestedArray;
nestedArray.add(1);
array.add(nestedArray);
outputMustBe("[[1]]");
}
private:
void outputMustBe(const char* expected)
{
size_t n = array.printTo(buffer, sizeof(buffer));
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), n);
}
};
}

View File

@ -1,107 +0,0 @@
<?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>{B9545D97-E084-4A19-8E48-929157064360}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>JsonGeneratorTests</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(ProjectDir)/../JsonGenerator;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(ProjectDir)/../JsonGenerator;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ARDUINO_JSON_NO_DEPRECATION_WARNING;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<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="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>
<ProjectReference Include="..\JsonGenerator\JsonGenerator.vcxproj">
<Project>{c6536d27-738d-4ceb-a2bc-e13c8897d894}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,52 +0,0 @@
<?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>
<ClCompile Include="JsonArrayTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StringBuilderTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="EscapedStringTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<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,73 +0,0 @@
/*
* 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

@ -1,152 +0,0 @@
/*
* 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"] = static_cast<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

@ -1,80 +0,0 @@
/*
* 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(
reinterpret_cast<const void*>(&expected),
reinterpret_cast<const void*>(&actual));
}
};
}

View File

@ -1,109 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "StringBuilder.h"
#include "JsonValue.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(JsonValue_PrintTo_Tests)
{
char buffer[1024];
size_t returnValue;
public:
TEST_METHOD(String)
{
setValueTo("hello");
outputMustBe("\"hello\"");
}
TEST_METHOD(ZeroFloat)
{
setValueTo(0.0f);
outputMustBe("0.0");
}
TEST_METHOD(Float)
{
setValueTo(3.1415f);
outputMustBe("3.14");
}
TEST_METHOD(DoubleZeroDigits)
{
setValueTo<0>(3.14159265358979323846);
outputMustBe("3");
}
TEST_METHOD(DoubleOneDigit)
{
setValueTo<1>(3.14159265358979323846);
outputMustBe("3.1");
}
TEST_METHOD(DoubleTwoDigits)
{
setValueTo<2>(3.14159265358979323846);
outputMustBe("3.14");
}
TEST_METHOD(Integer)
{
setValueTo(314);
outputMustBe("314");
}
TEST_METHOD(Char)
{
setValueTo('A');
outputMustBe("65");
}
TEST_METHOD(Short)
{
setValueTo(static_cast<short>(314));
outputMustBe("314");
}
TEST_METHOD(Long)
{
setValueTo(314159265L);
outputMustBe("314159265");
}
private:
template<int DIGITS>
void setValueTo(double value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
jsonValue.set<DIGITS>(value);
returnValue = jsonValue.printTo(sb);
}
template<typename T>
void setValueTo(T value)
{
StringBuilder sb(buffer, sizeof(buffer));
JsonValue jsonValue;
jsonValue = value;
returnValue = jsonValue.printTo(sb);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
Assert::AreEqual(strlen(expected), returnValue);
}
};
}

View File

@ -1,91 +0,0 @@
/*
* 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

@ -1,89 +0,0 @@
/*
* 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

@ -1,76 +0,0 @@
/*
* 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,85 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "CppUnitTest.h"
#include "StringBuilder.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ArduinoJson::Internals;
namespace JsonGeneratorTests
{
TEST_CLASS(StringBuilderTests)
{
char buffer[20];
Print* sb;
size_t returnValue;
public:
TEST_METHOD_INITIALIZE(Initialize)
{
sb = new StringBuilder(buffer, sizeof(buffer));
}
TEST_METHOD(InitialState)
{
outputMustBe("");
}
TEST_METHOD(OverCapacity)
{
print("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
resultMustBe(19);
print("ABC");
resultMustBe(0);
outputMustBe("ABCDEFGHIJKLMNOPQRS");
}
TEST_METHOD(EmptyString)
{
print("");
resultMustBe(0);
outputMustBe("");
}
TEST_METHOD(OneString)
{
print("ABCD");
resultMustBe(4);
outputMustBe("ABCD");
}
TEST_METHOD(TwoStrings)
{
print("ABCD");
resultMustBe(4);
print("EFGH");
resultMustBe(4);
outputMustBe("ABCDEFGH");
}
private:
void print(const char* value)
{
returnValue = sb->print(value);
}
void outputMustBe(const char* expected)
{
Assert::AreEqual(expected, buffer);
}
void resultMustBe(size_t expected)
{
Assert::AreEqual(expected, returnValue);
}
};
}

View File

@ -1,13 +0,0 @@
/*
* 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/JsonObject.cpp"
#include "JsonParser/JsonParserBase.cpp"
#include "JsonParser/JsonValue.cpp"
#include "JsonParser/JsonToken.cpp"
#include "JsonParser/jsmn.cpp"

View File

@ -1,6 +0,0 @@
/*
* malloc-free JSON parser for Arduino
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonParser/JsonParser.h"

View File

@ -1,14 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#include "JsonArray.h"
#include "JsonObject.h"
using namespace ArduinoJson::Parser;
DEPRECATED JsonObject JsonArray::getHashTable(int index)
{
return operator[](index);
}

View File

@ -1,103 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonValue.h"
#include "JsonArrayIterator.h"
namespace ArduinoJson
{
namespace Parser
{
class JsonObject;
// A JSON array
class JsonArray : JsonValue
{
public:
// Create an invalid array
JsonArray()
{
}
// Convert a JsonValue into a JsonArray
JsonArray(JsonValue value)
: JsonValue(value)
{
}
// 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);
}
// Obsolete: Use operator[] instead
DEPRECATED bool getBool(int index)
{
return operator[](index);
}
// Obsolete: Use operator[] instead
DEPRECATED double getDouble(int index)
{
return operator[](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

@ -1,46 +0,0 @@
/*
* 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,15 +0,0 @@
/*
* 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);
}

View File

@ -1,102 +0,0 @@
/*
* 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,58 +0,0 @@
/*
* 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();
}
};
}
}

View File

@ -1,37 +0,0 @@
/*
* 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,35 +0,0 @@
/*
* Arduino JSON library
* Benoit Blanchon 2014 - MIT License
*/
#pragma once
#include "JsonParserBase.h"
namespace ArduinoJson
{
namespace Parser
{
// 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 : public JsonParserBase
{
public:
JsonParser()
: JsonParserBase(_tokens, MAX_TOKENS)
{
}
private:
jsmntok_t _tokens[MAX_TOKENS];
};
}
}

View File

@ -1,96 +0,0 @@
<?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

@ -1,69 +0,0 @@
<?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

@ -1,20 +0,0 @@
/*
* 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

@ -1,49 +0,0 @@
/*
* 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;
};
}
}

View File

@ -1,71 +0,0 @@
/*
* 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);
}

View File

@ -1,99 +0,0 @@
/*
* 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);
};
}
}

View File

@ -1,110 +0,0 @@
/*
* 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();
}

View File

@ -1,72 +0,0 @@
/*
* 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

@ -1,250 +0,0 @@
Arduino JSON library - Parser
=============================
This library is an thin C++ wrapper around the *jsmn* tokenizer: http://zserge.com/jsmn.html
It's design to be very lightweight, works without any allocation on the heap (no malloc) and supports nested objects.
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
--------
* Based on the well-proven [jsmn](http://zserge.com/jsmn.html) tokenizer
* Supports nested objects
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
* MIT License
Example
-------
JsonParser<32> parser;
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonObject root = parser.parse(json);
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
How to use ?
-------------
### 1. Install the library
Download the library and extract it to:
<your Arduino Sketch folder>/libraries/ArduinoJson
### 2. Import in your sketch
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
To extract data from the JSON string, you need to create a `JsonParser`, and specify the number of token you allocate for the parser itself:
JsonParser<32> parser;
> #### How to choose the number of tokens ?
> 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 9 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.
> Each token takes 8 bytes, so `sizeof(JsonParser<32>)` is 256 bytes which is quite big in an Arduino with only 2KB of RAM.
> Don't forget that you also have to store the JSON string in RAM and it's probably big.
> 32 tokens may seem small, but it's very decent for an 8-bit processor, you wouldn't get better results with other JSON libraries.
### 4. Extract data
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 an object (like `{"key":"value"}`) or an array (like `[1,2]`).
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.
#### Object
Consider we have a `char json[]` containing to the following JSON string:
{
"sensor":"gps",
"time":1351824120,
"data":[48.756080,2.302038]
}
In this case the string contains a JSON object, so you need to extract a `JsonObject`:
JsonObject root = parser.parse(json);
To check if the parsing was successful, you must check:
if (!root.success())
{
// Parsing fail: could be an invalid JSON, or too many tokens
}
And then extract the member you need:
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
You can also iterate through the key-value pairs of the object:
for (JsonObjectIterator i=root.begin(); i!=root.end(); ++i)
{
Serial.println(i.key());
Serial.println((char*)i.value());
}
#### Array
Consider we have a `char json[]` containing to the following JSON string:
[
[ 1.2, 3.4 ],
[ 5.6, 7.8 ]
]
In this case the root object of the JSON string is an array, so you need to extract a `JsonArray`:
JsonArray root = parser.parse(json);
To check if the parsing was successful, you must check:
if (!root.success())
{
// Parsing fail: could be an invalid JSON, or too many tokens
}
And then extract the content by its index in the array:
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::parse()` failed.
There are basically two reasons why they may fail:
1. the JSON string is invalid
2. the JSON string contains more tokens that the parser can store
So, if you are sure the JSON string is correct and you still can't parse it, you should slightly increase the number of token of the parser.
### 2. Not enough memory
You may go into unpredictable trouble if you allocate more memory than your processor really has.
It's a very common issue in embedded development.
To diagnose this, look at every big objects in you code and sum their size to check that they fit in RAM.
For example, don't do this:
char json[1024]; // 1 KB
JsonParser<64> parser; // 512 B
because it may be too big for a processor with only 2 KB: you need free memory to store other variables and the call stack.
That is why an 8-bit processor is not able to parse long and complex JSON strings.
### 3. JsonParser not 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:
JsonArray getArray(char* json)
{
JsonParser<16> parser;
return parser.parseArray(parser);
}
because the local variable `parser` will be *removed* from memory when the function `getArray()` returns, and the pointer inside `JsonArray` will point to an invalid location.
### 4. JSON string is altered
This will probably never be an issue, but you need to be aware of this feature.
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.
Memory usage
------------
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 |
| ------------ | ------------- |
| `Parser<N>` | 4 + 8 x N |
| `JsonArray` | 4 |
| `JsonObject` | 4 |
| `JsonValue` | 4 |
Code size
---------
The sizes have been obtained with Arduino IDE 1.0.5 for a Duemilanove.
### Minimum setup
| Function | Size |
| ------------------------------------ | ---- |
| `jsmn_parse()` | 962 |
| `JsonValue::operator[](char const*)` | 218 |
| `JsonParserBase::parse()` | 116 |
| `JsonValue::operator[](int)` | 108 |
| `strcmp()` | 18 |
### Additional space for integers
| Function | Size |
| ---------------------------- | ---- |
| `strtol()` | 606 |
| `JsonValue::operator long()` | 94 |
### Additional space for floating points
| Function | Size |
| -------------------------------- | ----- |
| `strtod()` | 1369 |
| `JsonValue::operator double()` | 82 |

View File

@ -1,255 +0,0 @@
#include <stdlib.h>
#include "jsmn.h"
/**
* Allocates a fresh unused token from the token pull.
*/
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *tok;
if (parser->toknext >= num_tokens) {
return NULL;
}
tok = &tokens[parser->toknext++];
tok->start = tok->end = -1;
tok->size = 0;
#ifdef JSMN_PARENT_LINKS
tok->parent = -1;
#endif
return tok;
}
/**
* Fills token type and boundaries.
*/
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
int start, int end) {
token->type = type;
token->start = start;
token->end = end;
token->size = 0;
}
/**
* Fills next available token with JSON primitive.
*/
static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start;
start = parser->pos;
for (; js[parser->pos] != '\0'; parser->pos++) {
switch (js[parser->pos]) {
#ifndef JSMN_STRICT
/* In strict mode primitive must be followed by "," or "}" or "]" */
case ':':
#endif
case '\t' : case '\r' : case '\n' : case ' ' :
case ',' : case ']' : case '}' :
goto found;
}
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
#ifdef JSMN_STRICT
/* In strict mode primitive must be followed by a comma/object/array */
parser->pos = start;
return JSMN_ERROR_PART;
#endif
found:
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
parser->pos--;
return JSMN_SUCCESS;
}
/**
* Filsl next token with JSON string.
*/
static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
jsmntok_t *tokens, size_t num_tokens) {
jsmntok_t *token;
int start = parser->pos;
parser->pos++;
/* Skip starting quote */
for (; js[parser->pos] != '\0'; parser->pos++) {
char c = js[parser->pos];
/* Quote: end of string */
if (c == '\"') {
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL) {
parser->pos = start;
return JSMN_ERROR_NOMEM;
}
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
return JSMN_SUCCESS;
}
/* Backslash: Quoted symbol expected */
if (c == '\\') {
parser->pos++;
switch (js[parser->pos]) {
/* Allowed escaped symbols */
case '\"': case '/' : case '\\' : case 'b' :
case 'f' : case 'r' : case 'n' : case 't' :
break;
/* Allows escaped symbol \uXXXX */
case 'u':
/* TODO */
break;
/* Unexpected symbol */
default:
parser->pos = start;
return JSMN_ERROR_INVAL;
}
}
}
parser->pos = start;
return JSMN_ERROR_PART;
}
/**
* Parse JSON string and fill tokens.
*/
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
unsigned int num_tokens) {
jsmnerr_t r;
int i;
jsmntok_t *token;
for (; js[parser->pos] != '\0'; parser->pos++) {
char c;
jsmntype_t type;
c = js[parser->pos];
switch (c) {
case '{': case '[':
token = jsmn_alloc_token(parser, tokens, num_tokens);
if (token == NULL)
return JSMN_ERROR_NOMEM;
if (parser->toksuper != -1) {
tokens[parser->toksuper].size++;
#ifdef JSMN_PARENT_LINKS
token->parent = parser->toksuper;
#endif
}
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
token->start = parser->pos;
parser->toksuper = parser->toknext - 1;
break;
case '}': case ']':
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
#ifdef JSMN_PARENT_LINKS
if (parser->toknext < 1) {
return JSMN_ERROR_INVAL;
}
token = &tokens[parser->toknext - 1];
for (;;) {
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
token->end = parser->pos + 1;
parser->toksuper = token->parent;
break;
}
if (token->parent == -1) {
break;
}
token = &tokens[token->parent];
}
#else
for (i = parser->toknext - 1; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
if (token->type != type) {
return JSMN_ERROR_INVAL;
}
parser->toksuper = -1;
token->end = parser->pos + 1;
break;
}
}
/* Error if unmatched closing bracket */
if (i == -1) return JSMN_ERROR_INVAL;
for (; i >= 0; i--) {
token = &tokens[i];
if (token->start != -1 && token->end == -1) {
parser->toksuper = i;
break;
}
}
#endif
break;
case '\"':
r = jsmn_parse_string(parser, js, tokens, num_tokens);
if (r < 0) return r;
if (parser->toksuper != -1)
tokens[parser->toksuper].size++;
break;
case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
break;
#ifdef JSMN_STRICT
/* In strict mode primitives are: numbers and booleans */
case '-': case '0': case '1' : case '2': case '3' : case '4':
case '5': case '6': case '7' : case '8': case '9':
case 't': case 'f': case 'n' :
#else
/* In non-strict mode every unquoted value is a primitive */
default:
#endif
r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
if (r < 0) return r;
if (parser->toksuper != -1)
tokens[parser->toksuper].size++;
break;
#ifdef JSMN_STRICT
/* Unexpected char in strict mode */
default:
return JSMN_ERROR_INVAL;
#endif
}
}
for (i = parser->toknext - 1; i >= 0; i--) {
/* Unmatched opened object or array */
if (tokens[i].start != -1 && tokens[i].end == -1) {
return JSMN_ERROR_PART;
}
}
return JSMN_SUCCESS;
}
/**
* Creates a new parser based over a given buffer with an array of tokens
* available.
*/
void jsmn_init(jsmn_parser *parser) {
parser->pos = 0;
parser->toknext = 0;
parser->toksuper = -1;
}

View File

@ -1,67 +0,0 @@
#ifndef __JSMN_H_
#define __JSMN_H_
/**
* JSON type identifier. Basic types are:
* o Object
* o Array
* o String
* o Other primitive: number, boolean (true/false) or null
*/
typedef enum {
JSMN_PRIMITIVE = 0,
JSMN_OBJECT = 1,
JSMN_ARRAY = 2,
JSMN_STRING = 3
} jsmntype_t;
typedef enum {
/* Not enough tokens were provided */
JSMN_ERROR_NOMEM = -1,
/* Invalid character inside JSON string */
JSMN_ERROR_INVAL = -2,
/* The string is not a full JSON packet, more bytes expected */
JSMN_ERROR_PART = -3,
/* Everything was fine */
JSMN_SUCCESS = 0
} jsmnerr_t;
/**
* JSON token description.
* @param type type (object, array, string etc.)
* @param start start position in JSON data string
* @param end end position in JSON data string
*/
typedef struct {
jsmntype_t type;
int start;
int end;
int size;
#ifdef JSMN_PARENT_LINKS
int parent;
#endif
} jsmntok_t;
/**
* JSON parser. Contains an array of token blocks available. Also stores
* the string being parsed now and current position in that string
*/
typedef struct {
unsigned int pos; /* offset in the JSON string */
int toknext; /* next token to allocate */
int toksuper; /* superior token node, e.g parent object or array */
} jsmn_parser;
/**
* Create JSON parser over an array of tokens
*/
void jsmn_init(jsmn_parser *parser);
/**
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
* a single JSON object.
*/
jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
jsmntok_t *tokens, unsigned int num_tokens);
#endif /* __JSMN_H_ */

View File

@ -1,244 +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(GbathreeBug)
{
char json[1024];
JsonParser<200> parser;
JsonHashTable root;
public:
TEST_METHOD_INITIALIZE(Initialize)
{
// BUG described here:
// http://forum.arduino.cc/index.php?topic=172578.msg1608219#msg1608219
strcpy(json, "{ \"protocol_name\":\"fluorescence\",\"repeats\":1,\"wait\":0,\"averages\":1,\"measurements\":3,\"meas2_light\":15,\"meas1_baseline\":0,\"act_light\":20,\"pulsesize\":25,\"pulsedistance\":10000,\"actintensity1\":50,\"actintensity2\":255,\"measintensity\":255,\"calintensity\":255,\"pulses\":[50,50,50],\"act\":[2,1,2,2],\"red\":[2,2,2,2],\"detectors\":[[34,34,34,34],[34,34,34,34],[34,34,34,34],[34,34,34,34]],\"alta\":[2,2,2,2],\"altb\":[2,2,2,2],\"measlights\":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]],\"measlights2\":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]],\"altc\":[2,2,2,2],\"altd\":[2,2,2,2]}");
root = parser.parseHashTable(json);
}
TEST_METHOD(Root)
{
Assert::IsTrue(root.success());
}
TEST_METHOD(ProtocolName)
{
string protocol_name = root.getString("protocol_name");
Assert::AreEqual(string("fluorescence"), protocol_name);
}
TEST_METHOD(Repeats)
{
Assert::AreEqual(1L, root.getLong("repeats"));
}
TEST_METHOD(Wait)
{
Assert::AreEqual(0L, root.getLong("wait"));
}
TEST_METHOD(Measurements)
{
Assert::AreEqual(3L, root.getLong("measurements"));
}
TEST_METHOD(Meas2_Light)
{
Assert::AreEqual(15L, root.getLong("meas2_light"));
}
TEST_METHOD(Meas1_Baseline)
{
Assert::AreEqual(0L, root.getLong("meas1_baseline"));
}
TEST_METHOD(Act_Light)
{
Assert::AreEqual(20L, root.getLong("act_light"));
}
TEST_METHOD(Pulsesize)
{
Assert::AreEqual(25L, root.getLong("pulsesize"));
}
TEST_METHOD(Pulsedistance)
{
Assert::AreEqual(10000L, root.getLong("pulsedistance"));
}
TEST_METHOD(Actintensity1)
{
Assert::AreEqual(50L, root.getLong("actintensity1"));
}
TEST_METHOD(Actintensity2)
{
Assert::AreEqual(255L, root.getLong("actintensity2"));
}
TEST_METHOD(Measintensity)
{
Assert::AreEqual(255L, root.getLong("measintensity"));
}
TEST_METHOD(Calintensity)
{
Assert::AreEqual(255L, root.getLong("calintensity"));
}
TEST_METHOD(Pulses)
{
// "pulses":[50,50,50]
JsonArray array = root.getArray("pulses");
Assert::IsTrue(array.success());
Assert::AreEqual(3, array.getLength());
for (int i = 0; i < 3; i++)
{
Assert::AreEqual(50L, array.getLong(i));
}
}
TEST_METHOD(Act)
{
// "act":[2,1,2,2]
JsonArray array = root.getArray("act");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
Assert::AreEqual(2L, array.getLong(0));
Assert::AreEqual(1L, array.getLong(1));
Assert::AreEqual(2L, array.getLong(2));
Assert::AreEqual(2L, array.getLong(3));
}
TEST_METHOD(Detectors)
{
// "detectors":[[34,34,34,34],[34,34,34,34],[34,34,34,34],[34,34,34,34]]
JsonArray array = root.getArray("detectors");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(4, array.getArray(i).getLength());
for (int j = 0; j < 4; j++)
Assert::AreEqual(34L, array.getArray(i).getLong(j));
}
}
TEST_METHOD(Alta)
{
// alta:[2,2,2,2]
JsonArray array = root.getArray("alta");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(2L, array.getLong(i));
}
}
TEST_METHOD(Altb)
{
// altb:[2,2,2,2]
JsonArray array = root.getArray("altb");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(2L, array.getLong(i));
}
}
TEST_METHOD(Measlights)
{
// "measlights":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray array = root.getArray("measlights");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(4, array.getArray(i).getLength());
for (int j = 0; j < 4; j++)
Assert::AreEqual(15L, array.getArray(i).getLong(j));
}
}
TEST_METHOD(Measlights2)
{
// "measlights2":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray array = root.getArray("measlights2");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(4, array.getArray(i).getLength());
for (int j = 0; j < 4; j++)
Assert::AreEqual(15L, array.getArray(i).getLong(j));
}
}
TEST_METHOD(Altc)
{
// altc:[2,2,2,2]
JsonArray array = root.getArray("altc");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(2L, array.getLong(i));
}
}
TEST_METHOD(Altd)
{
// altd:[2,2,2,2]
JsonArray array = root.getArray("altd");
Assert::IsTrue(array.success());
Assert::AreEqual(4, array.getLength());
for (int i = 0; i < 4; i++)
{
Assert::AreEqual(2L, array.getLong(i));
}
}
};
}

View File

@ -1,67 +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 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

@ -1,189 +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(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

@ -1,71 +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 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

@ -1,165 +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(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

@ -1,103 +0,0 @@
<?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>{4DD596EF-0185-4AB4-A3C2-F20C496F7806}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ArduinoJsonParserTests</RootNamespace>
<ProjectName>JsonParserTests</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</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 Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);..</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ARDUINO_JSON_NO_DEPRECATION_WARNING;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<UseFullPaths>true</UseFullPaths>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<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>
<ProjectReference Include="..\JsonParser\JsonParser.vcxproj">
<Project>{c15274de-2695-4dfe-8520-4424223fe6da}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,37 +0,0 @@
<?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>
<ClCompile Include="GbathreeBug.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObjectTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonArrayIteratorTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonObjectIteratorTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonArrayTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="JsonStringTests.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -1,107 +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(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,25 +0,0 @@
#include "stdafx.h"
#include "CppUnitTest.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace ArduinoJsonParserTests
{
TEST_CLASS(TestHashGenerator)
{
public:
TEST_METHOD(TestMethod1)
{
JsonArray<5> arr;
arr.Add(1);
arr.Add("Hi!");
JsonHashTable<4> hash;
hash.Add("key1", 1);
hash.Add("key2", "Hello!");
hash.Add("key3", arr);
}
};
}

View File

@ -1,6 +1,8 @@
Arduino JSON library
====================
[![Build Status](https://travis-ci.org/bblanchon/ArduinoJson.svg?branch=master)](https://travis-ci.org/bblanchon/ArduinoJson)
*An elegant and efficient JSON library for embedded systems.*
It's design to have the most intuitive API, the smallest footprint and works without any allocation on the heap (no malloc).
@ -10,31 +12,48 @@ It has been written with Arduino in mind, but it isn't linked to Arduino librari
Features
--------
* JSON decoding: [see documentation here](/JsonParser/)
* JSON encoding: [see documentation here](/JsonGenerator/)
* JSON decoding
* JSON encoding (with optional indentation)
* Elegant API, very easy to use
* Fixed memory allocation (no malloc)
* Small footprint
* MIT License
Feature comparison
------------------
Quick start
-----------
| Library | Memory allocation | Nested objects | Parser size | Encoder size |
| ------------ | ----------------- | -------------- | ----------- | ------------- |
| Arduino JSON | static | yes | 2760 Bytes | 862 bytes |
| json-arduino | dynamic | no | 3348 (+21%) | not supported |
| aJson | dynamic | yes | 5088 (+84%) | 4678 (+540%) |
#### Decoding / Parsing
"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).
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
"Encoder size" was measured with a program generating `{"sensor":"outdoor","value":25.6}`.
[Source files are here](https://gist.github.com/bblanchon/60224e9dcfeab4ddc7e9).
StaticJsonBuffer<200> jsonBuffer;
In each case the target platform was an Arduino Duemilanove and Arduino IDE 1.0.5 was used.
JsonObject& root = jsonBuffer.parseObject(json);
Links: [json-arduino](https://github.com/not404/json-arduino), [aJson](https://github.com/interactive-matter/aJson)
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
[See complete guide](/doc/Decoding JSON.md)
#### Encoding / Generating
StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 1351824120;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080, 6); // 6 is the number of decimals to print
data.add(2.302038, 6); // if not specified, 2 digits are printed
root.printTo(Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
[See complete guide](/doc/Encoding JSON.md)
Testimonials
------------
@ -55,10 +74,6 @@ From GitHub user `zacsketches`:
> I've been watching you consistently develop this library over the past six months, and I used it today for a publish and subscribe architecture designed to help hobbyists move into more advanced robotics. Your library allowed me to implement remote subscription in order to facilitate multi-processor robots.
> ArduinoJson saved me a week's worth of time!!
Related blog posts
-----
---
* [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/)
Found this library useful? [Help me back with a donation!](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=donate%40benoitblanchon%2efr&lc=GB&item_name=Benoit%20Blanchon&item_number=Arduino%20JSON&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted) :smile:

102
doc/Avoiding pitfalls.md Normal file
View File

@ -0,0 +1,102 @@
Avoiding common pitfalls in Arduino JSON
========================================
As `StaticJsonBuffer` is the corner stone of this library, you'll see that every pitfall listed here are related to a wrong understanding of the memory model.
Make sure you read [Arduino JSON memory model](Memory model.md) before going further.
## 1. Make `StaticJsonBuffer` big enough
By design, the library has no way to tell you why `parseArray()` or `parseObject()` failed.
There are basically two reasons why they may fail:
1. the JSON string is invalid,
2. the JSON string contains more values that the buffer can store.
So, if you are sure the JSON string is correct and you still can't parse it, you should try to increase the size of the `StaticJsonBuffer`.
## 2. Make sure everything fits in memory
You may go into unpredictable trouble if you allocate more memory than your processor really has.
It's a very common issue in embedded development.
To diagnose this, look at every big objects in you code and sum their size to check that they fit in RAM.
For example, don't do this:
char json[1024]; // 1 KB
StaticJsonBuffer<512> buffer; // 514 B
because it may be too big for a processor with only 2 KB: you need free memory to store other variables and the call stack.
That is why an 8-bit processor is not able to parse long and complex JSON strings.
## 3. Keep the `StaticJsonBuffer` in memory long enough
Remember that `StaticJsonBuffer`'s function return references.
References don't contain data, they are just pointer to the actual.
So they can only work if the actual data is in memory.
For example, don't do this:
JsonArray& getArray(char* json)
{
StaticJsonBuffer<200> buffer;
return buffer.parseArray(json);
}
because the local variable `buffer` will be *removed* from memory when the function `parseArray()` returns, and the `JsonArray&` will point to an invalid location.
## 4. Don't reuse the same `StaticJsonBuffer`
During is lifetime a `StaticJsonBuffer` growth until it's discarded. If you try to reuse the same instance several time, it will rapidly get full.
For this reason, you should not use a global variable for your `StaticJsonBuffer`. I don't think there is any scenario in which a global `StaticJsonBuffer` would be a valid option.
The best practice is to declare it in a local scope, so that it's discarded as soon as possible. My advice it to declare it in a function which unique role is to handle the JSON serialization.
## 5. Keep the JSON string in memory long enough
The library never make memory duplication.
This has an important implication on string values, it means that the library will return pointer to chunks of the string.
For instance, let's imagine that you parse `["hello","world"]`, like this:
char[] json = "[\"hello\",\"world\"]";
StaticJsonBuffer<32> buffer;
JsonArray& array = buffer.parseArray(json);
const char* first = array[0];
const char* second = array[1];
In that case, both `first` and `second` are pointers to the content of the original string `json`.
So this will only work if `json` is still in memory.
## 6. JSON string is altered
If you read carefully the previous section, you may have come to the conclusion that the JSON parser modifies the JSON string.
Indeed, the parser modifies the string for two reasons:
1. it inserts `\0` to terminate substrings,
2. it translate escaped characters like `\n` or `\t`.
Most of the time this wont be an issue, but there are some corner cases that can be problematic.
Let take the example bellow:
char[] json = "[\"hello\",\"world\"]";
StaticJsonBuffer<32> buffer;
JsonArray& array = buffer.parseArray(json);
If you replace it by:
char* json = "[\"hello\",\"world\"]";
StaticJsonBuffer<32> buffer;
JsonArray& array = buffer.parseArray(json);
Depending on your platform, you may have an exception because the parser tries to write at a location that is read-only.
In the first case `char json[]` declares an array of `char` initialized to the specified string.
In the second case `char* json` declares a pointer to a read-only string, in fact it should be a `const char*` instead of a `char*`.

15
doc/Contributing.md Normal file
View File

@ -0,0 +1,15 @@
Contributing to Arduino JSON
============================
If you want to contribute to the project, please:
1. Use GitHub pull request feature
2. Follow the coding conventions
3. Write tests
About the coding conventions: I try to follow the [Google C++ Style Guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html) with few variations to match the Arduino conventions.
I use [ClangFormat](http://clang.llvm.org/docs/ClangFormat.html) to format the code for me.
I use [CppLint](http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py) to detect non-compliant stuff.
You should have a look at the `scripts/` folder as it contains a few helpers scripts.

148
doc/Decoding JSON.md Normal file
View File

@ -0,0 +1,148 @@
Decoding JSON with Arduino JSON
===============================
Before writing any code, don't forget to include the header:
#include <ArduinoJson.h>
For instructions on how to install the library, please read [Using the library with Arduino](Using the library with Arduino.md) or [Using the library without Arduino](Using the library without Arduino.md).
## Example
Here an example that parse the string `{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}`:
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
//
// Step 1: Reserve memory space
//
StaticJsonBuffer<200> jsonBuffer;
//
// Step 2: Deserialize the JSON string
//
JsonObject& root = jsonBuffer.parseObject(json);
if (!root.success())
{
Serial.println("parseObject() failed");
return;
}
//
// Step 3: Retrieve the values
//
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
## Step 1: Reserve memory space
Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer`.
Before continuing please read the page [Arduino JSON memory model](Memory model.md) that explains everything you need to know about `StaticJsonBuffer`.
## Step 2: Parse the JSON string
You invoke the JSON parser through the instance of `StaticJsonBuffer`.
It exposes two functions for parsing JSON:
1. `parseArray()` that returns a reference to a `JsonArray`
2. `parseObject()` that returns a reference to a `JsonObject`
Let's see an example.
Say we want to parse `{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}`, it's an object so we call `parseObject()` as follows:
char json[] = "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
JsonObject& root = jsonBuffer.parseObject(json);
As you can see `parseObject()` takes a `char*` as a parameter.
Be careful, it's not a `const char*`, the memory must be writable.
Indeed, the parser will modify the string in two cases:
1. to insert string endings (character `\0`),
2. to translate escaped characters (like `\n` or `\t`).
Another thing that you must keep in mind is that the string (`char json[]` in the example above) must stay in memory during the whole parsing process.
That is because the in memory object tree will store pointer to chunks of the string, so as to avoid any memory duplication.
Now, to check if the parsing was successful, you can call `JsonObject::success()`:
if (!root.success())
{
// Parsing fail
}
The result can be `false` for tree reasons:
1. the JSON string is invalid,
2. the JSON string doesn't represent an object,
3. the `StaticJsonBuffer` is too small.
We just saw how to parse an object, there is nothing more to say for arrays, the procedure is exactly the same.
## Step 3: Retrieve the values
Now that the object or array is in memory, you can extract the data very easily.
In this section, we'll see how to do it with a `JsonObject`.
Once again, there is nothing more to say about arrays, `JsonArray` works exactly the same as `JsonObject`.
#### Subscript operator
The simplest way is to use the subscript operator of `JsonObject`:
const char* sensor = root["sensor"];
long time = root["time"];
You can chain the subscript operator if you have nested arrays or objects:
double latitude = root["data"][0];
double longitude = root["data"][1];
But alternatively, you can get a reference to the nested array:
JsonArray& nestedArray = root["data"];
#### Casting values
In the previous examples, the values were implicitly casted to the target type.
You can also do this explicitly
const char* sensor = root["sensor"].asString();
long time = root["time"].as<long>();
JsonArray& nestedArray = root["data"].asArray();
If the actual value doesn't match the target type, a default value will be return:
1. `false` for boolean values
2. `0` for integer values
3. `NULL` for string values
4. `JsonArray::invalid()` for nested arrays
5. `JsonObject::invalid()` for nested object
#### Check values
If you want to know if some value is present, call `containsKey()`:
if (root.contains("extra"))
{
// root["extra"] is valid
}
If you want to check the type value has a certain type, call `is<T>()`:
if (root["extra"].is<JsonArray&>())
{
// root["extra"] is an array
}
You can also iterate through the key-value pairs of the object:
for (JsonObject::itertor it=root.begin(); it!=root.end(); ++it)
{
Serial.println(it->key);
Serial.println(i->value.asString());
}

140
doc/Encoding JSON.md Normal file
View File

@ -0,0 +1,140 @@
Encoding JSON with Arduino JSON
===============================
Before writing any code, don't forget to include the header:
#include <ArduinoJson.h>
For instructions on how to install the library, please read [Using the library with Arduino](Using the library with Arduino.md) or [Using the library without Arduino](Using the library without Arduino.md).
## Example
Here is an example to generate `{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}`
//
// Step 1: Reserve memory space
//
StaticJsonBuffer<200> jsonBuffer;
//
// Step 2: Build object tree in memory
//
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 1351824120;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080, 6); // 6 is the number of decimals to print
data.add(2.302038, 6); // if not specified, 2 digits are printed
//
// Step 3: Generate the JSON string
//
root.printTo(Serial);
## Step 1: Reserve memory space
Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer`.
Before continuing please read the page [Arduino JSON memory model](Memory model.md) that explains everything you need to know about `StaticJsonBuffer`.
## Step 2: Build object tree in memory
Now that you have enough memory hold by the `StaticJsonBuffer`, you can use it to build your in-memory representation of the JSON string.
#### Arrays
You create an array like this:
JsonArray& array = jsonBuffer.createArray();
Don't forget the `&` after `JsonArray`, it needs to be a reference to the array.
Then you can add strings, integer, booleans, etc:
array.add("bazinga!");
array.add(42);
array.add(true);
There are two syntaxes for floating point values:
array.add(3.1415, 4); // 4 digits: "3.1415"
array.add(3.1415); // 2 digits: "3.14"
> ##### About floating point precision
> The overload of `add()` with 2 parameters allows you to specify the number of decimals to save in the JSON string.
> When you use the overload with one parameter, you use the default number of decimals which is 2.
> Note that this behavior is the exact same as Arduino's `Print::print(double,int);` which is implemented by `Serial`, so you may already be familiar with this behavior.
You can add a nested array or object if you have a reference to it.
Or simpler, you can create nested array or nested objects from the array:
JsonArray& nestedArray = array.createNestedArray();
JsonObject& nestedObject = array.createNestedObject();
#### Objects
You create an object like this:
JsonObject& object = jsonBuffer.createObject();
Again, don't forget the `&` after `JsonObject`, it needs to be a reference to the object.
Then you can add strings, integer, booleans, etc:
object["key1"] = "bazinga!";
object["key2"] = 42;
object["key3"] = true;
As for the arrays, there are two syntaxes for the floating point values:
object["key4"].set(3.1415, 4); // 4 digits "3.1415"
object["key5"] = 3.1415; // default: 2 digits "3.14"
You can add a nested array or object if you have a reference to it.
Or simpler, you can create nested array or nested objects from the object:
JsonArray& nestedArray = object.createNestedArray("key6");
JsonObject& nestedObject = object.createNestedObject("key7");
> ##### 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`
## Step 3: Generate the JSON string
There are two ways tho get the resulting JSON string.
Depending on your project, you may need to dump the string in a classic `char[]` or send it to a `Print` implementation like `Serial` or `EthernetClient `.
Both ways are the easy way :-)
#### Use a classic `char[]`
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 `Print` implementation
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:
array.printTo(Serial);
And, of course if you need an indented JSON string:
array.prettyPrintTo(Serial);
> ##### About the Print interface
> The library is designed to send the JSON string to an implementation of the `Print` interface that is part of Arduino.
> In the example above we used `Serial`, but they are many other implementations that would work as well, including: `HardwareSerial`, `SoftwareSerial`, `LiquidCrystal`, `EthernetClient`, `WiFiClient`, `Wire`...
> When you use this library out of the Arduino environment, it will use it's own implementation of `Print` and everything will be the same.

58
doc/Memory model.md Normal file
View File

@ -0,0 +1,58 @@
Arduino JSON memory model
=========================
## Fixed memory allocation
### Introducing `StaticJsonBuffer`
Arduino JSON uses a preallocated memory pool to store the object tree, this is done by the `StaticJsonBuffer` class.
Before using any function of the library you need to create a `StaticJsonBuffer`. Then you can use this instance to create arrays and objects, or parse a JSON string.
`StaticJsonBuffer` has a template parameter that determines its capacity. For example, the following line create a `StaticJsonBuffer` with a capacity of 200 bytes:
StaticJsonBuffer<200> jsonBuffer;
The bigger the buffer is, the more complex the object tree can be, but also the more memory you need.
### How to determine the buffer size?
So the big question you should have in mind right now is *How can I determine the size?*.
There are basically two approaches here:
1. either you can predict the content of the object tree,
2. or, you know how much memory is available.
In the first case, you know some constraints on the object tree. For instance, let's say that your know in advance (and by that I mean "at compilation time") that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
To determine the memory usage of this object tree, you use the two macros `JSON_ARRAY_SIZE(n)` and `JSON_OBJECT_SIZE(n)`, both take the number of elements as an argument.
For the example above, it would be:
const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
In the second case, let's say you dynamically generate a JSON object tree of a random complexity so you can't put a limit based on that. But on the other hand, you don't want your program to crash because the object tree doesn't fit in memory.
The solution here is to determine how much memory is available, or in other words how much memory you can afford for the JSON object tree.
### Why choosing fixed allocation?
This fixed allocation approach may seem a bit strange, especially if your a desktop application developer used to dynamic allocation, but it make a lot of sense in an embedded context:
1. the code is smaller
2. it uses less memory
3. it doesn't create memory fragmentation
4. it predictable
Don't forget that the memory is "freed" as soon as the `StaticJsonBuffer` is out of scope, like any other variable. It only hold the memory for a short amount of time.
## Memory usage
#### Object size for 8-bit AVR
| Type | Size |
|-------------------------|------------|
| JsonArray of N element | 4 + 8 * N |
| JsonObject of N element | 4 + 10 * N |

View File

@ -0,0 +1,80 @@
Migrating code written for Arduino JSON v3 to v4
================================================
Arduino JSON v4 was a major rewrite of the library, and the API changed significantly.
## Includes
Arduino JSON v3 had two include files:
#include <JsonParser.h>
#include <JsonGenerator.h>
Arduino JSON v4 only has one:
#include <ArduinoJson.h>
## Namespaces
Arduino JSON v3 had two namespaces:
using namespace ArduinoJson::Parser;
using namespace ArduinoJson::Generator;
Arduino JSON v4 doesn't require the `using namespace` statement.
It has a namespace but the `using namespace` is done in the header file.
## StaticJsonBuffer
Arduino JSON v3 had different memory allocation models for the parser:
JsonParser<16> parser; // 16 being the capacity in "tokens"
and for the generator:
JsonArray<4> array; // 4 being the number of element
JsonObject<4> object;
Arduino JSON v4 only has one memory allocation model:
StaticJsonBuffer<128> buffer; // 128 being the capacity in bytes
## Return values for the parser
Arduino JSON v3 returned value types:
JsonArray array = parser.parseArray(json);
JsonObject object = parser.parseObject(json);
Arduino JSON v4 returns references types:
JsonArray& array = buffer.parseArray(json);
JsonObject& object = buffer.parseObject(json);
Everything else is compatible
## Creating arrays and objects
Arduino JSON v3 allowed to create `JsonArray` and `JsonObject` directly:
JsonArray<4> array;
JsonObject<4> object;
Arduino JSON v4 requires that you use a `StaticJsonBuffer` for that:
JsonArray& array = buffer.createArray();
JsonObject& object = buffer.createObject();
Note: you don't have to specify the capacity anymore.
## Printable interface
Arduino JSON v3 used to implement the Printable interface, which allowed statements like:
Serial.print(array);
But Arduino JSON v4 doesn't, instead you need to write this:
array.printTo(Serial);
Note: there was a good reason for removing that feature, and it's reducing the size of `JsonArray` and `JsonObject`.

View File

@ -0,0 +1,30 @@
Using the library with Arduino
==============================
This library is primarily design to be used with the Arduino IDE and therefore has a simplified setup procedure for that environment.
If you don't use the Arduino IDE, please read [Using the library without Arduino](Using the library without Arduino.md).
## Install the library
[Download the zip package](https://github.com/bblanchon/ArduinoJson/releases) and extract it to:
<your Arduino Sketch folder>/libraries/ArduinoJson
Then restart the Arduino IDE.
## Run the examples sketches
Click `File` / `Example` / `ArduinoJson`.
![Screen capture of Arduino IDE](http://i.imgur.com/g5UwkVh.png)
## Use the library in your sketches
Just add the following line at the top of your program:
#include <ArduinoJson.h>
Then follow the instructions:
1. [Parsing JSON](Parsin JSON.md)
2. [Generating JSON](Generating JSON.md)

View File

@ -0,0 +1,37 @@
Using the library without Arduino
=================================
This library is primarily design to be used with the Arduino IDE and therefore has a simplified setup procedure for that environment.
If you use the Arduino IDE, please read [Using the library with Arduino](Using the library with Arduino.md).
However, it can be used without Arduino IDE with very little effort.
## Compiling the library
Step 1: Download source code:
git clone https://github.com/bblanchon/ArduinoJson.git
Step 2: Generate the `Makefile` for your environment
cd ArduinoJson
cmake .
Step 3: Build
make
## File paths
Assuming you installed the library into `<arduino-json>`, you need to add:
1. `<arduino-json>/include` to your include path
2. `<arduino-json>/lib` to your library path
----------
You are now ready to follow the instructions:
1. [Parsing JSON](Parsin JSON.md)
2. [Generating JSON](Generating JSON.md)

View File

@ -3,41 +3,28 @@
* Benoit Blanchon 2014 - MIT License
*/
#include <JsonGenerator.h>
#include <ArduinoJson.h>
using namespace ArduinoJson::Generator;
using namespace ArduinoJson::Internals;
void setup()
{
Serial.begin(9600);
void setup() {
Serial.begin(9600);
JsonObject<1> json;
json["key"] = "value";
IndentedPrint serial(Serial);
serial.setTabSize(4);
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("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");
serial.unindent();
serial.unindent();
serial.println("This is back at indentation 0");
}
void loop()
{
void loop() {
// not used in this example
}

View File

@ -1,32 +1,42 @@
/*
* Arduino JSON library - Generator example
* Benoit Blanchon 2014 - MIT License
*/
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <JsonGenerator.h>
#include <ArduinoJson.h>
using namespace ArduinoJson::Generator;
void setup() {
Serial.begin(9600);
void setup()
{
Serial.begin(9600);
StaticJsonBuffer<200> jsonBuffer;
JsonArray<2> array;
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
JsonObject& root = jsonBuffer.createObject();
root["sensor"] = "gps";
root["time"] = 1351824120;
JsonObject<3> root;
root["sensor"] = "gps";
root["time"] = 1351824120;
root["data"] = array;
JsonArray& data = root.createNestedArray("data");
data.add(48.756080, 6); // 6 is the number of decimals to print
data.add(2.302038, 6); // if not specified, 2 digits are printed
Serial.print(root); // {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
root.printTo(Serial);
// This prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
Serial.println();
root.prettyPrintTo(Serial); // same string indented
Serial.println();
root.prettyPrintTo(Serial);
// This prints:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [
// 48.756080,
// 2.302038
// ]
// }
}
void loop()
{
void loop() {
// not used in this example
}

View File

@ -1,40 +1,37 @@
/*
* Arduino JSON library - Parser Example
* Benoit Blanchon 2014 - MIT License
*/
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include <JsonParser.h>
#include <ArduinoJson.h>
using namespace ArduinoJson::Parser;
void setup() {
Serial.begin(9600);
void setup()
{
Serial.begin(9600);
StaticJsonBuffer<200> jsonBuffer;
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;
JsonObject& root = jsonBuffer.parseObject(json);
JsonObject root = parser.parse(json);
if (!root.success()) {
Serial.println("parseObject() failed");
return;
}
if (!root.success())
{
Serial.println("JsonParser.parse() failed");
return;
}
const char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
char* sensor = root["sensor"];
long time = root["time"];
double latitude = root["data"][0];
double longitude = root["data"][1];
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
Serial.println(sensor);
Serial.println(time);
Serial.println(latitude, 6);
Serial.println(longitude, 6);
}
void loop()
{
void loop() {
// not used in this example
}

11
include/ArduinoJson.h Normal file
View File

@ -0,0 +1,11 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
#include "../include/ArduinoJson/StaticJsonBuffer.hpp"
using namespace ArduinoJson;

View File

@ -0,0 +1,31 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#ifndef ARDUINO
#include <stddef.h>
#include <stdint.h>
// This class reproduces Arduino's Print
class Print {
public:
virtual ~Print() {}
virtual size_t write(uint8_t) = 0;
size_t print(const char[]);
size_t print(double, int = 2);
size_t print(long);
size_t println();
};
#else
#include <Print.h>
#endif

View File

@ -0,0 +1,54 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../Arduino/Print.hpp"
namespace ArduinoJson {
namespace Internals {
// 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:
explicit IndentedPrint(Print &p) : sink(&p) {
level = 0;
tabSize = 2;
isNewLine = true;
}
virtual size_t write(uint8_t);
// Adds one level of indentation
void indent() {
if (level < MAX_LEVEL) level++;
}
// Removes one level of indentation
void unindent() {
if (level > 0) level--;
}
// Set the number of space printed for each level of indentation
void setTabSize(uint8_t n) {
if (n < MAX_TAB_SIZE) tabSize = n & MAX_TAB_SIZE;
}
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

@ -0,0 +1,42 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../JsonBuffer.hpp"
#include "../JsonVariant.hpp"
namespace ArduinoJson {
namespace Internals {
// Parse JSON string to create JsonArrays and JsonObjects
// This internal class is not indended to be used directly.
// Instead, use JsonBuffer.parseArray() or .parseObject()
class JsonParser {
public:
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
: _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {}
JsonArray &parseArray();
JsonObject &parseObject();
private:
bool skip(char charToSkip);
bool skip(const char *wordToSkip);
void skipSpaces();
void parseAnythingTo(JsonVariant &destination);
inline void parseBooleanTo(JsonVariant &destination);
inline void parseNullTo(JsonVariant &destination);
inline void parseNumberTo(JsonVariant &destination);
inline const char *parseString();
JsonBuffer *_buffer;
char *_ptr;
uint8_t _nestingLimit;
};
}
}

View File

@ -0,0 +1,54 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "IndentedPrint.hpp"
#include "JsonWriter.hpp"
#include "Prettyfier.hpp"
#include "StringBuilder.hpp"
namespace ArduinoJson {
namespace Internals {
// Implements all the overloads of printTo() and prettyPrintTo()
// Caution: this class use a template parameter to avoid virtual methods.
// This is a bit curious but allows to reduce the size of JsonVariant, JsonArray
// and JsonObject.
template <typename T>
class JsonPrintable {
public:
size_t printTo(Print &print) const {
JsonWriter writer(print);
downcast().writeTo(writer);
return writer.bytesWritten();
}
size_t printTo(char *buffer, size_t bufferSize) const {
StringBuilder sb(buffer, bufferSize);
return printTo(sb);
}
size_t prettyPrintTo(IndentedPrint &print) const {
Prettyfier p(print);
return printTo(p);
}
size_t prettyPrintTo(char *buffer, size_t bufferSize) const {
StringBuilder sb(buffer, bufferSize);
return prettyPrintTo(sb);
}
size_t prettyPrintTo(Print &print) const {
IndentedPrint indentedPrint = IndentedPrint(print);
return prettyPrintTo(indentedPrint);
}
private:
const T &downcast() const { return *static_cast<const T *>(this); }
};
}
}

View File

@ -0,0 +1,28 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
namespace ArduinoJson {
// Forward declarations
class JsonArray;
class JsonObject;
namespace Internals {
// A union that defines the actual content of a JsonVariant.
// The enum JsonVariantType determines which member is in use.
union JsonVariantContent {
bool asBoolean;
double asDouble; // asDouble is also used for float
long asLong; // asLong is also used for char, short and int
const char* asString; // asString can be null
JsonArray* asArray; // asArray cannot be null
JsonObject* asObject; // asObject cannot be null
};
}
}

View File

@ -0,0 +1,33 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
namespace ArduinoJson {
namespace Internals {
// Enumerated type to know the current type of a JsonVariant.
// The value determines which member of JsonVariantContent is used.
enum JsonVariantType {
JSON_INVALID, // a special state for JsonVariant::invalid()
JSON_UNDEFINED, // the JsonVariant has not been initialized
JSON_ARRAY, // the JsonVariant stores a pointer to a JsonArray
JSON_OBJECT, // the JsonVariant stores a pointer to a JsonObject
JSON_BOOLEAN, // the JsonVariant stores a bool
JSON_STRING, // the JsonVariant stores a const char*
JSON_LONG, // the JsonVariant stores a long
// The following values are reserved for double values
// Multiple values are used for double, depending on the number of decimal
// digits that must be printed in the JSON output.
// This little trick allow to save one extra member in JsonVariant
JSON_DOUBLE_0_DECIMALS
// JSON_DOUBLE_1_DECIMAL
// JSON_DOUBLE_2_DECIMALS
// ...
};
}
}

View File

@ -0,0 +1,64 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../Arduino/Print.hpp"
#include "QuotedString.hpp"
namespace ArduinoJson {
namespace Internals {
// Writes the JSON tokens to a Print implementation
// This class is used by:
// - JsonArray::writeTo()
// - JsonObject::writeTo()
// - JsonVariant::writeTo()
// Its derived by PrettyJsonWriter that overrides some members to add
// indentation.
class JsonWriter {
public:
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
// Returns the number of bytes sent to the Print implementation.
// This is very handy for implementations of printTo() that must return the
// number of bytes written.
size_t bytesWritten() { return _length; }
void beginArray() { write('['); }
void endArray() { write(']'); }
void beginObject() { write('{'); }
void endObject() { write('}'); }
void writeColon() { write(':'); }
void writeComma() { write(','); }
void writeString(const char *value) {
_length += QuotedString::printTo(value, _sink);
}
void writeLong(long value) { _length += _sink.print(value); }
void writeBoolean(bool value) {
_length += _sink.print(value ? "true" : "false");
}
void writeDouble(double value, uint8_t decimals) {
_length += _sink.print(value, decimals);
}
protected:
void write(char c) { _length += _sink.write(c); }
void write(const char *s) { _length += _sink.print(s); }
Print &_sink;
size_t _length;
private:
JsonWriter &operator=(const JsonWriter &); // cannot be assigned
};
}
}

View File

@ -0,0 +1,74 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "../JsonBuffer.hpp"
#include "ListConstIterator.hpp"
#include "ListIterator.hpp"
#include "PlacementNew.hpp"
namespace ArduinoJson {
namespace Internals {
// A singly linked list of T.
// The linked list is composed of ListNode<T>.
// It is derived by JsonArray and JsonObject
template <typename T>
class List {
public:
typedef T value_type;
typedef ListNode<T> node_type;
typedef ListIterator<T> iterator;
typedef ListConstIterator<T> const_iterator;
// Creates an empty List<T> attached to a JsonBuffer.
// The JsonBuffer allows to allocate new nodes.
// When buffer is NULL, the List is not able to grow and success() returns
// false. This is used to identify bad memory allocations and parsing
// failures.
explicit List(JsonBuffer *buffer) : _buffer(buffer), _firstNode(NULL) {}
// Returns true if the object is valid
// Would return false in the following situation:
// - the memory allocation failed (StaticJsonBuffer was too small)
// - the JSON parsing failed
bool success() const { return _buffer != NULL; }
// Returns the numbers of elements in the list.
// For a JsonObject, it would return the number of key-value pairs
int size() const;
iterator begin() { return iterator(_firstNode); }
iterator end() { return iterator(NULL); }
const_iterator begin() const { return const_iterator(_firstNode); }
const_iterator end() const { return const_iterator(NULL); }
protected:
node_type *createNode() {
if (!_buffer) return NULL;
void *ptr = _buffer->alloc(sizeof(node_type));
return ptr ? new (ptr) node_type() : NULL;
}
void addNode(node_type *nodeToAdd) {
if (_firstNode) {
node_type *lastNode = _firstNode;
while (lastNode->next) lastNode = lastNode->next;
lastNode->next = nodeToAdd;
} else {
_firstNode = nodeToAdd;
}
}
void removeNode(node_type *nodeToRemove);
JsonBuffer *_buffer;
node_type *_firstNode;
};
}
}

View File

@ -0,0 +1,40 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "ListNode.hpp"
namespace ArduinoJson {
namespace Internals {
// A read-only forward itertor for List<T>
template <typename T>
class ListConstIterator {
public:
explicit ListConstIterator(const ListNode<T> *node = NULL) : _node(node) {}
const T &operator*() const { return _node->content; }
const T *operator->() { return &_node->content; }
bool operator==(const ListConstIterator<T> &other) const {
return _node == other._node;
}
bool operator!=(const ListConstIterator<T> &other) const {
return _node != other._node;
}
ListConstIterator<T> &operator++() {
if (_node) _node = _node->next;
return *this;
}
private:
const ListNode<T> *_node;
};
}
}

View File

@ -0,0 +1,40 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include "ListNode.hpp"
namespace ArduinoJson {
namespace Internals {
// A read-write forward iterator for List<T>
template <typename T>
class ListIterator {
public:
explicit ListIterator(ListNode<T> *node = NULL) : _node(node) {}
T &operator*() const { return _node->content; }
T *operator->() { return &_node->content; }
bool operator==(const ListIterator<T> &other) const {
return _node == other._node;
}
bool operator!=(const ListIterator<T> &other) const {
return _node != other._node;
}
ListIterator<T> &operator++() {
if (_node) _node = _node->next;
return *this;
}
private:
ListNode<T> *_node;
};
}
}

View File

@ -0,0 +1,24 @@
// Copyright Benoit Blanchon 2014
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#pragma once
#include <stddef.h> // for NULL
namespace ArduinoJson {
namespace Internals {
// A node for a singly-linked list.
// Used by List<T> and its iterators.
template <typename T>
struct ListNode {
ListNode() : next(NULL) {}
ListNode<T>* next;
T content;
};
}
}

Some files were not shown because too many files have changed in this diff Show More