mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-02 21:31:00 +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)
|
||||
* Implicitly call `strdup()` for `String` but not for `char*` (issues #84, #87)
|
||||
* 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)
|
||||
* 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
|
||||
|
||||
ZIP="C:\Program Files\7-Zip\7z.exe"
|
||||
TAG=$(git describe)
|
||||
OUTPUT="ArduinoJson-$TAG.zip"
|
||||
|
||||
cd ../..
|
||||
cd $(dirname $0)/../..
|
||||
|
||||
# remove existing file
|
||||
rm -f $OUTPUT
|
||||
|
||||
# create zip
|
||||
"$ZIP" a $OUTPUT \
|
||||
7z a $OUTPUT \
|
||||
ArduinoJson/CHANGELOG.md \
|
||||
ArduinoJson/examples \
|
||||
ArduinoJson/include \
|
||||
|
@ -11,6 +11,12 @@
|
||||
#include <math.h> // for isnan() and isinf()
|
||||
#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 n = 0;
|
||||
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 <ctype.h>
|
||||
|
||||
#include "../../include/ArduinoJson/Internals/Comments.hpp"
|
||||
#include "../../include/ArduinoJson/Internals/Encoding.hpp"
|
||||
#include "../../include/ArduinoJson/JsonArray.hpp"
|
||||
#include "../../include/ArduinoJson/JsonBuffer.hpp"
|
||||
@ -17,16 +18,11 @@
|
||||
using namespace ArduinoJson;
|
||||
using namespace ArduinoJson::Internals;
|
||||
|
||||
static const char *skipSpaces(const char *ptr) {
|
||||
while (isspace(*ptr)) ptr++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool JsonParser::skip(char charToSkip) {
|
||||
register const char *ptr = skipSpaces(_readPtr);
|
||||
register const char *ptr = skipSpacesAndComments(_readPtr);
|
||||
if (*ptr != charToSkip) return false;
|
||||
ptr++;
|
||||
_readPtr = skipSpaces(ptr);
|
||||
_readPtr = skipSpacesAndComments(ptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -50,7 +46,7 @@ bool JsonParser::parseAnythingTo(JsonVariant *destination) {
|
||||
}
|
||||
|
||||
inline bool JsonParser::parseAnythingToUnsafe(JsonVariant *destination) {
|
||||
_readPtr = skipSpaces(_readPtr);
|
||||
_readPtr = skipSpacesAndComments(_readPtr);
|
||||
|
||||
switch (*_readPtr) {
|
||||
case '[':
|
||||
@ -212,8 +208,13 @@ bool JsonParser::parseNullTo(JsonVariant *destination) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isStopChar(char c) {
|
||||
return c == '\0' || c == ':' || c == '}' || c == ']' || c == ',';
|
||||
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');
|
||||
}
|
||||
|
||||
const char *JsonParser::parseString() {
|
||||
@ -222,7 +223,7 @@ const char *JsonParser::parseString() {
|
||||
|
||||
char c = *readPtr;
|
||||
|
||||
if (c == '\'' || c == '\"') {
|
||||
if (c == '\'' || c == '\"') { // quotes
|
||||
char stopChar = c;
|
||||
for (;;) {
|
||||
c = *++readPtr;
|
||||
@ -241,9 +242,9 @@ const char *JsonParser::parseString() {
|
||||
|
||||
*writePtr++ = c;
|
||||
}
|
||||
} else {
|
||||
} else { // no quotes
|
||||
for (;;) {
|
||||
if (isStopChar(c)) break;
|
||||
if (!isLetterOrNumber(c)) break;
|
||||
*writePtr++ = c;
|
||||
c = *++readPtr;
|
||||
}
|
||||
|
@ -164,8 +164,26 @@ TEST_F(JsonParser_Array_Tests, MixedTrueFalse) {
|
||||
parseMustFail();
|
||||
}
|
||||
|
||||
TEST_F(JsonParser_Array_Tests, TwoStrings) {
|
||||
whenInputIs("[\"hello\",\"world\"]");
|
||||
TEST_F(JsonParser_Array_Tests, TwoStringsDoubleQuotes) {
|
||||
whenInputIs("[ \"hello\" , \"world\" ]");
|
||||
|
||||
parseMustSucceed();
|
||||
sizeMustBe(2);
|
||||
firstElementMustBe("hello");
|
||||
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);
|
||||
@ -224,3 +242,118 @@ TEST_F(JsonParser_Array_Tests, StringWithUnterminatedEscapeSequence) {
|
||||
whenInputIs("\"\\\0\"", 4);
|
||||
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