Extracted StringReader and StringWriter from JsonParser

Split `Internals/` folder into `Data/`, `Deserialization/`, `Serialization/`
This commit is contained in:
Benoit Blanchon
2016-12-21 22:09:13 +01:00
parent b923e8f4df
commit 8032a4b564
44 changed files with 230 additions and 132 deletions

View File

@ -13,11 +13,11 @@
#include "ArduinoJson/JsonVariantComparisons.hpp"
#include "ArduinoJson/StaticJsonBuffer.hpp"
#include "ArduinoJson/Internals/JsonParserImpl.hpp"
#include "ArduinoJson/Internals/JsonSerializerImpl.hpp"
#include "ArduinoJson/Deserialization/JsonParserImpl.hpp"
#include "ArduinoJson/JsonArrayImpl.hpp"
#include "ArduinoJson/JsonBufferImpl.hpp"
#include "ArduinoJson/JsonObjectImpl.hpp"
#include "ArduinoJson/JsonVariantImpl.hpp"
#include "ArduinoJson/Serialization/JsonSerializerImpl.hpp"
using namespace ArduinoJson;

View File

@ -0,0 +1,76 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
template <typename TInput>
void skipSpacesAndComments(TInput& input) {
for (;;) {
switch (input.peek()) {
// spaces
case ' ':
case '\t':
case '\r':
case '\n':
input.skip();
continue;
// comments
case '/':
switch (input.peekNext()) {
// C-style block comment
case '*':
input.skip(); // skip '/'
input.skip(); // skip '*'
for (;;) {
switch (input.peek()) {
case '\0':
return;
case '*':
input.skip(); // skip '*'
if (input.peek() == '/') {
input.skip(); // skip '/'
return;
}
break;
default:
input.skip();
}
}
break;
// C++-style line comment
case '/':
input.skip(); // skip '/'
for (;;) {
switch (input.peek()) {
case '\0':
return;
case '\n':
input.skip();
return;
default:
input.skip();
}
}
return;
// not a comment, just a '/'
default:
return;
}
break;
default:
return;
}
}
}
}
}

View File

@ -9,6 +9,8 @@
#include "../JsonBuffer.hpp"
#include "../JsonVariant.hpp"
#include "StringReader.hpp"
#include "StringWriter.hpp"
namespace ArduinoJson {
namespace Internals {
@ -20,8 +22,8 @@ class JsonParser {
public:
JsonParser(JsonBuffer *buffer, char *json, uint8_t nestingLimit)
: _buffer(buffer),
_readPtr(json ? json : ""),
_writePtr(json),
_reader(json),
_writer(json),
_nestingLimit(nestingLimit) {}
JsonArray &parseArray();
@ -34,7 +36,10 @@ class JsonParser {
}
private:
bool skip(char charToSkip);
static bool eat(StringReader &, char charToSkip);
FORCE_INLINE bool eat(char charToSkip) {
return eat(_reader, charToSkip);
}
const char *parseString();
bool parseAnythingTo(JsonVariant *destination);
@ -58,8 +63,8 @@ class JsonParser {
}
JsonBuffer *_buffer;
const char *_readPtr;
char *_writePtr;
StringReader _reader;
StringWriter _writer;
uint8_t _nestingLimit;
};
}

View File

@ -10,11 +10,12 @@
#include "Comments.hpp"
#include "JsonParser.hpp"
inline bool ArduinoJson::Internals::JsonParser::skip(char charToSkip) {
const char *ptr = skipSpacesAndComments(_readPtr);
if (*ptr != charToSkip) return false;
ptr++;
_readPtr = skipSpacesAndComments(ptr);
inline bool ArduinoJson::Internals::JsonParser::eat(StringReader &reader,
char charToSkip) {
skipSpacesAndComments(reader);
if (reader.peek() != charToSkip) return false;
reader.skip();
skipSpacesAndComments(reader);
return true;
}
@ -29,9 +30,9 @@ inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo(
inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe(
JsonVariant *destination) {
_readPtr = skipSpacesAndComments(_readPtr);
skipSpacesAndComments(_reader);
switch (*_readPtr) {
switch (_reader.peek()) {
case '[':
return parseArrayTo(destination);
@ -49,8 +50,8 @@ ArduinoJson::Internals::JsonParser::parseArray() {
JsonArray &array = _buffer->createArray();
// Check opening braket
if (!skip('[')) goto ERROR_MISSING_BRACKET;
if (skip(']')) goto SUCCESS_EMPTY_ARRAY;
if (!eat('[')) goto ERROR_MISSING_BRACKET;
if (eat(']')) goto SUCCESS_EMPTY_ARRAY;
// Read each value
for (;;) {
@ -60,8 +61,8 @@ ArduinoJson::Internals::JsonParser::parseArray() {
if (!array.add(value)) goto ERROR_NO_MEMORY;
// 2 - More values?
if (skip(']')) goto SUCCES_NON_EMPTY_ARRAY;
if (!skip(',')) goto ERROR_MISSING_COMMA;
if (eat(']')) goto SUCCES_NON_EMPTY_ARRAY;
if (!eat(',')) goto ERROR_MISSING_COMMA;
}
SUCCESS_EMPTY_ARRAY:
@ -90,15 +91,15 @@ ArduinoJson::Internals::JsonParser::parseObject() {
JsonObject &object = _buffer->createObject();
// Check opening brace
if (!skip('{')) goto ERROR_MISSING_BRACE;
if (skip('}')) goto SUCCESS_EMPTY_OBJECT;
if (!eat('{')) goto ERROR_MISSING_BRACE;
if (eat('}')) goto SUCCESS_EMPTY_OBJECT;
// Read each key value pair
for (;;) {
// 1 - Parse key
const char *key = parseString();
if (!key) goto ERROR_INVALID_KEY;
if (!skip(':')) goto ERROR_MISSING_COLON;
if (!eat(':')) goto ERROR_MISSING_COLON;
// 2 - Parse value
JsonVariant value;
@ -106,8 +107,8 @@ ArduinoJson::Internals::JsonParser::parseObject() {
if (!object.set(key, value)) goto ERROR_NO_MEMORY;
// 3 - More keys/values?
if (skip('}')) goto SUCCESS_NON_EMPTY_OBJECT;
if (!skip(',')) goto ERROR_MISSING_COMMA;
if (eat('}')) goto SUCCESS_NON_EMPTY_OBJECT;
if (!eat(',')) goto ERROR_MISSING_COMMA;
}
SUCCESS_EMPTY_OBJECT:
@ -133,53 +134,45 @@ inline bool ArduinoJson::Internals::JsonParser::parseObjectTo(
}
inline const char *ArduinoJson::Internals::JsonParser::parseString() {
const char *readPtr = _readPtr;
char *writePtr = _writePtr;
const char *str = _writer.startString();
char c = *readPtr;
char c = _reader.peek();
if (isQuote(c)) { // quotes
_reader.skip();
char stopChar = c;
for (;;) {
c = *++readPtr;
c = _reader.peek();
if (c == '\0') break;
_reader.skip();
if (c == stopChar) {
readPtr++;
break;
}
if (c == stopChar) break;
if (c == '\\') {
// replace char
c = Encoding::unescapeChar(*++readPtr);
c = Encoding::unescapeChar(_reader.peek());
if (c == '\0') break;
_reader.skip();
}
*writePtr++ = c;
_writer.append(c);
}
} else { // no quotes
for (;;) {
if (!isLetterOrNumber(c)) break;
*writePtr++ = c;
c = *++readPtr;
_reader.skip();
_writer.append(c);
c = _reader.peek();
}
}
// end the string here
*writePtr++ = '\0';
const char *startPtr = _writePtr;
// update end ptr
_readPtr = readPtr;
_writePtr = writePtr;
// return pointer to unquoted string
return startPtr;
_writer.stopString();
return str;
}
inline bool ArduinoJson::Internals::JsonParser::parseStringTo(
JsonVariant *destination) {
bool hasQuotes = isQuote(_readPtr[0]);
bool hasQuotes = isQuote(_reader.peek());
const char *value = parseString();
if (value == NULL) return false;
if (hasQuotes) {

View File

@ -0,0 +1,36 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
// 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 StringReader {
public:
StringReader(const char *input) : _ptr(input ? input : "") {}
void skip() {
_ptr++;
}
char peek() const {
return _ptr[0];
}
char peekNext() const {
return _ptr[1];
}
private:
const char *_ptr;
};
}
}

View File

@ -0,0 +1,36 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
// 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 StringWriter {
public:
StringWriter(char *buffer) : _ptr(buffer) {}
const char *startString() {
return _ptr;
}
void stopString() {
*_ptr++ = 0;
}
void append(char c) {
*_ptr++ = c;
}
private:
char *_ptr;
};
}
}

View File

@ -7,7 +7,7 @@
#pragma once
#include "Internals/BlockJsonBuffer.hpp"
#include "Data/BlockJsonBuffer.hpp"
namespace ArduinoJson {
// Implements a JsonBuffer with dynamic memory allocation.

View File

@ -1,56 +0,0 @@
// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#pragma once
namespace ArduinoJson {
namespace Internals {
inline const char *skipCStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0') return ptr;
if (ptr[0] == '*' && ptr[1] == '/') return ptr + 2;
ptr++;
}
}
inline const char *skipCppStyleComment(const char *ptr) {
ptr += 2;
for (;;) {
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
ptr++;
}
}
inline const char *skipSpacesAndComments(const char *ptr) {
for (;;) {
switch (ptr[0]) {
case ' ':
case '\t':
case '\r':
case '\n':
ptr++;
continue;
case '/':
switch (ptr[1]) {
case '*':
ptr = skipCStyleComment(ptr);
break;
case '/':
ptr = skipCppStyleComment(ptr);
break;
default:
return ptr;
}
break;
default:
return ptr;
}
}
}
}
}

View File

@ -7,13 +7,13 @@
#pragma once
#include "Internals/JsonBufferAllocated.hpp"
#include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp"
#include "Internals/StringFuncs.hpp"
#include "Internals/ValueSetter.hpp"
#include "Data/JsonBufferAllocated.hpp"
#include "Data/List.hpp"
#include "Data/ReferenceType.hpp"
#include "Data/StringFuncs.hpp"
#include "Data/ValueSetter.hpp"
#include "JsonVariant.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"

View File

@ -7,7 +7,7 @@
#pragma once
#include "Internals/JsonParser.hpp"
#include "Deserialization/JsonParser.hpp"
inline ArduinoJson::JsonArray &ArduinoJson::JsonBuffer::createArray() {
JsonArray *ptr = new (this) JsonArray(this);

View File

@ -7,13 +7,13 @@
#pragma once
#include "Internals/JsonBufferAllocated.hpp"
#include "Internals/JsonPrintable.hpp"
#include "Internals/List.hpp"
#include "Internals/ReferenceType.hpp"
#include "Internals/StringFuncs.hpp"
#include "Internals/ValueSetter.hpp"
#include "Data/JsonBufferAllocated.hpp"
#include "Data/List.hpp"
#include "Data/ReferenceType.hpp"
#include "Data/StringFuncs.hpp"
#include "Data/ValueSetter.hpp"
#include "JsonPair.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "TypeTraits/ConstRefOrConstPtr.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"

View File

@ -10,12 +10,12 @@
#include <stddef.h>
#include <stdint.h> // for uint8_t
#include "Internals/JsonPrintable.hpp"
#include "Internals/JsonVariantContent.hpp"
#include "Internals/JsonVariantDefault.hpp"
#include "Internals/JsonVariantType.hpp"
#include "Data/JsonVariantContent.hpp"
#include "Data/JsonVariantDefault.hpp"
#include "Data/JsonVariantType.hpp"
#include "JsonVariantBase.hpp"
#include "RawJson.hpp"
#include "Serialization/JsonPrintable.hpp"
#include "TypeTraits/EnableIf.hpp"
#include "TypeTraits/IsFloatingPoint.hpp"
#include "TypeTraits/IsIntegral.hpp"

View File

@ -7,8 +7,9 @@
#pragma once
#include "Internals/JsonVariantAs.hpp"
#include "Data/JsonVariantAs.hpp"
#include "Polyfills/attributes.hpp"
#include "Serialization/JsonPrintable.hpp"
namespace ArduinoJson {

View File

@ -8,7 +8,7 @@
#pragma once
#include "Configuration.hpp"
#include "Internals/Parse.hpp"
#include "Data/Parse.hpp"
#include "JsonArray.hpp"
#include "JsonObject.hpp"
#include "JsonVariant.hpp"

View File

@ -7,8 +7,8 @@
#pragma once
#include "../Data/StringFuncs.hpp"
#include "../Print.hpp"
#include "StringFuncs.hpp"
namespace ArduinoJson {
namespace Internals {

View File

@ -7,13 +7,13 @@
#pragma once
#include "../Data/Encoding.hpp"
#include "../Data/JsonFloat.hpp"
#include "../Data/JsonInteger.hpp"
#include "../Polyfills/attributes.hpp"
#include "../Polyfills/math.hpp"
#include "../Polyfills/normalize.hpp"
#include "../Print.hpp"
#include "Encoding.hpp"
#include "JsonFloat.hpp"
#include "JsonInteger.hpp"
namespace ArduinoJson {
namespace Internals {

View File

@ -5,8 +5,8 @@
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include <gtest/gtest.h>
#include <ArduinoJson.h>
#include <gtest/gtest.h>
class JsonParser_Variant_Test : public testing::Test {
protected:
@ -92,7 +92,14 @@ TEST_F(JsonParser_Variant_Test, True) {
verify("false", false);
}
TEST_F(JsonParser_Variant_Test, Invalid) {
TEST_F(JsonParser_Variant_Test, OpenBrace) {
whenInputIs("{");
resultMustBeInvalid();
}
TEST_F(JsonParser_Variant_Test, IncompleteStrings) {
verify("\"", "");
verify("\"hello", "hello");
verify("\'", "");
verify("\'world", "world");
}

View File

@ -8,8 +8,8 @@
#include <gtest/gtest.h>
#include <limits>
#include <ArduinoJson/Internals/JsonWriter.hpp>
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>
#include <ArduinoJson/Serialization/JsonWriter.hpp>
#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
using namespace ArduinoJson::Internals;

View File

@ -7,8 +7,8 @@
#include <gtest/gtest.h>
#include <ArduinoJson/Internals/JsonWriter.hpp>
#include <ArduinoJson/Internals/StaticStringBuilder.hpp>
#include <ArduinoJson/Serialization/JsonWriter.hpp>
#include <ArduinoJson/Serialization/StaticStringBuilder.hpp>
using namespace ArduinoJson::Internals;