Files
thirdparty-ArduinoJson/include/ArduinoJson/Internals/JsonParser.ipp
2016-06-22 21:41:19 +02:00

190 lines
4.3 KiB
C++

// Copyright Benoit Blanchon 2014-2016
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
// If you like this project, please add a star!
#include "JsonParser.hpp"
#include "Comments.hpp"
inline bool ArduinoJson::Internals::JsonParser::skip(char charToSkip) {
const char *ptr = skipSpacesAndComments(_readPtr);
if (*ptr != charToSkip) return false;
ptr++;
_readPtr = skipSpacesAndComments(ptr);
return true;
}
inline bool ArduinoJson::Internals::JsonParser::parseAnythingTo(
JsonVariant *destination) {
if (_nestingLimit == 0) return false;
_nestingLimit--;
bool success = parseAnythingToUnsafe(destination);
_nestingLimit++;
return success;
}
inline bool ArduinoJson::Internals::JsonParser::parseAnythingToUnsafe(
JsonVariant *destination) {
_readPtr = skipSpacesAndComments(_readPtr);
switch (*_readPtr) {
case '[':
return parseArrayTo(destination);
case '{':
return parseObjectTo(destination);
default:
return parseStringTo(destination);
}
}
inline ArduinoJson::JsonArray &
ArduinoJson::Internals::JsonParser::parseArray() {
// Create an empty array
JsonArray &array = _buffer->createArray();
// Check opening braket
if (!skip('[')) goto ERROR_MISSING_BRACKET;
if (skip(']')) goto SUCCESS_EMPTY_ARRAY;
// Read each value
for (;;) {
// 1 - Parse value
JsonVariant value;
if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
if (!array.add(value)) goto ERROR_NO_MEMORY;
// 2 - More values?
if (skip(']')) goto SUCCES_NON_EMPTY_ARRAY;
if (!skip(',')) goto ERROR_MISSING_COMMA;
}
SUCCESS_EMPTY_ARRAY:
SUCCES_NON_EMPTY_ARRAY:
return array;
ERROR_INVALID_VALUE:
ERROR_MISSING_BRACKET:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
return JsonArray::invalid();
}
inline bool ArduinoJson::Internals::JsonParser::parseArrayTo(
JsonVariant *destination) {
JsonArray &array = parseArray();
if (!array.success()) return false;
*destination = array;
return true;
}
inline ArduinoJson::JsonObject &
ArduinoJson::Internals::JsonParser::parseObject() {
// Create an empty object
JsonObject &object = _buffer->createObject();
// Check opening brace
if (!skip('{')) goto ERROR_MISSING_BRACE;
if (skip('}')) 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;
// 2 - Parse value
JsonVariant value;
if (!parseAnythingTo(&value)) goto ERROR_INVALID_VALUE;
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;
}
SUCCESS_EMPTY_OBJECT:
SUCCESS_NON_EMPTY_OBJECT:
return object;
ERROR_INVALID_KEY:
ERROR_INVALID_VALUE:
ERROR_MISSING_BRACE:
ERROR_MISSING_COLON:
ERROR_MISSING_COMMA:
ERROR_NO_MEMORY:
return JsonObject::invalid();
}
inline bool ArduinoJson::Internals::JsonParser::parseObjectTo(
JsonVariant *destination) {
JsonObject &object = parseObject();
if (!object.success()) return false;
*destination = object;
return true;
}
inline const char *ArduinoJson::Internals::JsonParser::parseString() {
const char *readPtr = _readPtr;
char *writePtr = _writePtr;
char c = *readPtr;
if (isQuote(c)) { // quotes
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 { // no quotes
for (;;) {
if (!isLetterOrNumber(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;
}
inline bool ArduinoJson::Internals::JsonParser::parseStringTo(
JsonVariant *destination) {
bool hasQuotes = isQuote(_readPtr[0]);
const char *value = parseString();
if (value == NULL) return false;
if (hasQuotes) {
*destination = value;
} else {
*destination = RawJson(value);
}
return true;
}