@@ -67,6 +67,7 @@ Features Features::all() { return {}; }
6767Features 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,9 @@ 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 &&
459+ (name.empty () ||
460+ features_.allowTrailingCommas_ )) // empty object or trailing comma
458461 return true ;
459462 name.clear ();
460463 if (tokenName.type_ == tokenString) {
@@ -502,15 +505,20 @@ bool Reader::readArray(Token& token) {
502505 Value init (arrayValue);
503506 currentValue ().swapPayload (init);
504507 currentValue ().setOffsetStart (token.start_ - begin_);
505- skipSpaces ();
506- if (current_ != end_ && *current_ == ' ]' ) // empty array
507- {
508- Token endArray;
509- readToken (endArray);
510- return true ;
511- }
512508 int index = 0 ;
513509 for (;;) {
510+ skipSpaces ();
511+ if (current_ != end_ && *current_ == ' ]' &&
512+ (index == 0 ||
513+ (features_.allowTrailingCommas_ &&
514+ !features_.allowDroppedNullPlaceholders_ ))) // empty array or trailing
515+ // comma
516+ {
517+ Token endArray;
518+ readToken (endArray);
519+ return true ;
520+ }
521+
514522 Value& value = currentValue ()[index++];
515523 nodes_.push (&value);
516524 bool ok = readValue ();
@@ -863,6 +871,7 @@ class OurFeatures {
863871public:
864872 static OurFeatures all ();
865873 bool allowComments_;
874+ bool allowTrailingCommas_;
866875 bool strictRoot_;
867876 bool allowDroppedNullPlaceholders_;
868877 bool allowNumericKeys_;
@@ -1437,7 +1446,9 @@ bool OurReader::readObject(Token& token) {
14371446 initialTokenOk = readToken (tokenName);
14381447 if (!initialTokenOk)
14391448 break ;
1440- if (tokenName.type_ == tokenObjectEnd && name.empty ()) // empty object
1449+ if (tokenName.type_ == tokenObjectEnd &&
1450+ (name.empty () ||
1451+ features_.allowTrailingCommas_ )) // empty object or trailing comma
14411452 return true ;
14421453 name.clear ();
14431454 if (tokenName.type_ == tokenString) {
@@ -1491,15 +1502,19 @@ bool OurReader::readArray(Token& token) {
14911502 Value init (arrayValue);
14921503 currentValue ().swapPayload (init);
14931504 currentValue ().setOffsetStart (token.start_ - begin_);
1494- skipSpaces ();
1495- if (current_ != end_ && *current_ == ' ]' ) // empty array
1496- {
1497- Token endArray;
1498- readToken (endArray);
1499- return true ;
1500- }
15011505 int index = 0 ;
15021506 for (;;) {
1507+ skipSpaces ();
1508+ if (current_ != end_ && *current_ == ' ]' &&
1509+ (index == 0 ||
1510+ (features_.allowTrailingCommas_ &&
1511+ !features_.allowDroppedNullPlaceholders_ ))) // empty array or trailing
1512+ // comma
1513+ {
1514+ Token endArray;
1515+ readToken (endArray);
1516+ return true ;
1517+ }
15031518 Value& value = currentValue ()[index++];
15041519 nodes_.push (&value);
15051520 bool ok = readValue ();
@@ -1866,6 +1881,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
18661881 bool collectComments = settings_[" collectComments" ].asBool ();
18671882 OurFeatures features = OurFeatures::all ();
18681883 features.allowComments_ = settings_[" allowComments" ].asBool ();
1884+ features.allowTrailingCommas_ = settings_[" allowTrailingCommas" ].asBool ();
18691885 features.strictRoot_ = settings_[" strictRoot" ].asBool ();
18701886 features.allowDroppedNullPlaceholders_ =
18711887 settings_[" allowDroppedNullPlaceholders" ].asBool ();
@@ -1884,6 +1900,7 @@ static void getValidReaderKeys(std::set<String>* valid_keys) {
18841900 valid_keys->clear ();
18851901 valid_keys->insert (" collectComments" );
18861902 valid_keys->insert (" allowComments" );
1903+ valid_keys->insert (" allowTrailingCommas" );
18871904 valid_keys->insert (" strictRoot" );
18881905 valid_keys->insert (" allowDroppedNullPlaceholders" );
18891906 valid_keys->insert (" allowNumericKeys" );
@@ -1917,6 +1934,7 @@ Value& CharReaderBuilder::operator[](const String& key) {
19171934void CharReaderBuilder::strictMode (Json::Value* settings) {
19181935 // ! [CharReaderBuilderStrictMode]
19191936 (*settings)[" allowComments" ] = false ;
1937+ (*settings)[" allowTrailingCommas" ] = false ;
19201938 (*settings)[" strictRoot" ] = true ;
19211939 (*settings)[" allowDroppedNullPlaceholders" ] = false ;
19221940 (*settings)[" allowNumericKeys" ] = false ;
@@ -1932,6 +1950,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
19321950 // ! [CharReaderBuilderDefaults]
19331951 (*settings)[" collectComments" ] = true ;
19341952 (*settings)[" allowComments" ] = true ;
1953+ (*settings)[" allowTrailingCommas" ] = true ;
19351954 (*settings)[" strictRoot" ] = false ;
19361955 (*settings)[" allowDroppedNullPlaceholders" ] = false ;
19371956 (*settings)[" allowNumericKeys" ] = false ;
0 commit comments