Commit 35b1e1c4936903ebb841ed89945ea55fe95e0abb

Authored by Jay Berkenbilt
1 parent dc8df962

Explicitly test ignoring unknown keys in JSON input

@@ -97,6 +97,9 @@ General things to remember: @@ -97,6 +97,9 @@ General things to remember:
97 97
98 * Add json to the large file tests. 98 * Add json to the large file tests.
99 99
  100 +* Document that keys other than "qpdf-v2" are ignored so people can
  101 + stash their own stuff.
  102 +
100 JSON to PDF: 103 JSON to PDF:
101 104
102 Have --json-input and --update-from-json. With --json-input, the json 105 Have --json-input and --update-from-json. With --json-input, the json
libqpdf/QPDF_json.cc
@@ -170,7 +170,7 @@ QPDF::JSONReactor::containerEnd(JSON const& value) @@ -170,7 +170,7 @@ QPDF::JSONReactor::containerEnd(JSON const& value)
170 } 170 }
171 } else if (state == st_objects) { 171 } else if (state == st_objects) {
172 if (parse_error) { 172 if (parse_error) {
173 - // ignore 173 + QTC::TC("qpdf", "QPDF_json don't check object after parse error");
174 } else if (cur_object == "trailer") { 174 } else if (cur_object == "trailer") {
175 if (!saw_value) { 175 if (!saw_value) {
176 QTC::TC("qpdf", "QPDF_json trailer no value"); 176 QTC::TC("qpdf", "QPDF_json trailer no value");
@@ -279,9 +279,9 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -279,9 +279,9 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
279 this->saw_qpdf = true; 279 this->saw_qpdf = true;
280 nestedState(key, value, st_qpdf); 280 nestedState(key, value, st_qpdf);
281 } else { 281 } else {
282 - // Ignore all other fields for forward compatibility.  
283 - // Don't use nestedState since this can be any type.  
284 - // QXXXQ QTC 282 + // Ignore all other fields. We explicitly allow people to
  283 + // add other top-level keys for their own use.
  284 + QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key");
285 next_state = st_ignore; 285 next_state = st_ignore;
286 } 286 }
287 } else if (state == st_qpdf) { 287 } else if (state == st_qpdf) {
@@ -304,8 +304,9 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -304,8 +304,9 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
304 this->saw_objects = true; 304 this->saw_objects = true;
305 nestedState(key, value, st_objects); 305 nestedState(key, value, st_objects);
306 } else { 306 } else {
307 - // ignore unknown keys for forward compatibility  
308 - // QXXXQ QTC 307 + // ignore unknown keys for forward compatibility and to
  308 + // skip keys we don't care about like "maxobjectid".
  309 + QTC::TC("qpdf", "QPDF_json ignore second-level key");
309 next_state = st_ignore; 310 next_state = st_ignore;
310 } 311 }
311 } else if (state == st_objects) { 312 } else if (state == st_objects) {
@@ -351,7 +352,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -351,7 +352,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
351 } 352 }
352 } else { 353 } else {
353 // Ignore unknown keys for forward compatibility 354 // Ignore unknown keys for forward compatibility
354 - // QXXXQ QTC 355 + QTC::TC("qpdf", "QPDF_json ignore unknown key in object_top");
355 next_state = st_ignore; 356 next_state = st_ignore;
356 } 357 }
357 if (replacement.isInitialized()) { 358 if (replacement.isInitialized()) {
@@ -373,7 +374,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -373,7 +374,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
373 parse_error = true; 374 parse_error = true;
374 } else { 375 } else {
375 // Ignore unknown keys for forward compatibility 376 // Ignore unknown keys for forward compatibility
376 - // QXXXQ QTC 377 + QTC::TC("qpdf", "QPDF_json ignore unknown key in trailer");
377 next_state = st_ignore; 378 next_state = st_ignore;
378 } 379 }
379 } else if (state == st_stream) { 380 } else if (state == st_stream) {
@@ -430,7 +431,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) @@ -430,7 +431,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value)
430 } 431 }
431 } else { 432 } else {
432 // Ignore unknown keys for forward compatibility. 433 // Ignore unknown keys for forward compatibility.
433 - // QXXXQ QTC 434 + QTC::TC("qpdf", "QPDF_json ignore unknown key in stream");
434 next_state = st_ignore; 435 next_state = st_ignore;
435 } 436 }
436 } else if (state == st_object) { 437 } else if (state == st_object) {
@@ -549,12 +550,6 @@ QPDF::importJSON(std::shared_ptr<InputSource> is, bool must_be_complete) @@ -549,12 +550,6 @@ QPDF::importJSON(std::shared_ptr<InputSource> is, bool must_be_complete)
549 if (reactor.anyErrors()) { 550 if (reactor.anyErrors()) {
550 throw std::runtime_error(is->getName() + ": errors found in JSON"); 551 throw std::runtime_error(is->getName() + ": errors found in JSON");
551 } 552 }
552 - // QXXXQ  
553 - // std::cout << "trailer:\n" << getTrailer().unparse() << std::endl;  
554 - // for (auto& oh: getAllObjects()) {  
555 - // std::cout << oh.unparse() << ":" << std::endl;  
556 - // std::cout << oh.unparseResolved() << std::endl;  
557 - // }  
558 } 553 }
559 554
560 void 555 void
qpdf/qpdf.testcov
@@ -669,3 +669,9 @@ QPDF_json value stream both or neither 0 @@ -669,3 +669,9 @@ QPDF_json value stream both or neither 0
669 QPDFJob need json-stream-prefix for stdout 0 669 QPDFJob need json-stream-prefix for stdout 0
670 QPDFJob write json to stdout 0 670 QPDFJob write json to stdout 0
671 QPDFJob write json to file 0 671 QPDFJob write json to file 0
  672 +QPDF_json don't check object after parse error 0
  673 +QPDF_json ignoring unknown top-level key 0
  674 +QPDF_json ignore second-level key 0
  675 +QPDF_json ignore unknown key in object_top 0
  676 +QPDF_json ignore unknown key in trailer 0
  677 +QPDF_json ignore unknown key in stream 0
qpdf/qtest/qpdf/manual-qpdf-json.json
1 { 1 {
  2 + "comment": [
  3 + "We allow and ignore other top-level keys"
  4 + ],
2 "qpdf-v2": { 5 "qpdf-v2": {
3 "pdfversion": "2.0", 6 "pdfversion": "2.0",
  7 + "maybe-future-key": {
  8 + "x": [
  9 + "Lots of times we ignore things",
  10 + "for forward-compatibility so we don't have",
  11 + "to change the version number if we add stuff",
  12 + "in the future"
  13 + ]
  14 + },
4 "objects": { 15 "objects": {
5 "obj:3 0 R": { 16 "obj:3 0 R": {
6 "value": { 17 "value": {
@@ -19,7 +30,8 @@ @@ -19,7 +30,8 @@
19 "/ProcSet": "5 0 R" 30 "/ProcSet": "5 0 R"
20 }, 31 },
21 "/Type": "/Page" 32 "/Type": "/Page"
22 - } 33 + },
  34 + "ignore": "this is ignored"
23 }, 35 },
24 "obj:2 0 R": { 36 "obj:2 0 R": {
25 "value": { 37 "value": {
@@ -28,6 +40,10 @@ @@ -28,6 +40,10 @@
28 "3 0 R" 40 "3 0 R"
29 ], 41 ],
30 "/Type": "/Pages" 42 "/Type": "/Pages"
  43 + },
  44 + "ignore": {
  45 + "potato": "salad",
  46 + "this": ["is ignored too"]
31 } 47 }
32 }, 48 },
33 "obj:1 0 R": { 49 "obj:1 0 R": {
@@ -38,6 +54,7 @@ @@ -38,6 +54,7 @@
38 }, 54 },
39 "obj:4 0 R": { 55 "obj:4 0 R": {
40 "stream": { 56 "stream": {
  57 + "what-is-this": "doesn't matter",
41 "dict": {}, 58 "dict": {},
42 "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=" 59 "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo="
43 } 60 }
@@ -58,6 +75,7 @@ @@ -58,6 +75,7 @@
58 } 75 }
59 }, 76 },
60 "trailer": { 77 "trailer": {
  78 + "even-here-we-ignore": "stuff",
61 "value": { 79 "value": {
62 "/QTest": "7 0 R", 80 "/QTest": "7 0 R",
63 "/Root": "1 0 R", 81 "/Root": "1 0 R",