mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-06 07:06:45 +02:00
Added support of comments in JSON input (issue #88)
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.sh text eol=lf
|
@ -8,6 +8,7 @@ v5.0 (currently in beta)
|
|||||||
* Added `JsonBuffer::strdup()` to make a copy of a string (issues #10, #57)
|
* Added `JsonBuffer::strdup()` to make a copy of a string (issues #10, #57)
|
||||||
* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87)
|
* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87)
|
||||||
* Added support of non standard JSON input (issue #44)
|
* Added support of non standard JSON input (issue #44)
|
||||||
|
* Added support of comments in JSON input (issue #88)
|
||||||
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66)
|
* Redesigned `JsonVariant` to leverage converting constructors instead of assignment operators (issue #66)
|
||||||
* 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)
|
||||||
|
|
||||||
|
13
include/ArduinoJson/Internals/Comments.hpp
Normal file
13
include/ArduinoJson/Internals/Comments.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ArduinoJson {
|
||||||
|
namespace Internals {
|
||||||
|
const char *skipSpacesAndComments(const char *ptr);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,15 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
ZIP="C:\Program Files\7-Zip\7z.exe"
|
|
||||||
TAG=$(git describe)
|
TAG=$(git describe)
|
||||||
OUTPUT="ArduinoJson-$TAG.zip"
|
OUTPUT="ArduinoJson-$TAG.zip"
|
||||||
|
|
||||||
cd ../..
|
cd $(dirname $0)/../..
|
||||||
|
|
||||||
# remove existing file
|
# remove existing file
|
||||||
rm -f $OUTPUT
|
rm -f $OUTPUT
|
||||||
|
|
||||||
# create zip
|
# create zip
|
||||||
"$ZIP" a $OUTPUT \
|
7z a $OUTPUT \
|
||||||
ArduinoJson/CHANGELOG.md \
|
ArduinoJson/CHANGELOG.md \
|
||||||
ArduinoJson/examples \
|
ArduinoJson/examples \
|
||||||
ArduinoJson/include \
|
ArduinoJson/include \
|
||||||
|
@ -11,6 +11,12 @@
|
|||||||
#include <math.h> // for isnan() and isinf()
|
#include <math.h> // for isnan() and isinf()
|
||||||
#include <stdio.h> // for sprintf()
|
#include <stdio.h> // for sprintf()
|
||||||
|
|
||||||
|
// only for GCC 4.9+
|
||||||
|
#if defined(__GNUC__) && \
|
||||||
|
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
|
||||||
|
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t Print::print(const char s[]) {
|
size_t Print::print(const char s[]) {
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
|
51
src/Internals/Comments.cpp
Normal file
51
src/Internals/Comments.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright Benoit Blanchon 2014-2015
|
||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Arduino JSON library
|
||||||
|
// https://github.com/bblanchon/ArduinoJson
|
||||||
|
|
||||||
|
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||||
|
|
||||||
|
inline static 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 static const char *skipCppStyleComment(const char *ptr) {
|
||||||
|
ptr += 2;
|
||||||
|
for (;;) {
|
||||||
|
if (ptr[0] == '\0' || ptr[0] == '\n') return ptr;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ArduinoJson::Internals::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@
|
|||||||
#include <stdlib.h> // for strtol, strtod
|
#include <stdlib.h> // for strtol, strtod
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||||
#include "../../include/ArduinoJson/Internals/Encoding.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"
|
||||||
@ -17,16 +18,11 @@
|
|||||||
using namespace ArduinoJson;
|
using namespace ArduinoJson;
|
||||||
using namespace ArduinoJson::Internals;
|
using namespace ArduinoJson::Internals;
|
||||||
|
|
||||||
static const char *skipSpaces(const char *ptr) {
|
|
||||||
while (isspace(*ptr)) ptr++;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JsonParser::skip(char charToSkip) {
|
bool JsonParser::skip(char charToSkip) {
|
||||||
register const char *ptr = skipSpaces(_readPtr);
|
register const char *ptr = skipSpacesAndComments(_readPtr);
|
||||||
if (*ptr != charToSkip) return false;
|
if (*ptr != charToSkip) return false;
|
||||||
ptr++;
|
ptr++;
|
||||||
_readPtr = skipSpaces(ptr);
|
_readPtr = skipSpacesAndComments(ptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +46,7 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||||
_readPtr = skipSpaces(_readPtr);
|
_readPtr = skipSpacesAndComments(_readPtr);
|
||||||
|
|
||||||
switch (*_readPtr) {
|
switch (*_readPtr) {
|
||||||
case '[':
|
case '[':
|
||||||
@ -212,8 +208,13 @@ bool JsonParser::parseNullTo(JsonVariant *destination) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isStopChar(char c) {
|
static inline bool isInRange(char c, char min, char max) {
|
||||||
return c == '\0' || c == ':' || c == '}' || c == ']' || c == ',';
|
return min <= c && c <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isLetterOrNumber(char c) {
|
||||||
|
return isInRange(c, '0', '9') || isInRange(c, 'a', 'z') ||
|
||||||
|
isInRange(c, 'A', 'Z');
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *JsonParser::parseString() {
|
const char *JsonParser::parseString() {
|
||||||
@ -222,7 +223,7 @@ const char *JsonParser::parseString() {
|
|||||||
|
|
||||||
char c = *readPtr;
|
char c = *readPtr;
|
||||||
|
|
||||||
if (c == '\'' || c == '\"') {
|
if (c == '\'' || c == '\"') { // quotes
|
||||||
char stopChar = c;
|
char stopChar = c;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = *++readPtr;
|
c = *++readPtr;
|
||||||
@ -241,9 +242,9 @@ const char *JsonParser::parseString() {
|
|||||||
|
|
||||||
*writePtr++ = c;
|
*writePtr++ = c;
|
||||||
}
|
}
|
||||||
} else {
|
} else { // no quotes
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (isStopChar(c)) break;
|
if (!isLetterOrNumber(c)) break;
|
||||||
*writePtr++ = c;
|
*writePtr++ = c;
|
||||||
c = *++readPtr;
|
c = *++readPtr;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ TEST_F(JsonParser_Array_Tests, MixedTrueFalse) {
|
|||||||
parseMustFail();
|
parseMustFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
TEST_F(JsonParser_Array_Tests, TwoStringsDoubleQuotes) {
|
||||||
whenInputIs("[ \"hello\" , \"world\" ]");
|
whenInputIs("[ \"hello\" , \"world\" ]");
|
||||||
|
|
||||||
parseMustSucceed();
|
parseMustSucceed();
|
||||||
@ -173,6 +173,24 @@ TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
|||||||
secondElementMustBe("world");
|
secondElementMustBe("world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, TwoStringsSingleQuotes) {
|
||||||
|
whenInputIs("[ 'hello' , 'world' ]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, TwoStringsNoQuotes) {
|
||||||
|
whenInputIs("[ hello , world ]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) {
|
TEST_F(JsonParser_Array_Tests, EmptyStringsDoubleQuotes) {
|
||||||
whenInputIs("[\"\",\"\"]");
|
whenInputIs("[\"\",\"\"]");
|
||||||
|
|
||||||
@ -224,3 +242,118 @@ TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) {
|
|||||||
whenInputIs("\"\\\0\"", 4);
|
whenInputIs("\"\\\0\"", 4);
|
||||||
parseMustFail();
|
parseMustFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentBeforeOpeningBracket) {
|
||||||
|
whenInputIs("/*COMMENT*/[\"hello\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentAfterOpeningBracket) {
|
||||||
|
whenInputIs("[/*COMMENT*/\"hello\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentBeforeClosingBracket) {
|
||||||
|
whenInputIs("[\"hello\"/*COMMENT*/]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentAfterClosingBracket) {
|
||||||
|
whenInputIs("[\"hello\"]/*COMMENT*/");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentBeforeComma) {
|
||||||
|
whenInputIs("[\"hello\"/*COMMENT*/,\"world\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CCommentAfterComma) {
|
||||||
|
whenInputIs("[\"hello\",/*COMMENT*/\"world\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentBeforeOpeningBracket) {
|
||||||
|
whenInputIs("//COMMENT\n[\"hello\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentAfterOpeningBracket) {
|
||||||
|
whenInputIs("[//COMMENT\n\"hello\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentBeforeClosingBracket) {
|
||||||
|
whenInputIs("[\"hello\"//COMMENT\n]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentAfterClosingBracket) {
|
||||||
|
whenInputIs("[\"hello\"]//COMMENT\n");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(1);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentBeforeComma) {
|
||||||
|
whenInputIs("[\"hello\"//COMMENT\n,\"world\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, CppCommentAfterComma) {
|
||||||
|
whenInputIs("[\"hello\",//COMMENT\n\"world\"]");
|
||||||
|
|
||||||
|
parseMustSucceed();
|
||||||
|
sizeMustBe(2);
|
||||||
|
firstElementMustBe("hello");
|
||||||
|
secondElementMustBe("world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, InvalidCppComment) {
|
||||||
|
whenInputIs("[/COMMENT\n]");
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, InvalidComment) {
|
||||||
|
whenInputIs("[/*/\n]");
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonParser_Array_Tests, UnfinishedCComment) {
|
||||||
|
whenInputIs("[/*COMMENT]");
|
||||||
|
parseMustFail();
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user