Merge pull request #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.
This commit is contained in:
Christopher Dunn 2015-03-06 12:58:55 -06:00
commit b2a7438d08
3 changed files with 37 additions and 0 deletions

View File

@ -320,6 +320,8 @@ public:
- `"failIfExtra": false or true` - `"failIfExtra": false or true`
- If true, `parse()` returns false when extra non-whitespace trails - If true, `parse()` returns false when extra non-whitespace trails
the JSON value in the input string. the JSON value in the input string.
- `"rejectDupKeys": false or true`
- If true, `parse()` returns false when a key is duplicated within an object.
You can examine 'settings_` yourself You can examine 'settings_` yourself
to see the defaults. You can also write and read them just like any to see the defaults. You can also write and read them just like any

View File

@ -916,6 +916,7 @@ public:
bool allowNumericKeys_; bool allowNumericKeys_;
bool allowSingleQuotes_; bool allowSingleQuotes_;
bool failIfExtra_; bool failIfExtra_;
bool rejectDupKeys_;
int stackLimit_; int stackLimit_;
}; // OurFeatures }; // OurFeatures
@ -1431,6 +1432,11 @@ bool OurReader::readObject(Token& tokenStart) {
"Missing ':' after object member name", colon, tokenObjectEnd); "Missing ':' after object member name", colon, tokenObjectEnd);
} }
if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30"); if (name.length() >= (1U<<30)) throw std::runtime_error("keylength >= 2^30");
if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
std::string msg = "Duplicate key: '" + name + "'";
return addErrorAndRecover(
msg, tokenName, tokenObjectEnd);
}
Value& value = currentValue()[name]; Value& value = currentValue()[name];
nodes_.push(&value); nodes_.push(&value);
bool ok = readValue(); bool ok = readValue();
@ -1896,6 +1902,7 @@ CharReader* CharReaderBuilder::newCharReader() const
features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
features.stackLimit_ = settings_["stackLimit"].asInt(); features.stackLimit_ = settings_["stackLimit"].asInt();
features.failIfExtra_ = settings_["failIfExtra"].asBool(); features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
return new OurCharReader(collectComments, features); return new OurCharReader(collectComments, features);
} }
static void getValidReaderKeys(std::set<std::string>* valid_keys) static void getValidReaderKeys(std::set<std::string>* valid_keys)
@ -1909,6 +1916,7 @@ static void getValidReaderKeys(std::set<std::string>* valid_keys)
valid_keys->insert("allowSingleQuotes"); valid_keys->insert("allowSingleQuotes");
valid_keys->insert("stackLimit"); valid_keys->insert("stackLimit");
valid_keys->insert("failIfExtra"); valid_keys->insert("failIfExtra");
valid_keys->insert("rejectDupKeys");
} }
bool CharReaderBuilder::validate(Json::Value* invalid) const bool CharReaderBuilder::validate(Json::Value* invalid) const
{ {
@ -1941,6 +1949,7 @@ void CharReaderBuilder::strictMode(Json::Value* settings)
(*settings)["allowNumericKeys"] = false; (*settings)["allowNumericKeys"] = false;
(*settings)["allowSingleQuotes"] = false; (*settings)["allowSingleQuotes"] = false;
(*settings)["failIfExtra"] = true; (*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true;
//! [CharReaderBuilderStrictMode] //! [CharReaderBuilderStrictMode]
} }
// static // static
@ -1955,6 +1964,7 @@ void CharReaderBuilder::setDefaults(Json::Value* settings)
(*settings)["allowSingleQuotes"] = false; (*settings)["allowSingleQuotes"] = false;
(*settings)["stackLimit"] = 1000; (*settings)["stackLimit"] = 1000;
(*settings)["failIfExtra"] = false; (*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false;
//! [CharReaderBuilderDefaults] //! [CharReaderBuilderDefaults]
} }

View File

@ -1884,6 +1884,29 @@ JSONTEST_FIXTURE(CharReaderTest, parseWithStackLimit) {
} }
} }
struct CharReaderStrictModeTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(CharReaderStrictModeTest, dupKeys) {
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
"{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }";
{
b.strictMode(&b.settings_);
Json::CharReader* reader(b.newCharReader());
std::string errs;
bool ok = reader->parse(
doc, doc + std::strlen(doc),
&root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT_STRING_EQUAL(
"* Line 1, Column 41\n"
" Duplicate key: 'key'\n",
errs);
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
delete reader;
}
}
struct CharReaderFailIfExtraTest : JsonTest::TestCase {}; struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) { JSONTEST_FIXTURE(CharReaderFailIfExtraTest, issue164) {
@ -2305,6 +2328,8 @@ int main(int argc, const char* argv[]) {
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError); JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithDetailError);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit); JSONTEST_REGISTER_FIXTURE(runner, CharReaderTest, parseWithStackLimit);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderStrictModeTest, dupKeys);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164); JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue164);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107); JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, issue107);
JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject); JSONTEST_REGISTER_FIXTURE(runner, CharReaderFailIfExtraTest, commentAfterObject);