mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-29 10:17:39 +02:00
Added support of non standard JSON input (issue #44)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
|||||||
/build
|
/build
|
||||||
/bin
|
/bin
|
||||||
/lib
|
/lib
|
||||||
|
/sftp-config.json
|
||||||
|
@ -4,9 +4,7 @@ compiler:
|
|||||||
- clang
|
- clang
|
||||||
before_install:
|
before_install:
|
||||||
- sudo pip install cpp-coveralls
|
- sudo pip install cpp-coveralls
|
||||||
before_script:
|
|
||||||
- cmake -DCOVERAGE=true .
|
|
||||||
script:
|
script:
|
||||||
- make && make test
|
- cmake -DCOVERAGE=true . && make && make test
|
||||||
after_success:
|
after_success:
|
||||||
- coveralls --exclude test --exclude third-party --gcov-options '\-lp'
|
- if [ "$CC" = "gcc" ]; then coveralls --exclude third-party --gcov-options '\-lp'; fi
|
||||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -5,6 +5,7 @@ v5.0 (currently in beta)
|
|||||||
----
|
----
|
||||||
|
|
||||||
* Added support of `String` class (issue #55, #56, #70, #77)
|
* Added support of `String` class (issue #55, #56, #70, #77)
|
||||||
|
* Added support of non standard JSON input (issue #44)
|
||||||
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators
|
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators
|
||||||
* Switched to new the library layout (requires Arduino 1.0.6 or above)
|
* Switched to new the library layout (requires Arduino 1.0.6 or above)
|
||||||
|
|
||||||
@ -20,6 +21,15 @@ The `String` class is **bad** because it uses dynamic memory allocation.
|
|||||||
Compared to static allocation, it compiles to a bigger, slower program, and is less predictable.
|
Compared to static allocation, it compiles to a bigger, slower program, and is less predictable.
|
||||||
You certainly don't want that in an embedded environment!
|
You certainly don't want that in an embedded environment!
|
||||||
|
|
||||||
|
v4.5
|
||||||
|
----
|
||||||
|
|
||||||
|
* Fixed buffer overflow when input contains a backslash followed by a terminator (issue #81)
|
||||||
|
|
||||||
|
**Upgrading is recommended** since previous versions contain a potential security risk.
|
||||||
|
|
||||||
|
Special thanks to [Giancarlo Canales Barreto](https://github.com/gcanalesb) for finding this nasty bug.
|
||||||
|
|
||||||
v4.4
|
v4.4
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -12,9 +12,8 @@ if(MSVC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${COVERAGE})
|
if(${COVERAGE})
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -coverage")
|
set(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
39
include/ArduinoJson/Internals/Encoding.hpp
Normal file
39
include/ArduinoJson/Internals/Encoding.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Arduino/Print.hpp"
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Internals {
|
||||||
|
|
||||||
|
class Encoding {
|
||||||
|
public:
|
||||||
|
// Optimized for code size on a 8-bit AVR
|
||||||
|
static char escapeChar(char c) {
|
||||||
|
const char *p = _escapeTable;
|
||||||
|
while (p[0] && p[1] != c) {
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimized for code size on a 8-bit AVR
|
||||||
|
static char unescapeChar(char c) {
|
||||||
|
const char *p = _escapeTable + 4;
|
||||||
|
for (;;) {
|
||||||
|
if (p[0] == '\0') return c;
|
||||||
|
if (p[0] == c) return p[1];
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char _escapeTable[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,10 @@ namespace Internals {
|
|||||||
class JsonParser {
|
class JsonParser {
|
||||||
public:
|
public:
|
||||||
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
|
||||||
: _buffer(buffer), _ptr(json), _nestingLimit(nestingLimit) {}
|
: _buffer(buffer),
|
||||||
|
_readPtr(json),
|
||||||
|
_writePtr(json),
|
||||||
|
_nestingLimit(nestingLimit) {}
|
||||||
|
|
||||||
JsonArray &parseArray();
|
JsonArray &parseArray();
|
||||||
JsonObject &parseObject();
|
JsonObject &parseObject();
|
||||||
@ -26,12 +29,10 @@ class JsonParser {
|
|||||||
private:
|
private:
|
||||||
bool skip(char charToSkip);
|
bool skip(char charToSkip);
|
||||||
bool skip(const char *wordToSkip);
|
bool skip(const char *wordToSkip);
|
||||||
void skipSpaces();
|
|
||||||
|
|
||||||
bool parseAnythingTo(JsonVariant *destination);
|
|
||||||
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
|
|
||||||
|
|
||||||
const char *parseString();
|
const char *parseString();
|
||||||
|
bool parseAnythingTo(JsonVariant *destination);
|
||||||
|
FORCE_INLINE bool parseAnythingToUnsafe(JsonVariant *destination);
|
||||||
|
|
||||||
inline bool parseArrayTo(JsonVariant *destination);
|
inline bool parseArrayTo(JsonVariant *destination);
|
||||||
inline bool parseBooleanTo(JsonVariant *destination);
|
inline bool parseBooleanTo(JsonVariant *destination);
|
||||||
@ -41,7 +42,8 @@ class JsonParser {
|
|||||||
inline bool parseStringTo(JsonVariant *destination);
|
inline bool parseStringTo(JsonVariant *destination);
|
||||||
|
|
||||||
JsonBuffer *_buffer;
|
JsonBuffer *_buffer;
|
||||||
char *_ptr;
|
const char *_readPtr;
|
||||||
|
char *_writePtr;
|
||||||
uint8_t _nestingLimit;
|
uint8_t _nestingLimit;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include "Prettyfier.hpp"
|
#include "Prettyfier.hpp"
|
||||||
#include "StringBuilder.hpp"
|
#include "StringBuilder.hpp"
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
#include "StreamPrintAdapter.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ArduinoJson {
|
namespace ArduinoJson {
|
||||||
namespace Internals {
|
namespace Internals {
|
||||||
|
|
||||||
@ -28,6 +32,14 @@ class JsonPrintable {
|
|||||||
return writer.bytesWritten();
|
return writer.bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
std::ostream& printTo(std::ostream &os) const {
|
||||||
|
StreamPrintAdapter adapter(os);
|
||||||
|
printTo(adapter);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t printTo(char *buffer, size_t bufferSize) const {
|
size_t printTo(char *buffer, size_t bufferSize) const {
|
||||||
StringBuilder sb(buffer, bufferSize);
|
StringBuilder sb(buffer, bufferSize);
|
||||||
return printTo(sb);
|
return printTo(sb);
|
||||||
@ -61,5 +73,13 @@ class JsonPrintable {
|
|||||||
private:
|
private:
|
||||||
const T &downcast() const { return *static_cast<const T *>(this); }
|
const T &downcast() const { return *static_cast<const T *>(this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
template<typename T>
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const JsonPrintable<T>& v) {
|
||||||
|
return v.printTo(os);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Arduino/Print.hpp"
|
#include "../Arduino/Print.hpp"
|
||||||
#include "QuotedString.hpp"
|
#include "Encoding.hpp"
|
||||||
|
|
||||||
namespace ArduinoJson {
|
namespace ArduinoJson {
|
||||||
namespace Internals {
|
namespace Internals {
|
||||||
@ -26,7 +26,7 @@ class JsonWriter {
|
|||||||
// Returns the number of bytes sent to the Print implementation.
|
// Returns the number of bytes sent to the Print implementation.
|
||||||
// This is very handy for implementations of printTo() that must return the
|
// This is very handy for implementations of printTo() that must return the
|
||||||
// number of bytes written.
|
// number of bytes written.
|
||||||
size_t bytesWritten() { return _length; }
|
size_t bytesWritten() const { return _length; }
|
||||||
|
|
||||||
void beginArray() { write('['); }
|
void beginArray() { write('['); }
|
||||||
void endArray() { write(']'); }
|
void endArray() { write(']'); }
|
||||||
@ -37,15 +37,32 @@ class JsonWriter {
|
|||||||
void writeColon() { write(':'); }
|
void writeColon() { write(':'); }
|
||||||
void writeComma() { write(','); }
|
void writeComma() { write(','); }
|
||||||
|
|
||||||
|
void writeBoolean(bool value) {
|
||||||
|
write(value ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
void writeString(const char *value) {
|
void writeString(const char *value) {
|
||||||
_length += QuotedString::printTo(value, _sink);
|
if (!value) {
|
||||||
|
write("null");
|
||||||
|
} else {
|
||||||
|
write('\"');
|
||||||
|
while (*value) writeChar(*value++);
|
||||||
|
write('\"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeChar(char c) {
|
||||||
|
char specialChar = Encoding::escapeChar(c);
|
||||||
|
if (specialChar) {
|
||||||
|
write('\\');
|
||||||
|
write(specialChar);
|
||||||
|
} else {
|
||||||
|
write(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeLong(long value) { _length += _sink.print(value); }
|
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) {
|
void writeDouble(double value, uint8_t decimals) {
|
||||||
_length += _sink.print(value, decimals);
|
_length += _sink.print(value, decimals);
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2015
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../Arduino/Print.hpp"
|
|
||||||
|
|
||||||
namespace ArduinoJson {
|
|
||||||
namespace Internals {
|
|
||||||
|
|
||||||
// An helper class to print and extract doubly-quoted strings
|
|
||||||
class QuotedString {
|
|
||||||
public:
|
|
||||||
// Writes a doubly-quote string to a Print implementation.
|
|
||||||
// It adds the double quotes (") at the beginning and the end of the string.
|
|
||||||
// It escapes the special characters as required by the JSON specifications.
|
|
||||||
static size_t printTo(const char *, Print &);
|
|
||||||
|
|
||||||
// Reads a doubly-quoted string from a buffer.
|
|
||||||
// It removes the double quotes (").
|
|
||||||
// It unescapes the special character as required by the JSON specification,
|
|
||||||
// with the exception of the Unicode characters (\u0000).
|
|
||||||
static char *extractFrom(char *input, char **end);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
34
include/ArduinoJson/Internals/StreamPrintAdapter.hpp
Normal file
34
include/ArduinoJson/Internals/StreamPrintAdapter.hpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
|
||||||
|
#include "../Arduino/Print.hpp"
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Internals {
|
||||||
|
|
||||||
|
class StreamPrintAdapter : public Print {
|
||||||
|
public:
|
||||||
|
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t c) {
|
||||||
|
_os << static_cast<char>(c);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// cannot be assigned
|
||||||
|
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
|
||||||
|
|
||||||
|
std::ostream& _os;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ARDUINOJSON_ENABLE_STD_STREAM
|
@ -40,8 +40,19 @@ class JsonArraySubscript : public JsonVariantBase<JsonArraySubscript> {
|
|||||||
return _array.is<T>(_index);
|
return _array.is<T>(_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeTo(Internals::JsonWriter &writer) const {
|
||||||
|
_array.get(_index).writeTo(writer);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JsonArray& _array;
|
JsonArray& _array;
|
||||||
const size_t _index;
|
const size_t _index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& source) {
|
||||||
|
return source.printTo(os);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ArduinoJson
|
||||||
|
@ -41,8 +41,18 @@ class JsonObjectSubscript : public JsonVariantBase<JsonObjectSubscript> {
|
|||||||
return _object.is<T>(_key);
|
return _object.is<T>(_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeTo(Internals::JsonWriter &writer) const {
|
||||||
|
_object.get(_key).writeTo(writer);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JsonObject& _object;
|
JsonObject& _object;
|
||||||
JsonObjectKey _key;
|
JsonObjectKey _key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& source) {
|
||||||
|
return source.printTo(os);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,7 @@ class JsonObject;
|
|||||||
// - a char, short, int or a long (signed or unsigned)
|
// - a char, short, int or a long (signed or unsigned)
|
||||||
// - a string (const char*)
|
// - a string (const char*)
|
||||||
// - a reference to a JsonArray or JsonObject
|
// - a reference to a JsonArray or JsonObject
|
||||||
class JsonVariant : public Internals::JsonPrintable<JsonVariant>,
|
class JsonVariant : public JsonVariantBase<JsonVariant> {
|
||||||
public JsonVariantBase<JsonVariant> {
|
|
||||||
public:
|
public:
|
||||||
// Creates an uninitialized JsonVariant
|
// Creates an uninitialized JsonVariant
|
||||||
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
|
FORCE_INLINE JsonVariant() : _type(Internals::JSON_UNDEFINED) {}
|
||||||
|
@ -186,4 +186,11 @@ template <>
|
|||||||
inline bool JsonVariant::is<unsigned short>() const {
|
inline bool JsonVariant::is<unsigned short>() const {
|
||||||
return _type == Internals::JSON_LONG;
|
return _type == Internals::JSON_LONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const JsonVariant& source) {
|
||||||
|
return source.printTo(os);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace ArduinoJson
|
||||||
|
@ -16,7 +16,7 @@ class JsonArraySubscript;
|
|||||||
class JsonObjectSubscript;
|
class JsonObjectSubscript;
|
||||||
|
|
||||||
template <typename TImpl>
|
template <typename TImpl>
|
||||||
class JsonVariantBase {
|
class JsonVariantBase : public Internals::JsonPrintable<TImpl> {
|
||||||
public:
|
public:
|
||||||
// Gets the variant as a boolean value.
|
// Gets the variant as a boolean value.
|
||||||
// Returns false if the variant is not a boolean value.
|
// Returns false if the variant is not a boolean value.
|
||||||
@ -79,6 +79,9 @@ class JsonVariantBase {
|
|||||||
FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const;
|
FORCE_INLINE const JsonObjectSubscript operator[](const char *key) const;
|
||||||
FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const;
|
FORCE_INLINE const JsonObjectSubscript operator[](const String &key) const;
|
||||||
|
|
||||||
|
// Serialize the variant to a JsonWriter
|
||||||
|
void writeTo(Internals::JsonWriter &writer) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TImpl *impl() const { return static_cast<const TImpl *>(this); }
|
const TImpl *impl() const { return static_cast<const TImpl *>(this); }
|
||||||
};
|
};
|
||||||
|
12
src/Internals/Encoding.cpp
Normal file
12
src/Internals/Encoding.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||||
|
|
||||||
|
// How to escape special chars:
|
||||||
|
// _escapeTable[2*i+1] => the special char
|
||||||
|
// _escapeTable[2*i] => the char to use instead
|
||||||
|
const char ArduinoJson::Internals::Encoding::_escapeTable[] = "\"\"\\\\b\bf\fn\nr\rt\t";
|
@ -9,7 +9,7 @@
|
|||||||
#include <stdlib.h> // for strtol, strtod
|
#include <stdlib.h> // for strtol, strtod
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
|
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||||
#include "../../include/ArduinoJson/JsonArray.hpp"
|
#include "../../include/ArduinoJson/JsonArray.hpp"
|
||||||
#include "../../include/ArduinoJson/JsonBuffer.hpp"
|
#include "../../include/ArduinoJson/JsonBuffer.hpp"
|
||||||
#include "../../include/ArduinoJson/JsonObject.hpp"
|
#include "../../include/ArduinoJson/JsonObject.hpp"
|
||||||
@ -17,25 +17,28 @@
|
|||||||
using namespace ArduinoJson;
|
using namespace ArduinoJson;
|
||||||
using namespace ArduinoJson::Internals;
|
using namespace ArduinoJson::Internals;
|
||||||
|
|
||||||
void JsonParser::skipSpaces() {
|
static const char *skipSpaces(const char *ptr) {
|
||||||
while (isspace(*_ptr)) _ptr++;
|
while (isspace(*ptr)) ptr++;
|
||||||
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonParser::skip(char charToSkip) {
|
bool JsonParser::skip(char charToSkip) {
|
||||||
skipSpaces();
|
register const char *ptr = skipSpaces(_readPtr);
|
||||||
if (*_ptr != charToSkip) return false;
|
if (*ptr != charToSkip) return false;
|
||||||
_ptr++;
|
ptr++;
|
||||||
skipSpaces();
|
_readPtr = skipSpaces(ptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonParser::skip(const char *wordToSkip) {
|
bool JsonParser::skip(const char *wordToSkip) {
|
||||||
const char *charToSkip = wordToSkip;
|
register const char *ptr = _readPtr;
|
||||||
while (*charToSkip && *_ptr == *charToSkip) {
|
while (*wordToSkip && *ptr == *wordToSkip) {
|
||||||
charToSkip++;
|
wordToSkip++;
|
||||||
_ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
return *charToSkip == '\0';
|
if (*wordToSkip != '\0') return false;
|
||||||
|
_readPtr = ptr;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
||||||
@ -47,9 +50,9 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||||
skipSpaces();
|
_readPtr = skipSpaces(_readPtr);
|
||||||
|
|
||||||
switch (*_ptr) {
|
switch (*_readPtr) {
|
||||||
case '[':
|
case '[':
|
||||||
return parseArrayTo(destination);
|
return parseArrayTo(destination);
|
||||||
|
|
||||||
@ -181,7 +184,7 @@ bool JsonParser::parseBooleanTo(JsonVariant *destination) {
|
|||||||
|
|
||||||
bool JsonParser::parseNumberTo(JsonVariant *destination) {
|
bool JsonParser::parseNumberTo(JsonVariant *destination) {
|
||||||
char *endOfLong;
|
char *endOfLong;
|
||||||
long longValue = strtol(_ptr, &endOfLong, 10);
|
long longValue = strtol(_readPtr, &endOfLong, 10);
|
||||||
char stopChar = *endOfLong;
|
char stopChar = *endOfLong;
|
||||||
|
|
||||||
// Could it be a floating point value?
|
// Could it be a floating point value?
|
||||||
@ -189,14 +192,14 @@ bool JsonParser::parseNumberTo(JsonVariant *destination) {
|
|||||||
|
|
||||||
if (couldBeFloat) {
|
if (couldBeFloat) {
|
||||||
// Yes => parse it as a double
|
// Yes => parse it as a double
|
||||||
double doubleValue = strtod(_ptr, &_ptr);
|
double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr));
|
||||||
// Count the decimal digits
|
// Count the decimal digits
|
||||||
uint8_t decimals = static_cast<uint8_t>(_ptr - endOfLong - 1);
|
uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1);
|
||||||
// Set the variant as a double
|
// Set the variant as a double
|
||||||
*destination = JsonVariant(doubleValue, decimals);
|
*destination = JsonVariant(doubleValue, decimals);
|
||||||
} else {
|
} else {
|
||||||
// No => set the variant as a long
|
// No => set the variant as a long
|
||||||
_ptr = endOfLong;
|
_readPtr = endOfLong;
|
||||||
*destination = longValue;
|
*destination = longValue;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -209,8 +212,53 @@ bool JsonParser::parseNullTo(JsonVariant *destination) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isStopChar(char c) {
|
||||||
|
return c == '\0' || c == ':' || c == '}' || c == ']' || c == ',';
|
||||||
|
}
|
||||||
|
|
||||||
const char *JsonParser::parseString() {
|
const char *JsonParser::parseString() {
|
||||||
return QuotedString::extractFrom(_ptr, &_ptr);
|
const char *readPtr = _readPtr;
|
||||||
|
char *writePtr = _writePtr;
|
||||||
|
|
||||||
|
char c = *readPtr;
|
||||||
|
|
||||||
|
if (c == '\'' || c == '\"') {
|
||||||
|
char stopChar = c;
|
||||||
|
for (;;) {
|
||||||
|
c = *++readPtr;
|
||||||
|
if (c == '\0') break;
|
||||||
|
|
||||||
|
if (c == stopChar) {
|
||||||
|
readPtr++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\\') {
|
||||||
|
// replace char
|
||||||
|
c = Encoding::unescapeChar(*++readPtr);
|
||||||
|
if (c == '\0') break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*writePtr++ = c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (;;) {
|
||||||
|
if (isStopChar(c)) break;
|
||||||
|
*writePtr++ = c;
|
||||||
|
c = *++readPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end the string here
|
||||||
|
*writePtr++ = '\0';
|
||||||
|
|
||||||
|
const char *startPtr = _writePtr;
|
||||||
|
|
||||||
|
// update end ptr
|
||||||
|
_readPtr = readPtr;
|
||||||
|
_writePtr = writePtr;
|
||||||
|
|
||||||
|
// return pointer to unquoted string
|
||||||
|
return startPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonParser::parseStringTo(JsonVariant *destination) {
|
bool JsonParser::parseStringTo(JsonVariant *destination) {
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2015
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
|
|
||||||
#include "../../include/ArduinoJson/Internals/QuotedString.hpp"
|
|
||||||
|
|
||||||
using namespace ArduinoJson::Internals;
|
|
||||||
|
|
||||||
// How to escape special chars:
|
|
||||||
// specialChars[2*i+1] => the special char
|
|
||||||
// specialChars[2*i] => the char to use instead
|
|
||||||
static const char specialChars[] = "\"\"\\\\b\bf\fn\nr\rt\t";
|
|
||||||
|
|
||||||
static inline char getSpecialChar(char c) {
|
|
||||||
// Optimized for code size on a 8-bit AVR
|
|
||||||
|
|
||||||
const char *p = specialChars;
|
|
||||||
|
|
||||||
while (p[0] && p[1] != c) {
|
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return p[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t printCharTo(char c, Print &p) {
|
|
||||||
char specialChar = getSpecialChar(c);
|
|
||||||
|
|
||||||
return specialChar ? p.write('\\') + p.write(specialChar) : p.write(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t QuotedString::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('\"');
|
|
||||||
}
|
|
||||||
|
|
||||||
static char unescapeChar(char c) {
|
|
||||||
// Optimized for code size on a 8-bit AVR
|
|
||||||
|
|
||||||
const char *p = specialChars + 4;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (p[0] == '\0') return c;
|
|
||||||
if (p[0] == c) return p[1];
|
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isQuote(char c) { return c == '\"' || c == '\''; }
|
|
||||||
|
|
||||||
char *QuotedString::extractFrom(char *input, char **endPtr) {
|
|
||||||
char firstChar = *input;
|
|
||||||
|
|
||||||
if (!isQuote(firstChar)) {
|
|
||||||
// must start with a quote
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char stopChar = firstChar; // closing quote is the same as opening quote
|
|
||||||
|
|
||||||
char *startPtr = input + 1; // skip the quote
|
|
||||||
char *readPtr = startPtr;
|
|
||||||
char *writePtr = startPtr;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
c = *readPtr++;
|
|
||||||
|
|
||||||
if (c == '\0') {
|
|
||||||
// premature ending
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == stopChar) {
|
|
||||||
// closing quote
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c == '\\') {
|
|
||||||
// replace char
|
|
||||||
c = unescapeChar(*readPtr++);
|
|
||||||
}
|
|
||||||
|
|
||||||
*writePtr++ = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end the string here
|
|
||||||
*writePtr = '\0';
|
|
||||||
|
|
||||||
// update end ptr
|
|
||||||
*endPtr = readPtr;
|
|
||||||
|
|
||||||
return startPtr;
|
|
||||||
}
|
|
@ -18,4 +18,4 @@ add_executable(ArduinoJsonTests
|
|||||||
|
|
||||||
target_link_libraries(ArduinoJsonTests ArduinoJson)
|
target_link_libraries(ArduinoJsonTests ArduinoJson)
|
||||||
|
|
||||||
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)
|
add_test(ArduinoJsonTests ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ArduinoJsonTests)
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
// https://github.com/bblanchon/ArduinoJson
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "Printers.hpp"
|
|
||||||
|
|
||||||
class GbathreeBug : public testing::Test {
|
class GbathreeBug : public testing::Test {
|
||||||
public:
|
public:
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
// https://github.com/bblanchon/ArduinoJson
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "Printers.hpp"
|
|
||||||
|
|
||||||
class JsonObject_Iterator_Test : public testing::Test {
|
class JsonObject_Iterator_Test : public testing::Test {
|
||||||
public:
|
public:
|
||||||
|
@ -9,14 +9,19 @@
|
|||||||
|
|
||||||
class JsonParser_Array_Tests : public testing::Test {
|
class JsonParser_Array_Tests : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void whenInputIs(const char *json) {
|
void whenInputIs(const char *json) { strcpy(_jsonString, json); }
|
||||||
strcpy(_jsonString, json);
|
|
||||||
_array = &_jsonBuffer.parseArray(_jsonString);
|
void whenInputIs(const char *json, size_t len) {
|
||||||
|
memcpy(_jsonString, json, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parseMustSucceed() { EXPECT_TRUE(_array->success()); }
|
void parseMustSucceed() {
|
||||||
|
_array = &_jsonBuffer.parseArray(_jsonString);
|
||||||
|
EXPECT_TRUE(_array->success());
|
||||||
|
}
|
||||||
|
|
||||||
void parseMustFail() {
|
void parseMustFail() {
|
||||||
|
_array = &_jsonBuffer.parseArray(_jsonString);
|
||||||
EXPECT_FALSE(_array->success());
|
EXPECT_FALSE(_array->success());
|
||||||
EXPECT_EQ(0, _array->size());
|
EXPECT_EQ(0, _array->size());
|
||||||
}
|
}
|
||||||
@ -154,6 +159,11 @@ TEST_F(JsonParser_Array_Tests, IncompleteFalse) {
|
|||||||
parseMustFail();
|
parseMustFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, MixedTrueFalse) {
|
||||||
|
whenInputIs("[trufalse]");
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
||||||
whenInputIs("[\"hello\",\"world\"]");
|
whenInputIs("[\"hello\",\"world\"]");
|
||||||
|
|
||||||
@ -162,3 +172,55 @@ TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
|||||||
firstElementMustBe("hello");
|
firstElementMustBe("hello");
|
||||||
secondElementMustBe("world");
|
secondElementMustBe("world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) {
|
||||||
|
whenInputIs("[\"\",\"\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("");
|
||||||
|
secondElementMustBe("");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, EmptyStringSingleQuotes) {
|
||||||
|
whenInputIs("[\'\',\'\']");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("");
|
||||||
|
secondElementMustBe("");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, EmptyStringNoQuotes) {
|
||||||
|
whenInputIs("[,]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("");
|
||||||
|
secondElementMustBe("");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, ClosingDoubleQuoteMissing) {
|
||||||
|
whenInputIs("[\"]");
|
||||||
|
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, ClosingSignleQuoteMissing) {
|
||||||
|
whenInputIs("[\']");
|
||||||
|
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, StringWithEscapedChars) {
|
||||||
|
whenInputIs("[\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) {
|
||||||
|
whenInputIs("\"\\\0\"", 4);
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
@ -75,6 +75,13 @@ TEST_F(JsonParser_Object_Test, OneStringSingleQuotes) {
|
|||||||
keyMustHaveValue("key", "value");
|
keyMustHaveValue("key", "value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Object_Test, OneStringNoQuotes) {
|
||||||
|
whenInputIs("{key:value}");
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
keyMustHaveValue("key", "value");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) {
|
TEST_F(JsonParser_Object_Test, OneStringSpaceBeforeKey) {
|
||||||
whenInputIs("{ \"key\":\"value\"}");
|
whenInputIs("{ \"key\":\"value\"}");
|
||||||
parseMustSucceed();
|
parseMustSucceed();
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
// https://github.com/bblanchon/ArduinoJson
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
#include <ArduinoJson/JsonVariant.hpp>
|
#include <ArduinoJson/JsonVariant.hpp>
|
||||||
#include "Printers.hpp"
|
|
||||||
|
|
||||||
using namespace ArduinoJson;
|
using namespace ArduinoJson;
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
// https://github.com/bblanchon/ArduinoJson
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include "Printers.hpp"
|
|
||||||
|
|
||||||
class JsonVariant_Undefined_Tests : public ::testing::Test {
|
class JsonVariant_Undefined_Tests : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
|
@ -6,16 +6,18 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <ArduinoJson/Internals/QuotedString.hpp>
|
#include <ArduinoJson/Internals/JsonWriter.hpp>
|
||||||
#include <ArduinoJson/Internals/StringBuilder.hpp>
|
#include <ArduinoJson/Internals/StringBuilder.hpp>
|
||||||
|
|
||||||
using namespace ArduinoJson::Internals;
|
using namespace ArduinoJson::Internals;
|
||||||
|
|
||||||
class QuotedString_PrintTo_Tests : public testing::Test {
|
class JsonWriter_WriteString_Tests : public testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void whenInputIs(const char *input) {
|
void whenInputIs(const char *input) {
|
||||||
StringBuilder sb(buffer, sizeof(buffer));
|
StringBuilder sb(buffer, sizeof(buffer));
|
||||||
returnValue = QuotedString::printTo(input, sb);
|
JsonWriter writer(sb);
|
||||||
|
writer.writeString(input);
|
||||||
|
returnValue = writer.bytesWritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
void outputMustBe(const char *expected) {
|
void outputMustBe(const char *expected) {
|
||||||
@ -28,52 +30,52 @@ class QuotedString_PrintTo_Tests : public testing::Test {
|
|||||||
size_t returnValue;
|
size_t returnValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, Null) {
|
TEST_F(JsonWriter_WriteString_Tests, Null) {
|
||||||
whenInputIs(0);
|
whenInputIs(0);
|
||||||
outputMustBe("null");
|
outputMustBe("null");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, EmptyString) {
|
TEST_F(JsonWriter_WriteString_Tests, EmptyString) {
|
||||||
whenInputIs("");
|
whenInputIs("");
|
||||||
outputMustBe("\"\"");
|
outputMustBe("\"\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, QuotationMark) {
|
TEST_F(JsonWriter_WriteString_Tests, QuotationMark) {
|
||||||
whenInputIs("\"");
|
whenInputIs("\"");
|
||||||
outputMustBe("\"\\\"\"");
|
outputMustBe("\"\\\"\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, ReverseSolidus) {
|
TEST_F(JsonWriter_WriteString_Tests, ReverseSolidus) {
|
||||||
whenInputIs("\\");
|
whenInputIs("\\");
|
||||||
outputMustBe("\"\\\\\"");
|
outputMustBe("\"\\\\\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, Solidus) {
|
TEST_F(JsonWriter_WriteString_Tests, Solidus) {
|
||||||
whenInputIs("/");
|
whenInputIs("/");
|
||||||
outputMustBe("\"/\""); // but the JSON format allows \/
|
outputMustBe("\"/\""); // but the JSON format allows \/
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, Backspace) {
|
TEST_F(JsonWriter_WriteString_Tests, Backspace) {
|
||||||
whenInputIs("\b");
|
whenInputIs("\b");
|
||||||
outputMustBe("\"\\b\"");
|
outputMustBe("\"\\b\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, Formfeed) {
|
TEST_F(JsonWriter_WriteString_Tests, Formfeed) {
|
||||||
whenInputIs("\f");
|
whenInputIs("\f");
|
||||||
outputMustBe("\"\\f\"");
|
outputMustBe("\"\\f\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, Newline) {
|
TEST_F(JsonWriter_WriteString_Tests, Newline) {
|
||||||
whenInputIs("\n");
|
whenInputIs("\n");
|
||||||
outputMustBe("\"\\n\"");
|
outputMustBe("\"\\n\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, CarriageReturn) {
|
TEST_F(JsonWriter_WriteString_Tests, CarriageReturn) {
|
||||||
whenInputIs("\r");
|
whenInputIs("\r");
|
||||||
outputMustBe("\"\\r\"");
|
outputMustBe("\"\\r\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(QuotedString_PrintTo_Tests, HorizontalTab) {
|
TEST_F(JsonWriter_WriteString_Tests, HorizontalTab) {
|
||||||
whenInputIs("\t");
|
whenInputIs("\t");
|
||||||
outputMustBe("\"\\t\"");
|
outputMustBe("\"\\t\"");
|
||||||
}
|
}
|
@ -1,50 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2015
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
|
|
||||||
#include "Printers.hpp"
|
|
||||||
#include <ArduinoJson/JsonArray.hpp>
|
|
||||||
|
|
||||||
class StreamPrintAdapter : public Print {
|
|
||||||
public:
|
|
||||||
explicit StreamPrintAdapter(std::ostream& os) : _os(os) {}
|
|
||||||
|
|
||||||
virtual size_t write(uint8_t c) {
|
|
||||||
_os << static_cast<char>(c);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// cannot be assigned
|
|
||||||
StreamPrintAdapter& operator=(const StreamPrintAdapter&);
|
|
||||||
|
|
||||||
std::ostream& _os;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& ArduinoJson::operator<<(std::ostream& os,
|
|
||||||
const ArduinoJson::JsonVariant& v) {
|
|
||||||
StreamPrintAdapter adapter(os);
|
|
||||||
v.printTo(adapter);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& ArduinoJson::operator<<(std::ostream& os,
|
|
||||||
const ArduinoJson::JsonArray& v) {
|
|
||||||
StreamPrintAdapter adapter(os);
|
|
||||||
v.printTo(adapter);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& ArduinoJson::operator<<(
|
|
||||||
std::ostream& os, const ArduinoJson::JsonObjectSubscript& v) {
|
|
||||||
JsonVariant value = v;
|
|
||||||
return os << value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& ArduinoJson::operator<<(
|
|
||||||
std::ostream& os, const ArduinoJson::JsonArraySubscript& v) {
|
|
||||||
JsonVariant value = v;
|
|
||||||
return os << value;
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2015
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
namespace ArduinoJson {
|
|
||||||
std::ostream& operator<<(std::ostream& os, const JsonVariant& v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, const JsonArray& v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, const JsonObjectSubscript& v);
|
|
||||||
std::ostream& operator<<(std::ostream& os, const JsonArraySubscript& v);
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
// Copyright Benoit Blanchon 2014-2015
|
|
||||||
// MIT License
|
|
||||||
//
|
|
||||||
// Arduino JSON library
|
|
||||||
// https://github.com/bblanchon/ArduinoJson
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <ArduinoJson/Internals/QuotedString.hpp>
|
|
||||||
|
|
||||||
using namespace ArduinoJson::Internals;
|
|
||||||
|
|
||||||
class QuotedString_ExtractFrom_Tests : public testing::Test {
|
|
||||||
protected:
|
|
||||||
void whenInputIs(const char *json) {
|
|
||||||
strcpy(_jsonString, json);
|
|
||||||
_result = QuotedString::extractFrom(_jsonString, &_trailing);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resultMustBe(const char *expected) { EXPECT_STREQ(expected, _result); }
|
|
||||||
|
|
||||||
void trailingMustBe(const char *expected) {
|
|
||||||
EXPECT_STREQ(expected, _trailing);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char _jsonString[256];
|
|
||||||
char *_result;
|
|
||||||
char *_trailing;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EmptyDoubleQuotedString) {
|
|
||||||
whenInputIs("\"\"");
|
|
||||||
|
|
||||||
resultMustBe("");
|
|
||||||
trailingMustBe("");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, NoQuotes) {
|
|
||||||
whenInputIs("hello world");
|
|
||||||
|
|
||||||
resultMustBe(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, MissingClosingQuote) {
|
|
||||||
whenInputIs("\"hello world");
|
|
||||||
|
|
||||||
resultMustBe(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EmptySingleQuotedString) {
|
|
||||||
whenInputIs("''");
|
|
||||||
|
|
||||||
resultMustBe("");
|
|
||||||
trailingMustBe("");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, SimpleDoubleQuotedString) {
|
|
||||||
whenInputIs("\"hello world\"");
|
|
||||||
|
|
||||||
resultMustBe("hello world");
|
|
||||||
trailingMustBe("");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, DoubleQuotedStringWithTrailing) {
|
|
||||||
whenInputIs("\"hello\" world");
|
|
||||||
|
|
||||||
resultMustBe("hello");
|
|
||||||
trailingMustBe(" world");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, SingleQuotedStringWithTrailing) {
|
|
||||||
whenInputIs("'hello' world");
|
|
||||||
|
|
||||||
resultMustBe("hello");
|
|
||||||
trailingMustBe(" world");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, CurlyBraces) {
|
|
||||||
whenInputIs("\"{hello:world}\"");
|
|
||||||
resultMustBe("{hello:world}");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, SquareBraquets) {
|
|
||||||
whenInputIs("\"[hello,world]\"");
|
|
||||||
resultMustBe("[hello,world]");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedDoubleQuote) {
|
|
||||||
whenInputIs("\"hello \\\"world\\\"\"");
|
|
||||||
resultMustBe("hello \"world\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedSingleQuote) {
|
|
||||||
whenInputIs("\"hello \\\'world\\\'\"");
|
|
||||||
resultMustBe("hello 'world'");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedSolidus) {
|
|
||||||
whenInputIs("\"hello \\/world\\/\"");
|
|
||||||
resultMustBe("hello /world/");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedReverseSolidus) {
|
|
||||||
whenInputIs("\"hello \\\\world\\\\\"");
|
|
||||||
resultMustBe("hello \\world\\");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedBackspace) {
|
|
||||||
whenInputIs("\"hello \\bworld\\b\"");
|
|
||||||
resultMustBe("hello \bworld\b");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedFormfeed) {
|
|
||||||
whenInputIs("\"hello \\fworld\\f\"");
|
|
||||||
resultMustBe("hello \fworld\f");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedNewline) {
|
|
||||||
whenInputIs("\"hello \\nworld\\n\"");
|
|
||||||
resultMustBe("hello \nworld\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedCarriageReturn) {
|
|
||||||
whenInputIs("\"hello \\rworld\\r\"");
|
|
||||||
resultMustBe("hello \rworld\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, EscapedTab) {
|
|
||||||
whenInputIs("\"hello \\tworld\\t\"");
|
|
||||||
resultMustBe("hello \tworld\t");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(QuotedString_ExtractFrom_Tests, AllEscapedCharsTogether) {
|
|
||||||
whenInputIs("\"1\\\"2\\\\3\\/4\\b5\\f6\\n7\\r8\\t9\"");
|
|
||||||
resultMustBe("1\"2\\3/4\b5\f6\n7\r8\t9");
|
|
||||||
}
|
|
62
test/StdStream.cpp
Normal file
62
test/StdStream.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#define ARDUINOJSON_ENABLE_STD_STREAM
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
TEST(StdStream, JsonVariantFalse) {
|
||||||
|
std::ostringstream os;
|
||||||
|
JsonVariant variant = false;
|
||||||
|
os << variant;
|
||||||
|
ASSERT_EQ("false", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdStream, JsonVariantString) {
|
||||||
|
std::ostringstream os;
|
||||||
|
JsonVariant variant = "coucou";
|
||||||
|
os << variant;
|
||||||
|
ASSERT_EQ("\"coucou\"", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdStream, JsonObject) {
|
||||||
|
std::ostringstream os;
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonObject& object = jsonBuffer.createObject();
|
||||||
|
object["key"] = "value";
|
||||||
|
os << object;
|
||||||
|
ASSERT_EQ("{\"key\":\"value\"}", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdStream, JsonObjectSubscript) {
|
||||||
|
std::ostringstream os;
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonObject& object = jsonBuffer.createObject();
|
||||||
|
object["key"] = "value";
|
||||||
|
os << object["key"];
|
||||||
|
ASSERT_EQ("\"value\"", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdStream, JsonArray) {
|
||||||
|
std::ostringstream os;
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonArray& array = jsonBuffer.createArray();
|
||||||
|
array.add("value");
|
||||||
|
os << array;
|
||||||
|
ASSERT_EQ("[\"value\"]", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StdStream, JsonArraySubscript) {
|
||||||
|
std::ostringstream os;
|
||||||
|
DynamicJsonBuffer jsonBuffer;
|
||||||
|
JsonArray& array = jsonBuffer.createArray();
|
||||||
|
array.add("value");
|
||||||
|
os << array[0];
|
||||||
|
ASSERT_EQ("\"value\"", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user