@@ -67,6 +67,7 @@ Features Features::all() { return {}; }
67
67
Features Features::strictMode () {
68
68
Features features;
69
69
features.allowComments_ = false ;
70
+ features.allowTrailingCommas_ = false ;
70
71
features.strictRoot_ = true ;
71
72
features.allowDroppedNullPlaceholders_ = false ;
72
73
features.allowNumericKeys_ = false ;
@@ -454,7 +455,9 @@ bool Reader::readObject(Token& token) {
454
455
initialTokenOk = readToken (tokenName);
455
456
if (!initialTokenOk)
456
457
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
458
461
return true ;
459
462
name.clear ();
460
463
if (tokenName.type_ == tokenString) {
@@ -502,15 +505,20 @@ bool Reader::readArray(Token& token) {
502
505
Value init (arrayValue);
503
506
currentValue ().swapPayload (init);
504
507
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
- }
512
508
int index = 0 ;
513
509
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
+
514
522
Value& value = currentValue ()[index ++];
515
523
nodes_.push (&value);
516
524
bool ok = readValue ();
@@ -863,6 +871,7 @@ class OurFeatures {
863
871
public:
864
872
static OurFeatures all ();
865
873
bool allowComments_;
874
+ bool allowTrailingCommas_;
866
875
bool strictRoot_;
867
876
bool allowDroppedNullPlaceholders_;
868
877
bool allowNumericKeys_;
@@ -1437,7 +1446,9 @@ bool OurReader::readObject(Token& token) {
1437
1446
initialTokenOk = readToken (tokenName);
1438
1447
if (!initialTokenOk)
1439
1448
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
1441
1452
return true ;
1442
1453
name.clear ();
1443
1454
if (tokenName.type_ == tokenString) {
@@ -1491,15 +1502,19 @@ bool OurReader::readArray(Token& token) {
1491
1502
Value init (arrayValue);
1492
1503
currentValue ().swapPayload (init);
1493
1504
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
- }
1501
1505
int index = 0 ;
1502
1506
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
+ }
1503
1518
Value& value = currentValue ()[index ++];
1504
1519
nodes_.push (&value);
1505
1520
bool ok = readValue ();
@@ -1866,6 +1881,7 @@ CharReader* CharReaderBuilder::newCharReader() const {
1866
1881
bool collectComments = settings_[" collectComments" ].asBool ();
1867
1882
OurFeatures features = OurFeatures::all ();
1868
1883
features.allowComments_ = settings_[" allowComments" ].asBool ();
1884
+ features.allowTrailingCommas_ = settings_[" allowTrailingCommas" ].asBool ();
1869
1885
features.strictRoot_ = settings_[" strictRoot" ].asBool ();
1870
1886
features.allowDroppedNullPlaceholders_ =
1871
1887
settings_[" allowDroppedNullPlaceholders" ].asBool ();
@@ -1884,6 +1900,7 @@ static void getValidReaderKeys(std::set<String>* valid_keys) {
1884
1900
valid_keys->clear ();
1885
1901
valid_keys->insert (" collectComments" );
1886
1902
valid_keys->insert (" allowComments" );
1903
+ valid_keys->insert (" allowTrailingCommas" );
1887
1904
valid_keys->insert (" strictRoot" );
1888
1905
valid_keys->insert (" allowDroppedNullPlaceholders" );
1889
1906
valid_keys->insert (" allowNumericKeys" );
@@ -1917,6 +1934,7 @@ Value& CharReaderBuilder::operator[](const String& key) {
1917
1934
void CharReaderBuilder::strictMode (Json::Value* settings) {
1918
1935
// ! [CharReaderBuilderStrictMode]
1919
1936
(*settings)[" allowComments" ] = false ;
1937
+ (*settings)[" allowTrailingCommas" ] = false ;
1920
1938
(*settings)[" strictRoot" ] = true ;
1921
1939
(*settings)[" allowDroppedNullPlaceholders" ] = false ;
1922
1940
(*settings)[" allowNumericKeys" ] = false ;
@@ -1932,6 +1950,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings) {
1932
1950
// ! [CharReaderBuilderDefaults]
1933
1951
(*settings)[" collectComments" ] = true ;
1934
1952
(*settings)[" allowComments" ] = true ;
1953
+ (*settings)[" allowTrailingCommas" ] = true ;
1935
1954
(*settings)[" strictRoot" ] = false ;
1936
1955
(*settings)[" allowDroppedNullPlaceholders" ] = false ;
1937
1956
(*settings)[" allowNumericKeys" ] = false ;
0 commit comments