Skip to content

Commit 01db7b7

Browse files
kimsey0cdunn2001
authored andcommitted
Allow trailing comma in objects
1 parent d2e6a97 commit 01db7b7

File tree

7 files changed

+20
-2
lines changed

7 files changed

+20
-2
lines changed

include/json/json_features.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class JSON_API Features {
2323
/** \brief A configuration that allows all features and assumes all strings
2424
* are UTF-8.
2525
* - C & C++ comments are allowed
26+
* - Trailing commas in objects and arrays are allowed.
2627
* - Root object can be any JSON value
2728
* - Assumes Value strings are encoded in UTF-8
2829
*/
@@ -31,6 +32,7 @@ class JSON_API Features {
3132
/** \brief A configuration that is strictly compatible with the JSON
3233
* specification.
3334
* - Comments are forbidden.
35+
* - Trailing commas in objects and arrays are forbidden.
3436
* - Root object must be either an array or an object value.
3537
* - Assumes Value strings are encoded in UTF-8
3638
*/
@@ -43,6 +45,9 @@ class JSON_API Features {
4345
/// \c true if comments are allowed. Default: \c true.
4446
bool allowComments_{true};
4547

48+
/// \c true if trailing commas in objects and arrays are allowed. Default \c true.
49+
bool allowTrailingCommas_{true};
50+
4651
/// \c true if root must be either an array or an object value. Default: \c
4752
/// false.
4853
bool strictRoot_{false};

include/json/reader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ class JSON_API CharReaderBuilder : public CharReader::Factory {
299299
* if allowComments is false.
300300
* - `"allowComments": false or true`
301301
* - true if comments are allowed.
302+
* - `"allowTrailingCommas": false or true`
303+
* - true if trailing commas in objects and arrays are allowed.
302304
* - `"strictRoot": false or true`
303305
* - true if root must be either an array or an object value
304306
* - `"allowDroppedNullPlaceholders": false or true`

src/lib_json/json_reader.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Features Features::all() { return {}; }
6767
Features Features::strictMode() {
6868
Features features;
6969
features.allowComments_ = false;
70+
features.allowTrailingCommas_ = false;
7071
features.strictRoot_ = true;
7172
features.allowDroppedNullPlaceholders_ = false;
7273
features.allowNumericKeys_ = false;
@@ -454,7 +455,7 @@ bool Reader::readObject(Token& token) {
454455
initialTokenOk = readToken(tokenName);
455456
if (!initialTokenOk)
456457
break;
457-
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
458+
if (tokenName.type_ == tokenObjectEnd && (name.empty() || features_.allowTrailingCommas_)) // empty object or trailing comma
458459
return true;
459460
name.clear();
460461
if (tokenName.type_ == tokenString) {
@@ -863,6 +864,7 @@ class OurFeatures {
863864
public:
864865
static OurFeatures all();
865866
bool allowComments_;
867+
bool allowTrailingCommas_;
866868
bool strictRoot_;
867869
bool allowDroppedNullPlaceholders_;
868870
bool allowNumericKeys_;
@@ -1437,7 +1439,7 @@ bool OurReader::readObject(Token& token) {
14371439
initialTokenOk = readToken(tokenName);
14381440
if (!initialTokenOk)
14391441
break;
1440-
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1442+
if (tokenName.type_ == tokenObjectEnd && (name.empty() || features_.allowTrailingCommas_)) // empty object or trailing comma
14411443
return true;
14421444
name.clear();
14431445
if (tokenName.type_ == tokenString) {
@@ -1866,6 +1868,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
18661868
bool collectComments = settings_["collectComments"].asBool();
18671869
OurFeatures features = OurFeatures::all();
18681870
features.allowComments_ = settings_["allowComments"].asBool();
1871+
features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
18691872
features.strictRoot_ = settings_["strictRoot"].asBool();
18701873
features.allowDroppedNullPlaceholders_ =
18711874
settings_["allowDroppedNullPlaceholders"].asBool();
@@ -1884,6 +1887,7 @@ static void getValidReaderKeys(std::set<String>* valid_keys) {
18841887
valid_keys->clear();
18851888
valid_keys->insert("collectComments");
18861889
valid_keys->insert("allowComments");
1890+
valid_keys->insert("allowTrailingCommas");
18871891
valid_keys->insert("strictRoot");
18881892
valid_keys->insert("allowDroppedNullPlaceholders");
18891893
valid_keys->insert("allowNumericKeys");
@@ -1917,6 +1921,7 @@ Value& CharReaderBuilder::operator[](const String& key) {
19171921
void CharReaderBuilder::strictMode(Json::Value* settings) {
19181922
//! [CharReaderBuilderStrictMode]
19191923
(*settings)["allowComments"] = false;
1924+
(*settings)["allowTrailingCommas"] = false;
19201925
(*settings)["strictRoot"] = true;
19211926
(*settings)["allowDroppedNullPlaceholders"] = false;
19221927
(*settings)["allowNumericKeys"] = false;
@@ -1932,6 +1937,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
19321937
//! [CharReaderBuilderDefaults]
19331938
(*settings)["collectComments"] = true;
19341939
(*settings)["allowComments"] = true;
1940+
(*settings)["allowTrailingCommas"] = true;
19351941
(*settings)["strictRoot"] = false;
19361942
(*settings)["allowDroppedNullPlaceholders"] = false;
19371943
(*settings)["allowNumericKeys"] = false;

src/test_lib_json/fuzz.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
4040
builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7);
4141
builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8);
4242
builder.settings_["collectComments"] = hash_settings & (1 << 9);
43+
builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10);
4344

4445
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
4546

test/data/fail_test_object_01.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "count" : 1234,, }

test/data/test_object_05.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.={}
2+
.count=1234

test/data/test_object_05.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{ "count" : 1234, }

0 commit comments

Comments
 (0)