Added support for non zero-terminated strings (fixes #704)

This commit is contained in:
Benoit Blanchon
2018-05-14 17:12:59 +02:00
parent 4c9c047ddf
commit ccb54136a2
54 changed files with 2234 additions and 1401 deletions

View File

@ -5,12 +5,10 @@
#pragma once
#include "ArduinoJson/DynamicJsonDocument.hpp"
#include "ArduinoJson/MsgPack/MsgPackDeserializer.hpp"
#include "ArduinoJson/StaticJsonDocument.hpp"
#include "ArduinoJson/deserializeJson.hpp"
#include "ArduinoJson/deserializeMsgPack.hpp"
#include "ArduinoJson/Json/Deserialization/JsonDeserializer.hpp"
#include "ArduinoJson/Json/Serialization/JsonSerializer.hpp"
#include "ArduinoJson/JsonArrayImpl.hpp"
#include "ArduinoJson/JsonObjectImpl.hpp"

View File

@ -1,61 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TInput>
void skipSpacesAndComments(TInput& input) {
for (;;) {
switch (input.current()) {
// spaces
case ' ':
case '\t':
case '\r':
case '\n':
input.move();
continue;
// comments
case '/':
switch (input.next()) {
// C-style block comment
case '*':
input.move(); // skip '/'
// no need to skip '*'
for (;;) {
input.move();
if (input.current() == '\0') return;
if (input.current() == '*' && input.next() == '/') {
input.move(); // skip '*'
input.move(); // skip '/'
break;
}
}
break;
// C++-style line comment
case '/':
// not need to skip "//"
for (;;) {
input.move();
if (input.current() == '\0') return;
if (input.current() == '\n') break;
}
break;
// not a comment, just a '/'
default:
return;
}
break;
default:
return;
}
}
}
}
}

View File

@ -7,10 +7,9 @@
#include "../../JsonError.hpp"
#include "../../JsonVariant.hpp"
#include "../../Memory/JsonBuffer.hpp"
#include "../../Strings/StringWriter.hpp"
#include "../../Reading/Reader.hpp"
#include "../../TypeTraits/IsConst.hpp"
#include "../Encoding.hpp"
#include "./Comments.hpp"
namespace ArduinoJson {
namespace Internals {
@ -23,11 +22,13 @@ class JsonDeserializer {
: _buffer(buffer),
_reader(reader),
_writer(writer),
_nestingLimit(nestingLimit) {}
_nestingLimit(nestingLimit),
_loaded(false) {}
JsonError parse(JsonVariant &variant) {
skipSpacesAndComments(_reader);
JsonError err = skipSpacesAndComments();
if (err) return err;
switch (_reader.current()) {
switch (current()) {
case '[':
return parseArray(variant);
@ -42,15 +43,25 @@ class JsonDeserializer {
private:
JsonDeserializer &operator=(const JsonDeserializer &); // non-copiable
static bool eat(TReader &reader, char charToSkip) {
skipSpacesAndComments(reader);
if (reader.current() != charToSkip) return false;
reader.move();
return true;
char current() {
if (!_loaded) {
if (_reader.ended())
_current = 0;
else
_current = _reader.read();
_loaded = true;
}
return _current;
}
void move() {
_loaded = false;
}
FORCE_INLINE bool eat(char charToSkip) {
return eat(_reader, charToSkip);
if (current() != charToSkip) return false;
move();
return true;
}
JsonError parseArray(JsonVariant &variant) {
@ -62,6 +73,12 @@ class JsonDeserializer {
// Check opening braket
if (!eat('[')) return JsonError::InvalidInput;
// Skip spaces
JsonError err = skipSpacesAndComments();
if (err) return err;
// Empty array?
if (eat(']')) return JsonError::Ok;
// Read each value
@ -69,12 +86,16 @@ class JsonDeserializer {
// 1 - Parse value
JsonVariant value;
_nestingLimit--;
JsonError error = parse(value);
err = parse(value);
_nestingLimit++;
if (error != JsonError::Ok) return error;
if (err) return err;
if (!array->add(value)) return JsonError::NoMemory;
// 2 - More values?
// 2 - Skip spaces
err = skipSpacesAndComments();
if (err) return err;
// 3 - More values?
if (eat(']')) return JsonError::Ok;
if (!eat(',')) return JsonError::InvalidInput;
}
@ -89,31 +110,52 @@ class JsonDeserializer {
// Check opening brace
if (!eat('{')) return JsonError::InvalidInput;
// Skip spaces
JsonError err = skipSpacesAndComments();
if (err) return err;
// Empty object?
if (eat('}')) return JsonError::Ok;
// Read each key value pair
for (;;) {
// 1 - Parse key
// Parse key
const char *key;
JsonError error = parseString(&key);
if (error) return error;
err = parseString(&key);
if (err) return err;
// Skip spaces
err = skipSpacesAndComments();
if (err) return err;
// Colon
if (!eat(':')) return JsonError::InvalidInput;
// 2 - Parse value
// Parse value
JsonVariant value;
_nestingLimit--;
error = parse(value);
err = parse(value);
_nestingLimit++;
if (error != JsonError::Ok) return error;
if (err) return err;
if (!object->set(key, value)) return JsonError::NoMemory;
// 3 - More keys/values?
// Skip spaces
err = skipSpacesAndComments();
if (err) return err;
// More keys/values?
if (eat('}')) return JsonError::Ok;
if (!eat(',')) return JsonError::InvalidInput;
// Skip spaces
err = skipSpacesAndComments();
if (err) return err;
}
}
JsonError parseValue(JsonVariant &variant) {
bool hasQuotes = isQuote(_reader.current());
bool hasQuotes = isQuote(current());
const char *value;
JsonError error = parseString(&value);
if (error) return error;
@ -128,33 +170,35 @@ class JsonDeserializer {
JsonError parseString(const char **result) {
typename RemoveReference<TWriter>::type::String str = _writer.startString();
skipSpacesAndComments(_reader);
char c = _reader.current();
char c = current();
if (c == '\0') return JsonError::IncompleteInput;
if (isQuote(c)) { // quotes
_reader.move();
move();
char stopChar = c;
for (;;) {
c = _reader.current();
if (c == '\0') break;
_reader.move();
c = current();
move();
if (c == stopChar) break;
if (c == '\0') return JsonError::IncompleteInput;
if (c == '\\') {
c = current();
if (c == 0) return JsonError::IncompleteInput;
// replace char
c = Encoding::unescapeChar(_reader.current());
c = Encoding::unescapeChar(c);
if (c == '\0') return JsonError::InvalidInput;
_reader.move();
move();
}
str.append(c);
}
} else if (canBeInNonQuotedString(c)) { // no quotes
do {
_reader.move();
move();
str.append(c);
c = _reader.current();
c = current();
} while (canBeInNonQuotedString(c));
} else {
return JsonError::InvalidInput;
@ -178,41 +222,80 @@ class JsonDeserializer {
return c == '\'' || c == '\"';
}
JsonError skipSpacesAndComments() {
for (;;) {
switch (current()) {
// end of string
case '\0':
return JsonError::IncompleteInput;
// spaces
case ' ':
case '\t':
case '\r':
case '\n':
move();
continue;
// comments
case '/':
move(); // skip '/'
switch (current()) {
// block comment
case '*': {
move(); // skip '*'
bool wasStar = false;
for (;;) {
char c = current();
if (c == '\0') return JsonError::IncompleteInput;
if (c == '/' && wasStar) {
move();
break;
}
wasStar = c == '*';
move();
}
break;
}
// trailing comment
case '/':
// no need to skip "//"
for (;;) {
move();
char c = current();
if (c == '\0') return JsonError::IncompleteInput;
if (c == '\n') break;
}
break;
// not a comment, just a '/'
default:
return JsonError::InvalidInput;
}
break;
default:
return JsonError::Ok;
}
}
}
JsonBuffer *_buffer;
TReader _reader;
TWriter _writer;
uint8_t _nestingLimit;
char _current;
bool _loaded;
};
template <typename TJsonBuffer, typename TString, typename Enable = void>
struct JsonParserBuilder {
typedef typename StringTraits<TString>::Reader InputReader;
typedef JsonDeserializer<InputReader, TJsonBuffer &> TParser;
static TParser makeParser(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) {
return TParser(buffer, InputReader(json), *buffer, nestingLimit);
}
};
template <typename TJsonBuffer, typename TChar>
struct JsonParserBuilder<TJsonBuffer, TChar *,
typename EnableIf<!IsConst<TChar>::value>::type> {
typedef typename StringTraits<TChar *>::Reader TReader;
typedef StringWriter<TChar> TWriter;
typedef JsonDeserializer<TReader, TWriter> TParser;
static TParser makeParser(TJsonBuffer *buffer, TChar *json,
uint8_t nestingLimit) {
return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
}
};
template <typename TJsonBuffer, typename TString>
inline typename JsonParserBuilder<TJsonBuffer, TString>::TParser makeParser(
TJsonBuffer *buffer, TString &json, uint8_t nestingLimit) {
return JsonParserBuilder<TJsonBuffer, TString>::makeParser(buffer, json,
nestingLimit);
template <typename TJsonBuffer, typename TReader, typename TWriter>
JsonDeserializer<TReader, TWriter> makeJsonDeserializer(TJsonBuffer *buffer,
TReader reader,
TWriter writer,
uint8_t nestingLimit) {
return JsonDeserializer<TReader, TWriter>(buffer, reader, writer,
nestingLimit);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,11 +4,15 @@
#pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream>
#endif
namespace ArduinoJson {
class JsonError {
public:
enum Code { Ok, TooDeep, NoMemory, InvalidInput };
enum Code { Ok, TooDeep, NoMemory, InvalidInput, IncompleteInput };
JsonError(Code code) : _code(code) {}
@ -42,6 +46,8 @@ class JsonError {
return "NoMemory";
case InvalidInput:
return "InvalidInput";
case IncompleteInput:
return "IncompleteInput";
default:
return "???";
}

View File

@ -6,8 +6,9 @@
#include "../JsonVariant.hpp"
#include "../Memory/JsonBuffer.hpp"
#include "../Strings/StringWriter.hpp"
#include "../Reading/Reader.hpp"
#include "../TypeTraits/IsConst.hpp"
#include "../Writing/Writer.hpp"
#include "./MsgPackError.hpp"
#include "./endianess.hpp"
#include "./ieee754.hpp"
@ -29,27 +30,28 @@ class MsgPackDeserializer {
_nestingLimit(nestingLimit) {}
MsgPackError parse(JsonVariant &variant) {
uint8_t c = readOne();
uint8_t code;
if (!readByte(code)) return MsgPackError::IncompleteInput;
if ((c & 0x80) == 0) {
variant = c;
if ((code & 0x80) == 0) {
variant = code;
return MsgPackError::Ok;
}
if ((c & 0xe0) == 0xe0) {
variant = static_cast<int8_t>(c);
if ((code & 0xe0) == 0xe0) {
variant = static_cast<int8_t>(code);
return MsgPackError::Ok;
}
if ((c & 0xe0) == 0xa0) {
return readString(variant, c & 0x1f);
if ((code & 0xe0) == 0xa0) {
return readString(variant, code & 0x1f);
}
if ((c & 0xf0) == 0x90) return readArray(variant, c & 0x0F);
if ((code & 0xf0) == 0x90) return readArray(variant, code & 0x0F);
if ((c & 0xf0) == 0x80) return readObject(variant, c & 0x0F);
if ((code & 0xf0) == 0x80) return readObject(variant, code & 0x0F);
switch (c) {
switch (code) {
case 0xc0:
variant = static_cast<char *>(0);
return MsgPackError::Ok;
@ -63,81 +65,65 @@ class MsgPackDeserializer {
return MsgPackError::Ok;
case 0xcc:
variant = readInteger<uint8_t>();
return MsgPackError::Ok;
return readInteger<uint8_t>(variant);
case 0xcd:
variant = readInteger<uint16_t>();
return MsgPackError::Ok;
return readInteger<uint16_t>(variant);
case 0xce:
variant = readInteger<uint32_t>();
return MsgPackError::Ok;
return readInteger<uint32_t>(variant);
case 0xcf:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<uint64_t>();
return readInteger<uint64_t>(variant);
#else
readInteger<uint32_t>();
variant = readInteger<uint32_t>();
return readInteger<uint32_t>(variant);
#endif
return MsgPackError::Ok;
case 0xd0:
variant = readInteger<int8_t>();
return MsgPackError::Ok;
return readInteger<int8_t>(variant);
case 0xd1:
variant = readInteger<int16_t>();
return MsgPackError::Ok;
return readInteger<int16_t>(variant);
case 0xd2:
variant = readInteger<int32_t>();
return MsgPackError::Ok;
return readInteger<int32_t>(variant);
case 0xd3:
#if ARDUINOJSON_USE_LONG_LONG || ARDUINOJSON_USE_INT64
variant = readInteger<int64_t>();
return readInteger<int64_t>(variant);
#else
readInteger<int32_t>();
variant = readInteger<int32_t>();
if (!skip(4)) return MsgPackError::IncompleteInput;
return readInteger<int32_t>(variant);
#endif
return MsgPackError::Ok;
case 0xca:
variant = readFloat<float>();
return MsgPackError::Ok;
return readFloat<float>(variant);
case 0xcb:
variant = readDouble<double>();
return MsgPackError::Ok;
return readDouble<double>(variant);
case 0xd9: {
uint8_t n = readInteger<uint8_t>();
return readString(variant, n);
}
case 0xd9:
return readString<uint8_t>(variant);
case 0xda: {
uint16_t n = readInteger<uint16_t>();
return readString(variant, n);
}
case 0xda:
return readString<uint16_t>(variant);
case 0xdb: {
uint32_t n = readInteger<uint32_t>();
return readString(variant, n);
}
case 0xdb:
return readString<uint32_t>(variant);
case 0xdc:
return readArray(variant, readInteger<uint16_t>());
return readArray<uint16_t>(variant);
case 0xdd:
return readArray(variant, readInteger<uint32_t>());
return readArray<uint32_t>(variant);
case 0xde:
return readObject(variant, readInteger<uint16_t>());
return readObject<uint16_t>(variant);
case 0xdf:
return readObject(variant, readInteger<uint32_t>());
return readObject<uint32_t>(variant);
default:
return MsgPackError::NotSupported;
@ -148,65 +134,115 @@ class MsgPackDeserializer {
// Prevent VS warning "assignment operator could not be generated"
MsgPackDeserializer &operator=(const MsgPackDeserializer &);
uint8_t readOne() {
char c = _reader.current();
_reader.move();
return static_cast<uint8_t>(c);
bool skip(uint8_t n) {
while (n--) {
if (_reader.ended()) return false;
_reader.read();
}
return true;
}
void read(uint8_t *p, size_t n) {
for (size_t i = 0; i < n; i++) p[i] = readOne();
bool readByte(uint8_t &value) {
if (_reader.ended()) return false;
value = static_cast<uint8_t>(_reader.read());
return true;
}
bool readBytes(uint8_t *p, size_t n) {
for (size_t i = 0; i < n; i++) {
if (!readByte(p[i])) return false;
}
return true;
}
template <typename T>
void read(T &value) {
read(reinterpret_cast<uint8_t *>(&value), sizeof(value));
bool readBytes(T &value) {
return readBytes(reinterpret_cast<uint8_t *>(&value), sizeof(value));
}
template <typename T>
T readInteger() {
T value;
read(value);
readBytes(value);
fixEndianess(value);
return value;
}
template <typename T>
typename EnableIf<sizeof(T) == 4, T>::type readFloat() {
bool readInteger(T &value) {
if (!readBytes(value)) return false;
fixEndianess(value);
return true;
}
template <typename T>
MsgPackError readInteger(JsonVariant &variant) {
T value;
read(value);
fixEndianess(value);
return value;
if (!readInteger(value)) return MsgPackError::IncompleteInput;
variant = value;
return MsgPackError::Ok;
}
template <typename T>
typename EnableIf<sizeof(T) == 8, T>::type readDouble() {
typename EnableIf<sizeof(T) == 4, MsgPackError>::type readFloat(
JsonVariant &variant) {
T value;
read(value);
if (!readBytes(value)) return MsgPackError::IncompleteInput;
fixEndianess(value);
return value;
variant = value;
return MsgPackError::Ok;
}
template <typename T>
typename EnableIf<sizeof(T) == 4, T>::type readDouble() {
typename EnableIf<sizeof(T) == 8, MsgPackError>::type readDouble(
JsonVariant &variant) {
T value;
if (!readBytes(value)) return MsgPackError::IncompleteInput;
fixEndianess(value);
variant = value;
return MsgPackError::Ok;
}
template <typename T>
typename EnableIf<sizeof(T) == 4, MsgPackError>::type readDouble(
JsonVariant &variant) {
uint8_t i[8]; // input is 8 bytes
T value; // output is 4 bytes
uint8_t *o = reinterpret_cast<uint8_t *>(&value);
read(i, 8);
if (!readBytes(i, 8)) return MsgPackError::IncompleteInput;
doubleToFloat(i, o);
fixEndianess(value);
return value;
variant = value;
return MsgPackError::Ok;
}
template <typename T>
MsgPackError readString(JsonVariant &variant) {
T size;
if (!readInteger(size)) return MsgPackError::IncompleteInput;
return readString(variant, size);
}
MsgPackError readString(JsonVariant &variant, size_t n) {
typename RemoveReference<TWriter>::type::String str = _writer.startString();
for (; n; --n) str.append(static_cast<char>(readOne()));
for (; n; --n) {
uint8_t c;
if (!readBytes(c)) return MsgPackError::IncompleteInput;
str.append(static_cast<char>(c));
}
const char *s = str.c_str();
if (s == NULL) return MsgPackError::NoMemory;
variant = s;
return MsgPackError::Ok;
}
template <typename TSize>
MsgPackError readArray(JsonVariant &variant) {
TSize size;
if (!readInteger(size)) return MsgPackError::IncompleteInput;
return readArray(variant, size);
}
MsgPackError readArray(JsonVariant &variant, size_t n) {
JsonArray *array = new (_buffer) JsonArray(_buffer);
if (!array) return MsgPackError::NoMemory;
@ -227,6 +263,13 @@ class MsgPackDeserializer {
return MsgPackError::Ok;
}
template <typename TSize>
MsgPackError readObject(JsonVariant &variant) {
TSize size;
if (!readInteger(size)) return MsgPackError::IncompleteInput;
return readObject(variant, size);
}
MsgPackError readObject(JsonVariant &variant, size_t n) {
JsonObject *object = new (_buffer) JsonObject(_buffer);
if (!object) return MsgPackError::NoMemory;
@ -258,37 +301,11 @@ class MsgPackDeserializer {
uint8_t _nestingLimit;
};
template <typename TJsonBuffer, typename TString, typename Enable = void>
struct MsgPackDeserializerBuilder {
typedef typename StringTraits<TString>::Reader InputReader;
typedef MsgPackDeserializer<InputReader, TJsonBuffer &> TParser;
static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) {
return TParser(buffer, InputReader(json), *buffer, nestingLimit);
}
};
template <typename TJsonBuffer, typename TChar>
struct MsgPackDeserializerBuilder<
TJsonBuffer, TChar *, typename EnableIf<!IsConst<TChar>::value>::type> {
typedef typename StringTraits<TChar *>::Reader TReader;
typedef StringWriter<TChar> TWriter;
typedef MsgPackDeserializer<TReader, TWriter> TParser;
static TParser makeMsgPackDeserializer(TJsonBuffer *buffer, TChar *json,
uint8_t nestingLimit) {
return TParser(buffer, TReader(json), TWriter(json), nestingLimit);
}
};
template <typename TJsonBuffer, typename TString>
inline typename MsgPackDeserializerBuilder<TJsonBuffer, TString>::TParser
makeMsgPackDeserializer(TJsonBuffer *buffer, TString &json,
uint8_t nestingLimit) {
return MsgPackDeserializerBuilder<
TJsonBuffer, TString>::makeMsgPackDeserializer(buffer, json,
nestingLimit);
template <typename TJsonBuffer, typename TReader, typename TWriter>
MsgPackDeserializer<TReader, TWriter> makeMsgPackDeserializer(
TJsonBuffer *buffer, TReader reader, TWriter writer, uint8_t nestingLimit) {
return MsgPackDeserializer<TReader, TWriter>(buffer, reader, writer,
nestingLimit);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -4,11 +4,15 @@
#pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <ostream>
#endif
namespace ArduinoJson {
class MsgPackError {
public:
enum Code { Ok, NotSupported, NoMemory, TooDeep };
enum Code { Ok, NotSupported, NoMemory, TooDeep, IncompleteInput };
MsgPackError() {}
@ -44,6 +48,8 @@ class MsgPackError {
return "NoMemory";
case TooDeep:
return "TooDeep";
case IncompleteInput:
return "IncompleteInput";
default:
return "???";
}

View File

@ -0,0 +1,41 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
#include <Stream.h>
namespace ArduinoJson {
namespace Internals {
struct ArduinoStreamReader {
Stream& _stream;
char _current;
bool _ended;
public:
explicit ArduinoStreamReader(Stream& stream)
: _stream(stream), _current(0), _ended(false) {}
char read() {
// don't use _stream.read() as it ignores the timeout
char c = 0;
_ended = _stream.readBytes(&c, 1) == 0;
return c;
}
bool ended() const {
return _ended;
}
};
inline ArduinoStreamReader makeReader(Stream& input) {
return ArduinoStreamReader(input);
}
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -0,0 +1,64 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TChar>
class UnsafeCharPointerReader {
const TChar* _ptr;
public:
explicit UnsafeCharPointerReader(const TChar* ptr)
: _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
char read() {
return static_cast<char>(*_ptr++);
}
bool ended() const {
// we cannot know
return false;
}
};
template <typename TChar>
class SafeCharPointerReader {
const TChar* _ptr;
const TChar* _end;
public:
explicit SafeCharPointerReader(const TChar* ptr, size_t len)
: _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")),
_end(_ptr + len) {}
char read() {
return static_cast<char>(*_ptr++);
}
bool ended() const {
return _ptr == _end;
}
};
template <typename TChar>
inline UnsafeCharPointerReader<TChar> makeReader(TChar* input) {
return UnsafeCharPointerReader<TChar>(input);
}
template <typename TChar>
inline SafeCharPointerReader<TChar> makeReader(TChar* input, size_t n) {
return SafeCharPointerReader<TChar>(input, n);
}
#if ARDUINOJSON_ENABLE_ARDUINO_STRING
inline SafeCharPointerReader<char> makeReader(const String& input) {
return SafeCharPointerReader<char>(input.c_str(), input.length());
}
#endif
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,56 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_PROGMEM
namespace ArduinoJson {
namespace Internals {
class UnsafeFlashStringReader {
const char* _ptr;
public:
explicit UnsafeFlashStringReader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
char read() {
return pgm_read_byte_near(_ptr++);
}
bool ended() const {
// this reader cannot detect the end
return false;
}
};
class SafeFlashStringReader {
const char* _ptr;
const char* _end;
public:
explicit SafeFlashStringReader(const __FlashStringHelper* ptr, size_t size)
: _ptr(reinterpret_cast<const char*>(ptr)), _end(_ptr + size) {}
char read() {
return pgm_read_byte_near(_ptr++);
}
bool ended() const {
return _ptr == _end;
}
};
inline UnsafeFlashStringReader makeReader(const __FlashStringHelper* input) {
return UnsafeFlashStringReader(input);
}
inline SafeFlashStringReader makeReader(const __FlashStringHelper* input,
size_t size) {
return SafeFlashStringReader(input, size);
}
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -0,0 +1,34 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TIterator>
class IteratorReader {
TIterator _ptr, _end;
public:
explicit IteratorReader(TIterator begin, TIterator end)
: _ptr(begin), _end(end) {}
bool ended() const {
return _ptr == _end;
}
char read() {
return char(*_ptr++);
}
};
template <typename TInput>
inline IteratorReader<typename TInput::const_iterator> makeReader(
const TInput& input) {
return IteratorReader<typename TInput::const_iterator>(input.begin(),
input.end());
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,11 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "./ArduinoStreamReader.hpp"
#include "./CharPointerReader.hpp"
#include "./FlashStringReader.hpp"
#include "./IteratorReader.hpp"
#include "./StdStreamReader.hpp"

View File

@ -0,0 +1,40 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <istream>
namespace ArduinoJson {
namespace Internals {
class StdStreamReader {
std::istream& _stream;
char _current;
public:
explicit StdStreamReader(std::istream& stream)
: _stream(stream), _current(0) {}
bool ended() const {
return _stream.eof();
}
char read() {
return static_cast<char>(_stream.get());
}
private:
StdStreamReader& operator=(const StdStreamReader&); // Visual Studio C4512
};
inline StdStreamReader makeReader(std::istream& input) {
return StdStreamReader(input);
}
} // namespace Internals
} // namespace ArduinoJson
#endif

View File

@ -1,61 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_ARDUINO_STREAM
#include <Stream.h>
namespace ArduinoJson {
namespace Internals {
struct ArduinoStreamTraits {
class Reader {
Stream& _stream;
char _current, _next;
public:
Reader(Stream& stream) : _stream(stream), _current(0), _next(0) {}
void move() {
_current = _next;
_next = 0;
}
char current() {
if (!_current) _current = read();
return _current;
}
char next() {
// assumes that current() has been called
if (!_next) _next = read();
return _next;
}
private:
char read() {
// don't use _stream.read() as it ignores the timeout
char c = 0;
_stream.readBytes(&c, 1);
return c;
}
};
static const bool has_append = false;
static const bool has_equals = false;
};
template <typename TStream>
struct StringTraits<
TStream,
// match any type that is derived from Stream:
typename EnableIf<
IsBaseOf<Stream, typename RemoveReference<TStream>::type>::value>::type>
: ArduinoStreamTraits {};
}
}
#endif

View File

@ -9,26 +9,6 @@ namespace Internals {
template <typename TChar>
struct CharPointerTraits {
class Reader {
const TChar* _ptr;
public:
Reader(const TChar* ptr)
: _ptr(ptr ? ptr : reinterpret_cast<const TChar*>("")) {}
void move() {
++_ptr;
}
char current() const {
return char(_ptr[0]);
}
char next() const {
return char(_ptr[1]);
}
};
static bool equals(const TChar* str, const char* expected) {
return strcmp(reinterpret_cast<const char*>(str), expected) == 0;
}

View File

@ -10,26 +10,6 @@ namespace ArduinoJson {
namespace Internals {
template <>
struct StringTraits<const __FlashStringHelper*, void> {
class Reader {
const char* _ptr;
public:
Reader(const __FlashStringHelper* ptr)
: _ptr(reinterpret_cast<const char*>(ptr)) {}
void move() {
_ptr++;
}
char current() const {
return pgm_read_byte_near(_ptr);
}
char next() const {
return pgm_read_byte_near(_ptr + 1);
}
};
static bool equals(const __FlashStringHelper* str, const char* expected) {
return strcmp_P(expected, (const char*)str) == 0;
}

View File

@ -1,60 +0,0 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#if ARDUINOJSON_ENABLE_STD_STREAM
#include <istream>
namespace ArduinoJson {
namespace Internals {
struct StdStreamTraits {
class Reader {
std::istream& _stream;
char _current, _next;
public:
Reader(std::istream& stream) : _stream(stream), _current(0), _next(0) {}
void move() {
_current = _next;
_next = 0;
}
char current() {
if (!_current) _current = read();
return _current;
}
char next() {
// assumes that current() has been called
if (!_next) _next = read();
return _next;
}
private:
Reader& operator=(const Reader&); // Visual Studio C4512
char read() {
return _stream.eof() ? '\0' : static_cast<char>(_stream.get());
}
};
static const bool has_append = false;
static const bool has_equals = false;
};
template <typename TStream>
struct StringTraits<
TStream,
// match any type that is derived from std::istream:
typename EnableIf<IsBaseOf<
std::istream, typename RemoveReference<TStream>::type>::value>::type>
: StdStreamTraits {};
}
}
#endif

View File

@ -35,10 +35,6 @@ struct StdStringTraits {
return !str.c_str();
}
struct Reader : CharPointerTraits<char>::Reader {
Reader(const TString& str) : CharPointerTraits<char>::Reader(str.c_str()) {}
};
static bool equals(const TString& str, const char* expected) {
return 0 == strcmp(str.c_str(), expected);
}

View File

@ -29,8 +29,6 @@ struct StringTraits<TString&, void> : StringTraits<TString> {};
}
}
#include "ArduinoStream.hpp"
#include "CharPointer.hpp"
#include "FlashString.hpp"
#include "StdStream.hpp"
#include "StdString.hpp"

View File

@ -0,0 +1,27 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "./StringWriter.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TJsonBuffer>
class JsonBufferWriter {
public:
JsonBufferWriter(TJsonBuffer& jb) : _jb(&jb) {}
typedef typename TJsonBuffer::String String;
String startString() {
return _jb->startString();
}
private:
TJsonBuffer* _jb;
};
} // namespace Internals
} // namespace ArduinoJson

View File

@ -0,0 +1,44 @@
// ArduinoJson - arduinojson.org
// Copyright Benoit Blanchon 2014-2018
// MIT License
#pragma once
#include "./JsonBufferWriter.hpp"
#include "./StringWriter.hpp"
namespace ArduinoJson {
namespace Internals {
template <typename TJsonBuffer, typename TInput, typename Enable = void>
struct Writer {
typedef JsonBufferWriter<TJsonBuffer> type;
static type create(TJsonBuffer& jb, TInput&) {
return type(jb);
}
};
template <typename TJsonBuffer, typename TChar>
struct Writer<TJsonBuffer, TChar*,
typename EnableIf<!IsConst<TChar>::value>::type> {
typedef StringWriter<TChar> type;
static type create(TJsonBuffer&, TChar* input) {
return type(input);
}
};
template <typename TJsonBuffer, typename TInput>
typename Writer<TJsonBuffer, TInput>::type makeWriter(TJsonBuffer& jb,
TInput& input) {
return Writer<TJsonBuffer, TInput>::create(jb, input);
}
template <typename TJsonBuffer, typename TChar>
typename Writer<TJsonBuffer, TChar*>::type makeWriter(TJsonBuffer& jb,
TChar* input) {
return Writer<TJsonBuffer, TChar*>::create(jb, input);
}
} // namespace Internals
} // namespace ArduinoJson

View File

@ -5,34 +5,53 @@
#pragma once
#include "Json/Deserialization/JsonDeserializer.hpp"
#include "Reading/Reader.hpp"
#include "Writing/Writer.hpp"
namespace ArduinoJson {
// JsonError deserializeJson(TDocument& doc, TString json);
// JsonError deserializeJson(TDocument& doc, TString input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const std::string&, const String&
template <typename TDocument, typename TString>
typename Internals::EnableIf<!Internals::IsArray<TString>::value,
JsonError>::type
deserializeJson(TDocument &doc, const TString &json) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit)
deserializeJson(TDocument &doc, const TString &input) {
using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// JsonError deserializeJson(TDocument& doc, TString json);
// JsonError deserializeJson(TDocument& doc, TChar* input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const char*, const char[N], const FlashStringHelper*
template <typename TDocument, typename TString>
JsonError deserializeJson(TDocument &doc, TString *json) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit)
// TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TChar>
JsonError deserializeJson(TDocument &doc, TChar *input) {
using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// JsonError deserializeJson(TDocument& doc, TString json);
// JsonError deserializeJson(TDocument& doc, TChar* input, size_t inputSize);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = std::istream&, Stream&
template <typename TDocument, typename TString>
JsonError deserializeJson(TDocument &doc, TString &json) {
return Internals::makeParser(&doc.buffer(), json, doc.nestingLimit)
// TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TChar>
JsonError deserializeJson(TDocument &doc, TChar *input, size_t inputSize) {
using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input, inputSize),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// JsonError deserializeJson(TDocument& doc, TStream input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TStream = std::istream&, Stream&
template <typename TDocument, typename TStream>
JsonError deserializeJson(TDocument &doc, TStream &input) {
using namespace Internals;
return makeJsonDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input), doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
} // namespace ArduinoJson

View File

@ -5,37 +5,59 @@
#pragma once
#include "MsgPack/MsgPackDeserializer.hpp"
#include "Reading/Reader.hpp"
#include "Writing/Writer.hpp"
namespace ArduinoJson {
// MsgPackError deserializeMsgPack(TDocument& doc, TString json);
// TDocument = DynamicJsonArray | StaticJsonArray
// MsgPackError deserializeMsgPack(TDocument& doc, TString input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TString = const std::string&, const String&
template <typename TDocument, typename TString>
typename Internals::EnableIf<!Internals::IsArray<TString>::value,
MsgPackError>::type
deserializeMsgPack(TDocument &doc, const TString &json) {
return Internals::makeMsgPackDeserializer(&doc.buffer(), json,
doc.nestingLimit)
deserializeMsgPack(TDocument &doc, const TString &input) {
using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input),
doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// MsgPackError deserializeMsgPack(TDocument& doc, TString json);
// TDocument = DynamicJsonArray | StaticJsonArray
// TString = const char*, const char[N], const FlashStringHelper*
template <typename TDocument, typename TString>
MsgPackError deserializeMsgPack(TDocument &doc, TString *json) {
return Internals::makeMsgPackDeserializer(&doc.buffer(), json,
doc.nestingLimit)
// MsgPackError deserializeMsgPack(TDocument& doc, TChar* input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TChar>
MsgPackError deserializeMsgPack(TDocument &doc, TChar *input) {
using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input),
doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// MsgPackError deserializeMsgPack(TDocument& doc, TString json);
// TDocument = DynamicJsonArray | StaticJsonArray
// TString = std::istream&, Stream&
template <typename TDocument, typename TString>
MsgPackError deserializeMsgPack(TDocument &doc, TString &json) {
return Internals::makeMsgPackDeserializer(&doc.buffer(), json,
doc.nestingLimit)
// MsgPackError deserializeMsgPack(TDocument& doc, TChar* input, size_t
// inputSize);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TChar* = char*, const char*, const FlashStringHelper*
template <typename TDocument, typename TChar>
MsgPackError deserializeMsgPack(TDocument &doc, TChar *input,
size_t inputSize) {
using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input, inputSize),
makeWriter(doc.buffer(), input),
doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
//
// MsgPackError deserializeMsgPack(TDocument& doc, TStream input);
// TDocument = DynamicJsonDocument, StaticJsonDocument
// TStream = std::istream&, Stream&
template <typename TDocument, typename TStream>
MsgPackError deserializeMsgPack(TDocument &doc, TStream &input) {
using namespace Internals;
return makeMsgPackDeserializer(&doc.buffer(), makeReader(input),
makeWriter(doc.buffer(), input),
doc.nestingLimit)
.parse(doc.template to<JsonVariant>());
}
} // namespace ArduinoJson