Commit 80c43b60dc18240214fad7712f93c99e5c1c00c3

Authored by m-holger
Committed by GitHub
2 parents 183ff8b9 78012927

Merge pull request #1132 from m-holger/jdk

In JSON::parse allow duplicate dictionary keys
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&amp; key, JSON const&amp; 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
... ... @@ -90,6 +90,5 @@ JSON optional key 0
90 90 JSON 16 high high 0
91 91 JSON 16 low not after high 0
92 92 JSON 16 dangling high 0
93   -JSON parse duplicate key 0
94 93 JSON schema array for single item 0
95 94 JSON schema array length mismatch 0
... ...
libtests/qtest/json_parse.test
... ... @@ -32,7 +32,7 @@ if ($^O ne &#39;msys&#39;)
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
  1 +dictionary start
  2 +dictionary item: one -> [11, 12): 1
  3 +dictionary item: two -> [23, 24): 2
  4 +dictionary item: one -> [35, 36): 3
  5 +dictionary item: four -> [48, 49): 4
  6 +container end: [0, 51): {}
  7 +{}
... ...
libtests/qtest/json_parse/good-12.json 0 โ†’ 100644
  1 +{
  2 + "one": 1,
  3 + "two": 2,
  4 + "one": 3,
  5 + "four": 4
  6 +}
... ...
libtests/qtest/json_parse/save-12.json 0 โ†’ 100644
  1 +{
  2 + "four": 4,
  3 + "one": 3,
  4 + "two": 2
  5 +}
... ...
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
... ...