Skip to content

Commit b2a7438

Browse files
committed
Merge pull request open-source-parsers#205 from open-source-parsers/reject-dup-keys
[Shekhar (shakers007) wrote](https://sourceforge.net/p/jsoncpp/bugs/22/): > As per RFC4627 (section 2.2), names within an object should be unique. When using JSONCPP's strict mode, parsing such an object should fail.
2 parents ff61752 + 62ad140 commit b2a7438

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

include/json/reader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ class JSON_API CharReaderBuilder : public CharReader::Factory {
320320
- `"failIfExtra": false or true`
321321
- If true, `parse()` returns false when extra non-whitespace trails
322322
the JSON value in the input string.
323+
- `"rejectDupKeys": false or true`
324+
- If true, `parse()` returns false when a key is duplicated within an object.
323325
324326
You can examine 'settings_` yourself
325327
to see the defaults. You can also write and read them just like any

src/lib_json/json_reader.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ class OurFeatures {
916916
bool allowNumericKeys_;
917917
bool allowSingleQuotes_;
918918
bool failIfExtra_;
919+
bool rejectDupKeys_;
919920
int stackLimit_;
920921
}; // OurFeatures
921922

@@ -1431,6 +1432,11 @@ bool OurReader::readObject(Token& tokenStart) {
14311432
"Missing ':' after object member name", colon, tokenObjectEnd);
14321433
}
14331434
if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30");
1435+
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
1436+
std::string msg = "Duplicate key: '" + name + "'";
1437+
return addErrorAndRecover(
1438+
msg, tokenName, tokenObjectEnd);
1439+
}
14341440
Value& value = currentValue()[name];
14351441
nodes_.push(&value);
14361442
bool ok = readValue();
@@ -1896,6 +1902,7 @@ CharReader* CharReaderBuilder::newCharReader() const
18961902
features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
18971903
features.stackLimit_ = settings_["stackLimit"].asInt();
18981904
features.failIfExtra_ = settings_["failIfExtra"].asBool();
1905+
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
18991906
return new OurCharReader(collectComments, features);
19001907
}
19011908
static void getValidReaderKeys(std::set<std::string>* valid_keys)
@@ -1909,6 +1916,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
19091916
valid_keys->insert("allowSingleQuotes");
19101917
valid_keys->insert("stackLimit");
19111918
valid_keys->insert("failIfExtra");
1919+
valid_keys->insert("rejectDupKeys");
19121920
}
19131921
bool CharReaderBuilder::validate(Json::Value* invalid) const
19141922
{
@@ -1941,6 +1949,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
19411949
(*settings)["allowNumericKeys"] = false;
19421950
(*settings)["allowSingleQuotes"] = false;
19431951
(*settings)["failIfExtra"] = true;
1952+
(*settings)["rejectDupKeys"] = true;
19441953
//! [CharReaderBuilderStrictMode]
19451954
}
19461955
// static
@@ -1955,6 +1964,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
19551964
(*settings)["allowSingleQuotes"] = false;
19561965
(*settings)["stackLimit"] = 1000;
19571966
(*settings)["failIfExtra"] = false;
1967+
(*settings)["rejectDupKeys"] = false;
19581968
//! [CharReaderBuilderDefaults]
19591969
}
19601970

src/test_lib_json/main.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,29 @@ JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
18841884
}
18851885
}
18861886

1887+
struct CharReaderStrictModeTest : JsonTest::TestCase {};
1888+
1889+
JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) {
1890+
Json::CharReaderBuilder b;
1891+
Json::Value root;
1892+
char const doc[] =
1893+
"{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }";
1894+
{
1895+
b.strictMode(&b.settings_);
1896+
Json::CharReader* reader(b.newCharReader());
1897+
std::string errs;
1898+
bool ok = reader->parse(
1899+
doc, doc + std::strlen(doc),
1900+
&root, &errs);
1901+
JSONTEST_ASSERT(!ok);
1902+
JSONTEST_ASSERT_STRING_EQUAL(
1903+
"* Line 1, Column 41\n"
1904+
" Duplicate key: 'key'\n",
1905+
errs);
1906+
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
1907+
delete reader;
1908+
}
1909+
}
18871910
struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
18881911

18891912
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) {
@@ -2305,6 +2328,8 @@ int main(int argc, const char* argv[]) {
23052328
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
23062329
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
23072330

2331+
JSONTEST_REGISTER_FIXTURE(runner, CharReaderStrictModeTest, dupKeys);
2332+
23082333
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
23092334
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107);
23102335
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject);

0 commit comments

Comments
 (0)