Commit 80c43b60dc18240214fad7712f93c99e5c1c00c3
Committed by
GitHub
Merge pull request #1132 from m-holger/jdk
In JSON::parse allow duplicate dictionary keys
Showing
9 changed files
with
41 additions
and
35 deletions
include/qpdf/JSON.hh
| ... | ... | @@ -143,12 +143,6 @@ class JSON |
| 143 | 143 | QPDF_DLL |
| 144 | 144 | bool isDictionary() const; |
| 145 | 145 | |
| 146 | - // If the key is already in the dictionary, return true. Otherwise, mark it as seen and return | |
| 147 | - // false. This is primarily intended to be used by the parser to detect duplicate keys when the | |
| 148 | - // reactor blocks them from being added to the final dictionary. | |
| 149 | - QPDF_DLL | |
| 150 | - bool checkDictionaryKeySeen(std::string const& key); | |
| 151 | - | |
| 152 | 146 | // Accessors. Accessor behavior: |
| 153 | 147 | // |
| 154 | 148 | // - If argument is wrong type, including null, return false |
| ... | ... | @@ -327,7 +321,6 @@ class JSON |
| 327 | 321 | ~JSON_dictionary() override = default; |
| 328 | 322 | void write(Pipeline*, size_t depth) const override; |
| 329 | 323 | std::map<std::string, JSON> members; |
| 330 | - std::set<std::string> parsed_keys; | |
| 331 | 324 | }; |
| 332 | 325 | struct JSON_array; |
| 333 | 326 | struct JSON_string: public JSON_value | ... | ... |
libqpdf/JSON.cc
| ... | ... | @@ -287,16 +287,6 @@ JSON::addDictionaryMember(std::string const& key, JSON const& val) |
| 287 | 287 | } |
| 288 | 288 | } |
| 289 | 289 | |
| 290 | -bool | |
| 291 | -JSON::checkDictionaryKeySeen(std::string const& key) | |
| 292 | -{ | |
| 293 | - if (auto* obj = m ? dynamic_cast<JSON_dictionary*>(m->value.get()) : nullptr) { | |
| 294 | - return !obj->parsed_keys.insert(key).second; | |
| 295 | - } | |
| 296 | - throw std::logic_error("JSON::checkDictionaryKey called on non-dictionary"); | |
| 297 | - return false; // unreachable | |
| 298 | -} | |
| 299 | - | |
| 300 | 290 | JSON |
| 301 | 291 | JSON::makeArray() |
| 302 | 292 | { |
| ... | ... | @@ -1266,11 +1256,6 @@ JSONParser::handleToken() |
| 1266 | 1256 | break; |
| 1267 | 1257 | |
| 1268 | 1258 | case ps_dict_after_colon: |
| 1269 | - if (tos.checkDictionaryKeySeen(dict_key)) { | |
| 1270 | - QTC::TC("libtests", "JSON parse duplicate key"); | |
| 1271 | - throw std::runtime_error( | |
| 1272 | - "JSON: offset " + std::to_string(dict_key_offset) + ": duplicated dictionary key"); | |
| 1273 | - } | |
| 1274 | 1259 | if (!reactor || !reactor->dictionaryItem(dict_key, item)) { |
| 1275 | 1260 | tos.addDictionaryMember(dict_key, item); |
| 1276 | 1261 | } | ... | ... |
libtests/json.cc
| ... | ... | @@ -162,11 +162,6 @@ test_main() |
| 162 | 162 | assert(jarr.addArrayElement(uninitialized).isNull()); |
| 163 | 163 | assert(!uninitialized.isArray()); |
| 164 | 164 | assert(!uninitialized.isDictionary()); |
| 165 | - try { | |
| 166 | - uninitialized.checkDictionaryKeySeen("key"); | |
| 167 | - assert(false); | |
| 168 | - } catch (std::logic_error&) { | |
| 169 | - } | |
| 170 | 165 | std::string st_out = "unchanged"; |
| 171 | 166 | assert(!uninitialized.getString(st_out)); |
| 172 | 167 | assert(!uninitialized.getNumber(st_out)); | ... | ... |
libtests/libtests.testcov
libtests/qtest/json_parse.test
| ... | ... | @@ -32,7 +32,7 @@ if ($^O ne 'msys') |
| 32 | 32 | |
| 33 | 33 | cleanup(); |
| 34 | 34 | |
| 35 | -my $good = 11; | |
| 35 | +my $good = 12; | |
| 36 | 36 | |
| 37 | 37 | for (my $i = 1; $i <= $good; ++$i) |
| 38 | 38 | { |
| ... | ... | @@ -120,7 +120,7 @@ my @bad = ( |
| 120 | 120 | "stray low surrogate", # 37 |
| 121 | 121 | "high high surrogate", # 38 |
| 122 | 122 | "dangling high surrogate", # 39 |
| 123 | - "duplicate dictionary key", # 40 | |
| 123 | + undef, # 40, removed | |
| 124 | 124 | "decimal point after minus",# 41 |
| 125 | 125 | "e after minus", # 42 |
| 126 | 126 | "missing digit after e", # 43 |
| ... | ... | @@ -136,10 +136,22 @@ foreach my $d (@bad) |
| 136 | 136 | { |
| 137 | 137 | ++$i; |
| 138 | 138 | my $n = sprintf("%02d", $i); |
| 139 | - $td->runtest("$n: $d", | |
| 140 | - {$td->COMMAND => "json_parse bad-$n.json"}, | |
| 141 | - {$td->FILE => "bad-$n.out", $td->EXIT_STATUS => 2}, | |
| 142 | - $td->NORMALIZE_NEWLINES); | |
| 139 | + if (defined $d) | |
| 140 | + { | |
| 141 | + $td->runtest("$n: $d", | |
| 142 | + {$td->COMMAND => "json_parse bad-$n.json"}, | |
| 143 | + {$td->FILE => "bad-$n.out", $td->EXIT_STATUS => 2}, | |
| 144 | + $td->NORMALIZE_NEWLINES); | |
| 145 | + } | |
| 146 | + else | |
| 147 | + { | |
| 148 | + # We used to disallow duplicated keys but no longer do. Add | |
| 149 | + # this hack to ignore a test number rather than renaming | |
| 150 | + # tests. | |
| 151 | + $td->runtest("$n: no longer used", | |
| 152 | + {$td->STRING => ""}, | |
| 153 | + {$td->STRING => ""}); | |
| 154 | + } | |
| 143 | 155 | } |
| 144 | 156 | |
| 145 | 157 | cleanup(); | ... | ... |
libtests/qtest/json_parse/good-12-react.out
0 โ 100644
libtests/qtest/json_parse/good-12.json
0 โ 100644
libtests/qtest/json_parse/save-12.json
0 โ 100644
manual/release-notes.rst
| ... | ... | @@ -11,6 +11,10 @@ For a detailed list of changes, please see the file |
| 11 | 11 | 12.0.0: not yet released |
| 12 | 12 | - API: breaking changes |
| 13 | 13 | |
| 14 | + - ``JSON::checkDictionaryKeySeen`` has been removed. If ``JSON::parse`` | |
| 15 | + encounters duplicate keys the last value is silently accepted instead | |
| 16 | + of throwing a runtime error. | |
| 17 | + | |
| 14 | 18 | - Deprecated versionless overload of ``QPDFObjectHandle::getJSON`` |
| 15 | 19 | has been removed. |
| 16 | 20 | |
| ... | ... | @@ -20,7 +24,7 @@ For a detailed list of changes, please see the file |
| 20 | 24 | or ``Buffer buffer2{buffer1.copy()};`` to make it explicit that |
| 21 | 25 | copying is intended. |
| 22 | 26 | |
| 23 | - - ``QIntC.hh`` contained the typ0 ``substract`` in function names, | |
| 27 | + - ``QIntC.hh`` contained the typo ``substract`` in function names, | |
| 24 | 28 | which has been fixed to ``subtract``. |
| 25 | 29 | |
| 26 | 30 | - Library Enhancements | ... | ... |