Store parsed token as string and allow conversion between various types (issues #64, #69, #90, #93)

This commit is contained in:
Benoit Blanchon
2015-08-10 17:22:22 +02:00
parent bce101578d
commit ef2641b49b
29 changed files with 686 additions and 274 deletions

31
src/Arduino/String.cpp Normal file
View File

@ -0,0 +1,31 @@
// Copyright Benoit Blanchon 2014-2015
// MIT License
//
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#ifndef ARDUINO
#include "../../include/ArduinoJson/Arduino/String.hpp"
#include <stdio.h> // for sprintf()
String::String(double value, unsigned char digits) {
char tmp[32];
sprintf(tmp, "%.*f", digits, value);
*this = tmp;
}
String::String(int value) {
char tmp[32];
sprintf(tmp, "%d", value);
*this = tmp;
}
String::String(long value) {
char tmp[32];
sprintf(tmp, "%ld", value);
*this = tmp;
}
#endif

View File

@ -6,9 +6,6 @@
#include "../../include/ArduinoJson/Internals/JsonParser.hpp"
#include <stdlib.h> // for strtol, strtod
#include <ctype.h>
#include "../../include/ArduinoJson/Internals/Comments.hpp"
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
#include "../../include/ArduinoJson/JsonArray.hpp"
@ -26,17 +23,6 @@ bool JsonParser::skip(char charToSkip) {
return true;
}
bool JsonParser::skip(const char *wordToSkip) {
register const char *ptr = _readPtr;
while (*wordToSkip && *ptr == *wordToSkip) {
wordToSkip++;
ptr++;
}
if (*wordToSkip != '\0') return false;
_readPtr = ptr;
return true;
}
bool JsonParser::parseAnythingTo(JsonVariant *destination) {
if (_nestingLimit == 0) return false;
_nestingLimit--;
@ -55,27 +41,6 @@ inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
case '{':
return parseObjectTo(destination);
case 't':
case 'f':
return parseBooleanTo(destination);
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return parseNumberTo(destination);
case 'n':
return parseNullTo(destination);
default:
return parseStringTo(destination);
}
@ -166,64 +131,24 @@ bool JsonParser::parseObjectTo(JsonVariant *destination) {
return true;
}
bool JsonParser::parseBooleanTo(JsonVariant *destination) {
if (skip("true")) {
*destination = true;
return true;
} else if (skip("false")) {
*destination = false;
return true;
} else {
return false;
}
}
bool JsonParser::parseNumberTo(JsonVariant *destination) {
char *endOfLong;
long longValue = strtol(_readPtr, &endOfLong, 10);
char stopChar = *endOfLong;
// Could it be a floating point value?
bool couldBeFloat = stopChar == '.' || stopChar == 'e' || stopChar == 'E';
if (couldBeFloat) {
// Yes => parse it as a double
double doubleValue = strtod(_readPtr, const_cast<char **>(&_readPtr));
// Count the decimal digits
uint8_t decimals = static_cast<uint8_t>(_readPtr - endOfLong - 1);
// Set the variant as a double
*destination = JsonVariant(doubleValue, decimals);
} else {
// No => set the variant as a long
_readPtr = endOfLong;
*destination = longValue;
}
return true;
}
bool JsonParser::parseNullTo(JsonVariant *destination) {
const char *NULL_STRING = NULL;
if (!skip("null")) return false;
*destination = NULL_STRING;
return true;
}
static inline bool isInRange(char c, char min, char max) {
return min <= c && c <= max;
}
static inline bool isLetterOrNumber(char c) {
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
isInRange(c, 'A', 'Z');
isInRange(c, 'A', 'Z') || c == '-' || c == '.';
}
static inline bool isQuote(char c) { return c == '\'' || c == '\"'; }
const char *JsonParser::parseString() {
const char *readPtr = _readPtr;
char *writePtr = _writePtr;
char c = *readPtr;
if (c == '\'' || c == '\"') { // quotes
if (isQuote(c)) { // quotes
char stopChar = c;
for (;;) {
c = *++readPtr;
@ -263,7 +188,13 @@ const char *JsonParser::parseString() {
}
bool JsonParser::parseStringTo(JsonVariant *destination) {
bool hasQuotes = isQuote(_readPtr[0]);
const char *value = parseString();
*destination = value;
return value != NULL;
if (value == NULL) return false;
if (hasQuotes) {
*destination = value;
} else {
*destination = Unparsed(value);
}
return true;
}

View File

@ -4,11 +4,11 @@
// Arduino JSON library
// https://github.com/bblanchon/ArduinoJson
#include "../../include/ArduinoJson/Internals/StringBuilder.hpp"
#include "../../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
using namespace ArduinoJson::Internals;
size_t StringBuilder::write(uint8_t c) {
size_t StaticStringBuilder::write(uint8_t c) {
if (length >= capacity) return 0;
buffer[length++] = c;

View File

@ -8,7 +8,7 @@
#include <string.h> // for strcmp
#include "../include/ArduinoJson/Internals/StringBuilder.hpp"
#include "../include/ArduinoJson/Internals/StaticStringBuilder.hpp"
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonBuffer.hpp"

View File

@ -9,22 +9,111 @@
#include "../include/ArduinoJson/JsonArray.hpp"
#include "../include/ArduinoJson/JsonObject.hpp"
using namespace ArduinoJson;
#include <errno.h> // for errno
#include <stdlib.h> // for strtol, strtod
using namespace ArduinoJson::Internals;
void JsonVariant::writeTo(JsonWriter &writer) const {
if (is<const JsonArray &>())
as<const JsonArray &>().writeTo(writer);
else if (is<const JsonObject &>())
as<const JsonObject &>().writeTo(writer);
else if (is<const char *>())
writer.writeString(as<const char *>());
else if (is<long>())
writer.writeLong(as<long>());
else if (is<bool>())
writer.writeBoolean(as<bool>());
else if (is<double>()) {
namespace ArduinoJson {
template <>
const char *JsonVariant::as<const char *>() const {
if (_type == JSON_UNPARSED && _content.asString &&
!strcmp("null", _content.asString))
return NULL;
if (_type == JSON_STRING || _type == JSON_UNPARSED) return _content.asString;
return NULL;
}
template <>
double JsonVariant::as<double>() const {
if (_type >= JSON_DOUBLE_0_DECIMALS) return _content.asDouble;
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
return static_cast<double>(_content.asLong);
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString)
return strtod(_content.asString, NULL);
return 0.0;
}
template <>
long JsonVariant::as<long>() const {
if (_type == JSON_LONG || _type == JSON_BOOLEAN) return _content.asLong;
if (_type >= JSON_DOUBLE_0_DECIMALS)
return static_cast<long>(_content.asDouble);
if ((_type == JSON_STRING || _type == JSON_UNPARSED) && _content.asString) {
if (!strcmp("true", _content.asString)) return 1;
return strtol(_content.asString, NULL, 10);
}
return 0L;
}
template <>
String JsonVariant::as<String>() const {
if ((_type == JSON_STRING || _type == JSON_UNPARSED) &&
_content.asString != NULL)
return String(_content.asString);
if (_type == JSON_LONG || _type == JSON_BOOLEAN)
return String(_content.asLong);
if (_type >= JSON_DOUBLE_0_DECIMALS) {
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
writer.writeDouble(as<double>(), decimals);
return String(_content.asDouble, decimals);
}
String s;
printTo(s);
return s;
}
template <>
bool JsonVariant::is<signed long>() const {
if (_type == JSON_LONG) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtol(_content.asString, &end, 10);
return *end == '\0' && errno == 0;
}
template <>
bool JsonVariant::is<double>() const {
if (_type >= JSON_DOUBLE_0_DECIMALS) return true;
if (_type != JSON_UNPARSED || _content.asString == NULL) return false;
char *end;
errno = 0;
strtod(_content.asString, &end);
return *end == '\0' && errno == 0 && !is<long>();
}
void JsonVariant::writeTo(JsonWriter &writer) const {
if (_type == JSON_ARRAY) _content.asArray->writeTo(writer);
if (_type == JSON_OBJECT) _content.asObject->writeTo(writer);
if (_type == JSON_STRING) writer.writeString(_content.asString);
if (_type == JSON_UNPARSED) writer.writeRaw(_content.asString);
if (_type == JSON_LONG) writer.writeLong(_content.asLong);
if (_type == JSON_BOOLEAN) writer.writeBoolean(_content.asLong);
if (_type >= JSON_DOUBLE_0_DECIMALS) {
uint8_t decimals = static_cast<uint8_t>(_type - JSON_DOUBLE_0_DECIMALS);
writer.writeDouble(_content.asDouble, decimals);
}
}
}