Skip to content

Commit f0e7848

Browse files
committed
Allow trailing comma in objects
1 parent bdacfd7 commit f0e7848

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
@@ -66,6 +66,7 @@ Features Features::all() { return {}; }
6666
Features Features::strictMode() {
6767
Features features;
6868
features.allowComments_ = false;
69+
features.allowTrailingCommas_ = false;
6970
features.strictRoot_ = true;
7071
features.allowDroppedNullPlaceholders_ = false;
7172
features.allowNumericKeys_ = false;
@@ -453,7 +454,7 @@ bool Reader::readObject(Token& token) {
453454
initialTokenOk = readToken(tokenName);
454455
if (!initialTokenOk)
455456
break;
456-
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
457+
if (tokenName.type_ == tokenObjectEnd && (name.empty() || features_.allowTrailingCommas_)) // empty object or trailing comma
457458
return true;
458459
name.clear();
459460
if (tokenName.type_ == tokenString) {
@@ -862,6 +863,7 @@ class OurFeatures {
862863
public:
863864
static OurFeatures all();
864865
bool allowComments_;
866+
bool allowTrailingCommas_;
865867
bool strictRoot_;
866868
bool allowDroppedNullPlaceholders_;
867869
bool allowNumericKeys_;
@@ -1421,7 +1423,7 @@ bool OurReader::readObject(Token& token) {
14211423
initialTokenOk = readToken(tokenName);
14221424
if (!initialTokenOk)
14231425
break;
1424-
if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
1426+
if (tokenName.type_ == tokenObjectEnd && (name.empty() || features_.allowTrailingCommas_)) // empty object or trailing comma
14251427
return true;
14261428
name.clear();
14271429
if (tokenName.type_ == tokenString) {
@@ -1881,6 +1883,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
18811883
bool collectComments = settings_["collectComments"].asBool();
18821884
OurFeatures features = OurFeatures::all();
18831885
features.allowComments_ = settings_["allowComments"].asBool();
1886+
features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
18841887
features.strictRoot_ = settings_["strictRoot"].asBool();
18851888
features.allowDroppedNullPlaceholders_ =
18861889
settings_["allowDroppedNullPlaceholders"].asBool();
@@ -1899,6 +1902,7 @@ static void getValidReaderKeys(std::set<String>* valid_keys) {
18991902
valid_keys->clear();
19001903
valid_keys->insert("collectComments");
19011904
valid_keys->insert("allowComments");
1905+
valid_keys->insert("allowTrailingCommas");
19021906
valid_keys->insert("strictRoot");
19031907
valid_keys->insert("allowDroppedNullPlaceholders");
19041908
valid_keys->insert("allowNumericKeys");
@@ -1932,6 +1936,7 @@ Value& CharReaderBuilder::operator[](const String& key) {
19321936
void CharReaderBuilder::strictMode(Json::Value* settings) {
19331937
//! [CharReaderBuilderStrictMode]
19341938
(*settings)["allowComments"] = false;
1939+
(*settings)["allowTrailingCommas"] = false;
19351940
(*settings)["strictRoot"] = true;
19361941
(*settings)["allowDroppedNullPlaceholders"] = false;
19371942
(*settings)["allowNumericKeys"] = false;
@@ -1947,6 +1952,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
19471952
//! [CharReaderBuilderDefaults]
19481953
(*settings)["collectComments"] = true;
19491954
(*settings)["allowComments"] = true;
1955+
(*settings)["allowTrailingCommas"] = true;
19501956
(*settings)["strictRoot"] = false;
19511957
(*settings)["allowDroppedNullPlaceholders"] = false;
19521958
(*settings)["allowNumericKeys"] = false;

src/test_lib_json/fuzz.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
3636
builder.settings_["failIfExtra_"] = hash_settings & (1 << 6);
3737
builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7);
3838
builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8);
39+
builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 9);
3940

4041
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
4142

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)