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,12 +143,6 @@ class JSON | ||
| 143 | QPDF_DLL | 143 | QPDF_DLL |
| 144 | bool isDictionary() const; | 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 | // Accessors. Accessor behavior: | 146 | // Accessors. Accessor behavior: |
| 153 | // | 147 | // |
| 154 | // - If argument is wrong type, including null, return false | 148 | // - If argument is wrong type, including null, return false |
| @@ -327,7 +321,6 @@ class JSON | @@ -327,7 +321,6 @@ class JSON | ||
| 327 | ~JSON_dictionary() override = default; | 321 | ~JSON_dictionary() override = default; |
| 328 | void write(Pipeline*, size_t depth) const override; | 322 | void write(Pipeline*, size_t depth) const override; |
| 329 | std::map<std::string, JSON> members; | 323 | std::map<std::string, JSON> members; |
| 330 | - std::set<std::string> parsed_keys; | ||
| 331 | }; | 324 | }; |
| 332 | struct JSON_array; | 325 | struct JSON_array; |
| 333 | struct JSON_string: public JSON_value | 326 | struct JSON_string: public JSON_value |
libqpdf/JSON.cc
| @@ -287,16 +287,6 @@ JSON::addDictionaryMember(std::string const& key, JSON const& val) | @@ -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 | JSON | 290 | JSON |
| 301 | JSON::makeArray() | 291 | JSON::makeArray() |
| 302 | { | 292 | { |
| @@ -1266,11 +1256,6 @@ JSONParser::handleToken() | @@ -1266,11 +1256,6 @@ JSONParser::handleToken() | ||
| 1266 | break; | 1256 | break; |
| 1267 | 1257 | ||
| 1268 | case ps_dict_after_colon: | 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 | if (!reactor || !reactor->dictionaryItem(dict_key, item)) { | 1259 | if (!reactor || !reactor->dictionaryItem(dict_key, item)) { |
| 1275 | tos.addDictionaryMember(dict_key, item); | 1260 | tos.addDictionaryMember(dict_key, item); |
| 1276 | } | 1261 | } |
libtests/json.cc
| @@ -162,11 +162,6 @@ test_main() | @@ -162,11 +162,6 @@ test_main() | ||
| 162 | assert(jarr.addArrayElement(uninitialized).isNull()); | 162 | assert(jarr.addArrayElement(uninitialized).isNull()); |
| 163 | assert(!uninitialized.isArray()); | 163 | assert(!uninitialized.isArray()); |
| 164 | assert(!uninitialized.isDictionary()); | 164 | assert(!uninitialized.isDictionary()); |
| 165 | - try { | ||
| 166 | - uninitialized.checkDictionaryKeySeen("key"); | ||
| 167 | - assert(false); | ||
| 168 | - } catch (std::logic_error&) { | ||
| 169 | - } | ||
| 170 | std::string st_out = "unchanged"; | 165 | std::string st_out = "unchanged"; |
| 171 | assert(!uninitialized.getString(st_out)); | 166 | assert(!uninitialized.getString(st_out)); |
| 172 | assert(!uninitialized.getNumber(st_out)); | 167 | assert(!uninitialized.getNumber(st_out)); |
libtests/libtests.testcov
| @@ -90,6 +90,5 @@ JSON optional key 0 | @@ -90,6 +90,5 @@ JSON optional key 0 | ||
| 90 | JSON 16 high high 0 | 90 | JSON 16 high high 0 |
| 91 | JSON 16 low not after high 0 | 91 | JSON 16 low not after high 0 |
| 92 | JSON 16 dangling high 0 | 92 | JSON 16 dangling high 0 |
| 93 | -JSON parse duplicate key 0 | ||
| 94 | JSON schema array for single item 0 | 93 | JSON schema array for single item 0 |
| 95 | JSON schema array length mismatch 0 | 94 | JSON schema array length mismatch 0 |
libtests/qtest/json_parse.test
| @@ -32,7 +32,7 @@ if ($^O ne 'msys') | @@ -32,7 +32,7 @@ if ($^O ne 'msys') | ||
| 32 | 32 | ||
| 33 | cleanup(); | 33 | cleanup(); |
| 34 | 34 | ||
| 35 | -my $good = 11; | 35 | +my $good = 12; |
| 36 | 36 | ||
| 37 | for (my $i = 1; $i <= $good; ++$i) | 37 | for (my $i = 1; $i <= $good; ++$i) |
| 38 | { | 38 | { |
| @@ -120,7 +120,7 @@ my @bad = ( | @@ -120,7 +120,7 @@ my @bad = ( | ||
| 120 | "stray low surrogate", # 37 | 120 | "stray low surrogate", # 37 |
| 121 | "high high surrogate", # 38 | 121 | "high high surrogate", # 38 |
| 122 | "dangling high surrogate", # 39 | 122 | "dangling high surrogate", # 39 |
| 123 | - "duplicate dictionary key", # 40 | 123 | + undef, # 40, removed |
| 124 | "decimal point after minus",# 41 | 124 | "decimal point after minus",# 41 |
| 125 | "e after minus", # 42 | 125 | "e after minus", # 42 |
| 126 | "missing digit after e", # 43 | 126 | "missing digit after e", # 43 |
| @@ -136,10 +136,22 @@ foreach my $d (@bad) | @@ -136,10 +136,22 @@ foreach my $d (@bad) | ||
| 136 | { | 136 | { |
| 137 | ++$i; | 137 | ++$i; |
| 138 | my $n = sprintf("%02d", $i); | 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 | cleanup(); | 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,6 +11,10 @@ For a detailed list of changes, please see the file | ||
| 11 | 12.0.0: not yet released | 11 | 12.0.0: not yet released |
| 12 | - API: breaking changes | 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 | - Deprecated versionless overload of ``QPDFObjectHandle::getJSON`` | 18 | - Deprecated versionless overload of ``QPDFObjectHandle::getJSON`` |
| 15 | has been removed. | 19 | has been removed. |
| 16 | 20 | ||
| @@ -20,7 +24,7 @@ For a detailed list of changes, please see the file | @@ -20,7 +24,7 @@ For a detailed list of changes, please see the file | ||
| 20 | or ``Buffer buffer2{buffer1.copy()};`` to make it explicit that | 24 | or ``Buffer buffer2{buffer1.copy()};`` to make it explicit that |
| 21 | copying is intended. | 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 | which has been fixed to ``subtract``. | 28 | which has been fixed to ``subtract``. |
| 25 | 29 | ||
| 26 | - Library Enhancements | 30 | - Library Enhancements |