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,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&amp; key, JSON const&amp; val) @@ -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 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 &#39;msys&#39;) @@ -32,7 +32,7 @@ if ($^O ne &#39;msys&#39;)
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
  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,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