Commit d01c4f8819ea93797784c19ecdd623eb41f2a8b4

Authored by Jay Berkenbilt
1 parent bb96499b

Change --json-output format

from "qpdf-v2" to "qpdf": [..., ...]
Showing 63 changed files with 569 additions and 249 deletions
... ... @@ -84,15 +84,13 @@ JSON v2 fixes
84 84 "qpdf": [
85 85 {
86 86 "jsonversion": 2,
  87 + "pdfversion": "1.3",
87 88 "pushedinheritedpageresources": false,
88 89 "calledgetallpages": false,
89 90 "maxobjectid": 10
90 91 },
91 92 {
92   - "pdfversion": "1.3",
93   - "objects": {
94   - ...
95   - }
  93 + ... objects ...
96 94 }
97 95 ]
98 96 }
... ...
cSpell.json
... ... @@ -47,6 +47,7 @@
47 47 "bufpl",
48 48 "bufsize",
49 49 "buildrules",
  50 + "calledgetallpages",
50 51 "ccase",
51 52 "ccitt",
52 53 "cdef",
... ... @@ -369,6 +370,7 @@
369 370 "programfiles",
370 371 "programlisting",
371 372 "proxied",
  373 + "pushedinheritedpageresources",
372 374 "putu",
373 375 "pval",
374 376 "pytest",
... ...
include/qpdf/QPDF.hh
... ... @@ -1072,6 +1072,7 @@ class QPDF
1072 1072 st_initial,
1073 1073 st_top,
1074 1074 st_qpdf,
  1075 + st_qpdf_meta,
1075 1076 st_objects,
1076 1077 st_trailer,
1077 1078 st_object_top,
... ... @@ -1097,7 +1098,9 @@ class QPDF
1097 1098 bool errors;
1098 1099 bool parse_error;
1099 1100 bool saw_qpdf;
  1101 + bool saw_qpdf_meta;
1100 1102 bool saw_objects;
  1103 + bool saw_json_version;
1101 1104 bool saw_pdf_version;
1102 1105 bool saw_trailer;
1103 1106 state_e state;
... ...
libqpdf/QPDFJob.cc
... ... @@ -1741,6 +1741,9 @@ QPDFJob::json_out_schema_v1()
1741 1741 void
1742 1742 QPDFJob::doJSON(QPDF& pdf, Pipeline* p)
1743 1743 {
  1744 + // qpdf guarantees that no new top-level keys whose names start
  1745 + // with "xdata" will be added. These are reserved for users.
  1746 +
1744 1747 std::string captured_json;
1745 1748 std::shared_ptr<Pl_String> pl_str;
1746 1749 if (this->m->test_json_schema) {
... ...
libqpdf/QPDF_json.cc
... ... @@ -226,7 +226,9 @@ QPDF::JSONReactor::JSONReactor(
226 226 errors(false),
227 227 parse_error(false),
228 228 saw_qpdf(false),
  229 + saw_qpdf_meta(false),
229 230 saw_objects(false),
  231 + saw_json_version(false),
230 232 saw_pdf_version(false),
231 233 saw_trailer(false),
232 234 state(st_initial),
... ... @@ -292,17 +294,21 @@ QPDF::JSONReactor::containerEnd(JSON const&amp; value)
292 294 QTC::TC("qpdf", "QPDF_json missing qpdf");
293 295 error(0, "\"qpdf\" object was not seen");
294 296 } else {
  297 + if (!this->saw_json_version) {
  298 + QTC::TC("qpdf", "QPDF_json missing json version");
  299 + error(0, "\"qpdf[0].jsonversion\" was not seen");
  300 + }
295 301 if (must_be_complete && !this->saw_pdf_version) {
296 302 QTC::TC("qpdf", "QPDF_json missing pdf version");
297   - error(0, "\"qpdf-v2.pdfversion\" was not seen");
  303 + error(0, "\"qpdf[0].pdfversion\" was not seen");
298 304 }
299 305 if (!this->saw_objects) {
300 306 QTC::TC("qpdf", "QPDF_json missing objects");
301   - error(0, "\"qpdf-v2.objects\" was not seen");
  307 + error(0, "\"qpdf[1]\" was not seen");
302 308 } else {
303 309 if (must_be_complete && !this->saw_trailer) {
304 310 QTC::TC("qpdf", "QPDF_json missing trailer");
305   - error(0, "\"qpdf-v2.objects.trailer\" was not seen");
  311 + error(0, "\"qpdf[1].trailer\" was not seen");
306 312 }
307 313 }
308 314 }
... ... @@ -421,16 +427,22 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
421 427 QTC::TC("qpdf", "QPDF_json ignoring in st_ignore");
422 428 // ignore
423 429 } else if (state == st_top) {
424   - if (key == "qpdf-v2") {
  430 + if (key == "qpdf") {
425 431 this->saw_qpdf = true;
426   - nestedState(key, value, st_qpdf);
  432 + if (!value.isArray()) {
  433 + QTC::TC("qpdf", "QPDF_json qpdf not array");
  434 + error(value.getStart(), "\"qpdf\" must be an array");
  435 + next_state = st_ignore;
  436 + parse_error = true;
  437 + } else {
  438 + next_state = st_qpdf;
  439 + }
427 440 } else {
428   - // Ignore all other fields. We explicitly allow people to
429   - // add other top-level keys for their own use.
  441 + // Ignore all other fields.
430 442 QTC::TC("qpdf", "QPDF_json ignoring unknown top-level key");
431 443 next_state = st_ignore;
432 444 }
433   - } else if (state == st_qpdf) {
  445 + } else if (state == st_qpdf_meta) {
434 446 if (key == "pdfversion") {
435 447 this->saw_pdf_version = true;
436 448 bool version_okay = false;
... ... @@ -447,9 +459,20 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
447 459 QTC::TC("qpdf", "QPDF_json bad pdf version");
448 460 error(value.getStart(), "invalid PDF version (must be x.y)");
449 461 }
450   - } else if (key == "objects") {
451   - this->saw_objects = true;
452   - nestedState(key, value, st_objects);
  462 + } else if (key == "jsonversion") {
  463 + this->saw_json_version = true;
  464 + bool version_okay = false;
  465 + std::string v;
  466 + if (value.getNumber(v)) {
  467 + std::string version;
  468 + if (QUtil::string_to_int(v.c_str()) == 2) {
  469 + version_okay = true;
  470 + }
  471 + }
  472 + if (!version_okay) {
  473 + QTC::TC("qpdf", "QPDF_json bad json version");
  474 + error(value.getStart(), "invalid JSON version (must be 2)");
  475 + }
453 476 } else {
454 477 // ignore unknown keys for forward compatibility and to
455 478 // skip keys we don't care about like "maxobjectid".
... ... @@ -601,6 +624,20 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
601 624 bool
602 625 QPDF::JSONReactor::arrayItem(JSON const& value)
603 626 {
  627 + if (state == st_qpdf) {
  628 + if (!this->saw_qpdf_meta) {
  629 + this->saw_qpdf_meta = true;
  630 + nestedState("qpdf[0]", value, st_qpdf_meta);
  631 + } else if (!this->saw_objects) {
  632 + this->saw_objects = true;
  633 + nestedState("qpdf[1]", value, st_objects);
  634 + } else {
  635 + QTC::TC("qpdf", "QPDF_json more than two qpdf elements");
  636 + error(value.getStart(), "\"qpdf\" must have two elements");
  637 + next_state = st_ignore;
  638 + parse_error = true;
  639 + }
  640 + }
604 641 if (state == st_object) {
605 642 if (!parse_error) {
606 643 auto tos = object_stack.back();
... ... @@ -771,30 +808,60 @@ QPDF::writeJSON(
771 808 std::string const& file_prefix,
772 809 std::set<std::string> wanted_objects)
773 810 {
  811 + int const depth_outer = 1;
  812 + int const depth_top = 1;
  813 + int const depth_qpdf = 2;
  814 + int const depth_qpdf_inner = 3;
  815 +
774 816 if (version != 2) {
775 817 throw std::runtime_error(
776 818 "QPDF::writeJSON: only version 2 is supported");
777 819 }
778 820 bool first = true;
779 821 if (complete) {
780   - JSON::writeDictionaryOpen(p, first, 0);
  822 + JSON::writeDictionaryOpen(p, first, depth_outer);
781 823 } else {
782 824 first = first_key;
783 825 }
784   - JSON::writeDictionaryKey(p, first, "qpdf-v2", 1);
  826 + JSON::writeDictionaryKey(p, first, "qpdf", depth_top);
785 827 bool first_qpdf = true;
786   - JSON::writeDictionaryOpen(p, first_qpdf, 2);
  828 + JSON::writeArrayOpen(p, first_qpdf, depth_top);
  829 + JSON::writeNext(p, first_qpdf, depth_qpdf);
  830 + bool first_qpdf_inner = true;
  831 + JSON::writeDictionaryOpen(p, first_qpdf_inner, depth_qpdf);
787 832 JSON::writeDictionaryItem(
788   - p, first_qpdf, "pdfversion", JSON::makeString(getPDFVersion()), 2);
  833 + p,
  834 + first_qpdf_inner,
  835 + "jsonversion",
  836 + JSON::makeInt(version),
  837 + depth_qpdf_inner);
  838 + JSON::writeDictionaryItem(
  839 + p,
  840 + first_qpdf_inner,
  841 + "pdfversion",
  842 + JSON::makeString(getPDFVersion()),
  843 + depth_qpdf_inner);
  844 + JSON::writeDictionaryItem(
  845 + p,
  846 + first_qpdf_inner,
  847 + "pushedinheritedpageresources",
  848 + JSON::makeBool(everPushedInheritedAttributesToPages()),
  849 + depth_qpdf_inner);
  850 + JSON::writeDictionaryItem(
  851 + p,
  852 + first_qpdf_inner,
  853 + "calledgetallpages",
  854 + JSON::makeBool(everCalledGetAllPages()),
  855 + depth_qpdf_inner);
789 856 JSON::writeDictionaryItem(
790 857 p,
791   - first_qpdf,
  858 + first_qpdf_inner,
792 859 "maxobjectid",
793 860 JSON::makeInt(QIntC::to_longlong(getObjectCount())),
794   - 2);
795   - JSON::writeDictionaryKey(p, first_qpdf, "objects", 2);
796   - bool first_object = true;
797   - JSON::writeDictionaryOpen(p, first_object, 2);
  861 + depth_qpdf_inner);
  862 + JSON::writeDictionaryClose(p, first_qpdf_inner, depth_qpdf);
  863 + JSON::writeNext(p, first_qpdf, depth_qpdf);
  864 + JSON::writeDictionaryOpen(p, first_qpdf_inner, depth_qpdf);
798 865 bool all_objects = wanted_objects.empty();
799 866 for (auto& obj: getAllObjects()) {
800 867 std::string key = "obj:" + obj.unparse();
... ... @@ -803,23 +870,23 @@ QPDF::writeJSON(
803 870 writeJSONStream(
804 871 version,
805 872 p,
806   - first_object,
  873 + first_qpdf_inner,
807 874 key,
808 875 obj,
809 876 decode_level,
810 877 json_stream_data,
811 878 file_prefix);
812 879 } else {
813   - writeJSONObject(version, p, first_object, key, obj);
  880 + writeJSONObject(version, p, first_qpdf_inner, key, obj);
814 881 }
815 882 }
816 883 }
817 884 if (all_objects || wanted_objects.count("trailer")) {
818 885 auto trailer = getTrailer();
819   - writeJSONObject(version, p, first_object, "trailer", trailer);
  886 + writeJSONObject(version, p, first_qpdf_inner, "trailer", trailer);
820 887 }
821   - JSON::writeDictionaryClose(p, first_object, 2);
822   - JSON::writeDictionaryClose(p, first_qpdf, 1);
  888 + JSON::writeDictionaryClose(p, first_qpdf_inner, depth_qpdf);
  889 + JSON::writeArrayClose(p, first_qpdf, depth_top);
823 890 if (complete) {
824 891 JSON::writeDictionaryClose(p, first, 0);
825 892 *p << "\n";
... ...
manual/json.rst
... ... @@ -256,17 +256,34 @@ qpdf JSON Output
256 256  
257 257 The format of the JSON written by qpdf's :qpdf:ref:`--json-output`
258 258 flag or the ``QPDF::writeJSON`` API call is a JSON object consisting
259   -of a single key: ``"qpdf-v2"``. Any other top-level keys are ignored.
260   -While unknown keys in other places are ignored for future
261   -compatibility, in this case, ignoring other top-level keys is an
262   -explicit decision to allow users to include other keys for their own
263   -use. No new top-level keys will be added in JSON version 2.
  259 +of a single key: ``"qpdf"``. This may be the only key, or it may be
  260 +embedded in the output of ``qpdf --json``. Unknown keys are ignored
  261 +for future compatibility. It is guaranteed that qpdf will never add
  262 +any keys whose names start with ``xdata``, so users are free to add
  263 +their own metadata using keys whose names start with ``xdata`` without
  264 +fear of clashing with a future version of qpdf.
264 265  
265   -The ``"qpdf-v2"`` key points to a JSON object with the following keys:
  266 +The ``"qpdf"`` key points to a two-element JSON array. The first element is
  267 +a JSON object with the following keys:
  268 +
  269 +- ``"jsonversion"`` -- a number indicating the JSON version used for
  270 + writing. This will always be ``2``.
266 271  
267 272 - ``"pdfversion"`` -- a string containing PDF version as indicated in
268 273 the PDF header (e.g. ``"1.7"``, ``"2.0"``)
269 274  
  275 +- ``pushedinheritedpageresources`` -- a boolean indicating whether
  276 + the library pushed inherited resources down to the page level.
  277 + Certain library calls cause this to happen, and qpdf needs to know
  278 + when reading a JSON file back in whether it should do this as it may
  279 + cause certain objects to be renumbered.
  280 +
  281 +- ``calledgetallpages`` -- a boolean indicating whether
  282 + ``getAllPages`` was called prior to writing the JSON output. This
  283 + method causes page tree repair to occur, which may renumber some
  284 + objects (in very rare cases of corrupted page trees), so qpdf needs
  285 + to know this information when reading a JSON file back in.
  286 +
270 287 - ``"maxobjectid"`` -- a number indicating the object ID of the
271 288 highest numbered object in the file. This is provided to make it
272 289 easier for software that wants to add new objects to the file as you
... ... @@ -280,8 +297,8 @@ The ``&quot;qpdf-v2&quot;`` key points to a JSON object with the following keys:
280 297 dangling references and says to treat them as nulls. This can happen
281 298 if objects are removed from a PDF file.)
282 299  
283   -- ``"objects"`` -- the actual PDF objects as described in
284   - :ref:`json.objects`.
  300 +The second element is a JSON object containing the actual PDF objects
  301 +as described in :ref:`json.objects`.
285 302  
286 303 Note that writing JSON output is done by ``QPDF``, not ``QPDFWriter``.
287 304 As such, none of the things ``QPDFWriter`` does apply. This includes
... ... @@ -302,10 +319,15 @@ qpdf JSON format.
302 319 .. code-block:: json
303 320  
304 321 {
305   - "qpdf-v2": {
306   - "pdfversion": "1.3",
307   - "maxobjectid": 5,
308   - "objects": {
  322 + "qpdf": [
  323 + {
  324 + "jsonversion": 2,
  325 + "pdfversion": "1.3",
  326 + "pushedinheritedpageresources": false,
  327 + "calledgetallpages": false,
  328 + "maxobjectid": 5,
  329 + },
  330 + {
309 331 "obj:1 0 R": {
310 332 "value": {
311 333 "/Pages": "2 0 R",
... ... @@ -359,7 +381,7 @@ qpdf JSON format.
359 381 }
360 382 }
361 383 }
362   - }
  384 + ]
363 385 }
364 386  
365 387 .. _json.input:
... ...
qpdf/qpdf.testcov
... ... @@ -668,3 +668,7 @@ QPDF_json non-trivial null reserved 0
668 668 QPDF_json data and datafile 0
669 669 QPDF_json no stream data in update mode 0
670 670 QPDF_json updating existing stream 0
  671 +QPDF_json qpdf not array 0
  672 +QPDF_json more than two qpdf elements 0
  673 +QPDF_json missing json version 0
  674 +QPDF_json bad json version 0
... ...
qpdf/qtest/qpdf-json.test
... ... @@ -18,6 +18,8 @@ my $n_tests = 0;
18 18  
19 19 my @badfiles = (
20 20 'no-qpdf-object',
  21 + 'qpdf-not-array',
  22 + 'qpdf-array-too-long',
21 23 'no-pdf-version',
22 24 'top-level-scalar',
23 25 'bad-pdf-version1',
... ...
qpdf/qtest/qpdf/exp-large-json.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 604,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 604
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -8444,5 +8449,5 @@
8444 8449 }
8445 8450 }
8446 8451 }
8447   - }
  8452 + ]
8448 8453 }
... ...
qpdf/qtest/qpdf/json-bad-data-json-file-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -71,5 +76,5 @@
71 76 }
72 77 }
73 78 }
74   - }
  79 + ]
75 80 }
... ...
qpdf/qtest/qpdf/json-bad-data-json-inline-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -71,5 +76,5 @@
71 76 }
72 77 }
73 78 }
74   - }
  79 + ]
75 80 }
... ...
qpdf/qtest/qpdf/json-image-streams-all-file-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:12 0 R": {
7 12 "stream": {
8 13 "datafile": "auto-12",
... ... @@ -36,5 +41,5 @@
36 41 }
37 42 }
38 43 }
39   - }
  44 + ]
40 45 }
... ...
qpdf/qtest/qpdf/json-image-streams-generalized-file-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:12 0 R": {
7 12 "stream": {
8 13 "datafile": "auto-12",
... ... @@ -38,5 +43,5 @@
38 43 }
39 44 }
40 45 }
41   - }
  46 + ]
42 47 }
... ...
qpdf/qtest/qpdf/json-image-streams-generalized-inline-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -457,5 +462,5 @@
457 462 }
458 463 }
459 464 }
460   - }
  465 + ]
461 466 }
... ...
qpdf/qtest/qpdf/json-image-streams-none-file-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:12 0 R": {
7 12 "stream": {
8 13 "datafile": "auto-12",
... ... @@ -40,5 +45,5 @@
40 45 }
41 46 }
42 47 }
43   - }
  48 + ]
44 49 }
... ...
qpdf/qtest/qpdf/json-image-streams-none-inline-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -478,5 +483,5 @@
478 483 }
479 484 }
480 485 }
481   - }
  486 + ]
482 487 }
... ...
qpdf/qtest/qpdf/json-image-streams-specialized-file-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:12 0 R": {
7 12 "stream": {
8 13 "datafile": "auto-12",
... ... @@ -37,5 +42,5 @@
37 42 }
38 43 }
39 44 }
40   - }
  45 + ]
41 46 }
... ...
qpdf/qtest/qpdf/json-image-streams-specialized-inline-v2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 30,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 30
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -454,5 +459,5 @@
454 459 }
455 460 }
456 461 }
457   - }
  462 + ]
458 463 }
... ...
qpdf/qtest/qpdf/manual-qpdf-json-out.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 100,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 100
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -139,5 +144,5 @@
139 144 }
140 145 }
141 146 }
142   - }
  147 + ]
143 148 }
... ...
qpdf/qtest/qpdf/manual-qpdf-json-pdf.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 10,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 10
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "3 0 R",
... ... @@ -146,5 +151,5 @@
146 151 }
147 152 }
148 153 }
149   - }
  154 + ]
150 155 }
... ...
qpdf/qtest/qpdf/manual-qpdf-json.json
... ... @@ -2,17 +2,20 @@
2 2 "comment": [
3 3 "We allow and ignore other top-level keys"
4 4 ],
5   - "qpdf-v2": {
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   - ]
  5 + "qpdf": [
  6 + {
  7 + "jsonversion": 2,
  8 + "pdfversion": "2.0",
  9 + "maybe-future-key": {
  10 + "x": [
  11 + "Lots of times we ignore things",
  12 + "for forward-compatibility so we don't have",
  13 + "to change the version number if we add stuff",
  14 + "in the future"
  15 + ]
  16 + }
14 17 },
15   - "objects": {
  18 + {
16 19 "obj:3 0 R": {
17 20 "value": {
18 21 "/Contents": "4 0 R",
... ... @@ -141,5 +144,5 @@
141 144 }
142 145 }
143 146 }
144   - }
  147 + ]
145 148 }
... ...
qpdf/qtest/qpdf/minimal-json-file-2.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -65,5 +70,5 @@
65 70 }
66 71 }
67 72 }
68   - }
  73 + ]
69 74 }
... ...
qpdf/qtest/qpdf/minimal-json-file.out
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "pushedinheritedpageresources": false,
  7 + "calledgetallpages": false,
  8 + "maxobjectid": 6
  9 + },
  10 + {
6 11 "obj:1 0 R": {
7 12 "value": {
8 13 "/Pages": "2 0 R",
... ... @@ -65,5 +70,5 @@
65 70 }
66 71 }
67 72 }
68   - }
  73 + ]
69 74 }
... ...
qpdf/qtest/qpdf/qjson-bad-data.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -64,5 +67,5 @@
64 67 }
65 68 }
66 69 }
67   - }
  70 + ]
68 71 }
... ...
qpdf/qtest/qpdf/qjson-bad-datafile.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -64,5 +67,5 @@
64 67 }
65 68 }
66 69 }
67   - }
  70 + ]
68 71 }
... ...
qpdf/qtest/qpdf/qjson-bad-object-key.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "potato": {
7 10 },
8 11 "obj:1 0 R": {
... ... @@ -66,5 +69,5 @@
66 69 }
67 70 }
68 71 }
69   - }
  72 + ]
70 73 }
... ...
qpdf/qtest/qpdf/qjson-bad-object-key.out
1   -WARNING: qjson-bad-object-key.json (offset 97): object key should be "trailer" or "obj:n n R"
  1 +WARNING: qjson-bad-object-key.json (offset 123): object key should be "trailer" or "obj:n n R"
2 2 qpdf: qjson-bad-object-key.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-bad-pdf-version1.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "potato",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": "quack",
  5 + "pdfversion": "potato",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -64,5 +67,5 @@
64 67 }
65 68 }
66 69 }
67   - }
  70 + ]
68 71 }
... ...
qpdf/qtest/qpdf/qjson-bad-pdf-version1.out
1   -WARNING: qjson-bad-pdf-version1.json (offset 35): invalid PDF version (must be x.y)
  1 +WARNING: qjson-bad-pdf-version1.json (offset 41): invalid JSON version (must be 2)
  2 +WARNING: qjson-bad-pdf-version1.json (offset 70): invalid PDF version (must be x.y)
2 3 qpdf: qjson-bad-pdf-version1.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-bad-pdf-version2.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": [],
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 850,
  5 + "pdfversion": [],
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -64,5 +67,5 @@
64 67 }
65 68 }
66 69 }
67   - }
  70 + ]
68 71 }
... ...
qpdf/qtest/qpdf/qjson-bad-pdf-version2.out
1   -WARNING: qjson-bad-pdf-version2.json (offset 35): invalid PDF version (must be x.y)
  1 +WARNING: qjson-bad-pdf-version2.json (offset 41): invalid JSON version (must be 2)
  2 +WARNING: qjson-bad-pdf-version2.json (offset 66): invalid PDF version (must be x.y)
2 3 qpdf: qjson-bad-pdf-version2.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-missing-objects.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6
5   - }
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + }
  8 + ]
6 9 }
... ...
qpdf/qtest/qpdf/qjson-missing-objects.out
1   -WARNING: qjson-missing-objects.json: "qpdf-v2.objects" was not seen
  1 +WARNING: qjson-missing-objects.json: "qpdf[1]" was not seen
2 2 qpdf: qjson-missing-objects.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-missing-trailer.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -58,5 +61,5 @@
58 61 }
59 62 }
60 63 }
61   - }
  64 + ]
62 65 }
... ...
qpdf/qtest/qpdf/qjson-missing-trailer.out
1   -WARNING: qjson-missing-trailer.json: "qpdf-v2.objects.trailer" was not seen
  1 +WARNING: qjson-missing-trailer.json: "qpdf[1].trailer" was not seen
2 2 qpdf: qjson-missing-trailer.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-no-pdf-version.json
1 1 {
2   - "qpdf-v2": {
3   - "maxobjectid": 6,
4   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "maxobjectid": 6
  5 + },
  6 + {
5 7 "obj:1 0 R": {
6 8 "value": {
7 9 "/Pages": "2 0 R",
... ... @@ -63,5 +65,5 @@
63 65 }
64 66 }
65 67 }
66   - }
  68 + ]
67 69 }
... ...
qpdf/qtest/qpdf/qjson-no-pdf-version.out
1   -WARNING: qjson-no-pdf-version.json: "qpdf-v2.pdfversion" was not seen
  1 +WARNING: qjson-no-pdf-version.json: "qpdf[0].jsonversion" was not seen
  2 +WARNING: qjson-no-pdf-version.json: "qpdf[0].pdfversion" was not seen
2 3 qpdf: qjson-no-pdf-version.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-obj-key-errors.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -55,5 +58,5 @@
55 58 }
56 59 }
57 60 }
58   - }
  61 + ]
59 62 }
... ...
qpdf/qtest/qpdf/qjson-obj-key-errors.out
1   -WARNING: qjson-obj-key-errors.json (obj:2 0 R, offset 218): object must have exactly one of "value" or "stream"
2   -WARNING: qjson-obj-key-errors.json (obj:3 0 R, offset 516): object must have exactly one of "value" or "stream"
3   -WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 684): "stream" is missing "dict"
4   -WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 684): new "stream" must have exactly one of "data" or "datafile"
5   -WARNING: qjson-obj-key-errors.json (obj:5 0 R, offset 774): new "stream" must have exactly one of "data" or "datafile"
6   -WARNING: qjson-obj-key-errors.json (trailer, offset 1152): "trailer" is missing "value"
  1 +WARNING: qjson-obj-key-errors.json (obj:2 0 R, offset 244): object must have exactly one of "value" or "stream"
  2 +WARNING: qjson-obj-key-errors.json (obj:3 0 R, offset 542): object must have exactly one of "value" or "stream"
  3 +WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 710): "stream" is missing "dict"
  4 +WARNING: qjson-obj-key-errors.json (obj:4 0 R, offset 710): new "stream" must have exactly one of "data" or "datafile"
  5 +WARNING: qjson-obj-key-errors.json (obj:5 0 R, offset 800): new "stream" must have exactly one of "data" or "datafile"
  6 +WARNING: qjson-obj-key-errors.json (trailer, offset 1178): "trailer" is missing "value"
7 7 qpdf: qjson-obj-key-errors.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-object-not-dict.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": "potato",
7 10 "obj:2 0 R": {
8 11 "value": {
... ... @@ -59,5 +62,5 @@
59 62 }
60 63 }
61 64 }
62   - }
  65 + ]
63 66 }
... ...
qpdf/qtest/qpdf/qjson-object-not-dict.out
1   -WARNING: qjson-object-not-dict.json (obj:1 0 R, offset 100): "obj:1 0 R" must be a dictionary
  1 +WARNING: qjson-object-not-dict.json (obj:1 0 R, offset 126): "obj:1 0 R" must be a dictionary
2 2 qpdf: qjson-object-not-dict.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-objects-not-dict.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.7",
4   - "objects": false
5   - }
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.7"
  6 + },
  7 + false
  8 + ]
6 9 }
... ...
qpdf/qtest/qpdf/qjson-objects-not-dict.out
1   -WARNING: qjson-objects-not-dict.json (offset 58): "objects" must be a dictionary
2   -WARNING: qjson-objects-not-dict.json: "qpdf-v2.objects.trailer" was not seen
  1 +WARNING: qjson-objects-not-dict.json (offset 82): "qpdf[1]" must be a dictionary
  2 +WARNING: qjson-objects-not-dict.json: "qpdf[1].trailer" was not seen
3 3 qpdf: qjson-objects-not-dict.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-qpdf-array-too-long.json 0 โ†’ 100644
  1 +{
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
  9 + "obj:1 0 R": {
  10 + "value": {
  11 + "/Pages": "2 0 R",
  12 + "/Type": "/Catalog"
  13 + }
  14 + },
  15 + "obj:2 0 R": {
  16 + "value": {
  17 + "/Count": 1,
  18 + "/Kids": [
  19 + "3 0 R"
  20 + ],
  21 + "/Type": "/Pages"
  22 + }
  23 + },
  24 + "obj:3 0 R": {
  25 + "value": {
  26 + "/Contents": "4 0 R",
  27 + "/MediaBox": [
  28 + 0,
  29 + 0,
  30 + 612,
  31 + 792
  32 + ],
  33 + "/Parent": "2 0 R",
  34 + "/Resources": {
  35 + "/Font": {
  36 + "/F1": "6 0 R"
  37 + },
  38 + "/ProcSet": "5 0 R"
  39 + },
  40 + "/Type": "/Page"
  41 + }
  42 + },
  43 + "obj:4 0 R": {
  44 + "stream": {
  45 + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=",
  46 + "dict": {}
  47 + }
  48 + },
  49 + "obj:5 0 R": {
  50 + "value": [
  51 + "/PDF",
  52 + "/Text"
  53 + ]
  54 + },
  55 + "obj:6 0 R": {
  56 + "value": {
  57 + "/BaseFont": "/Helvetica",
  58 + "/Encoding": "/WinAnsiEncoding",
  59 + "/Subtype": "/Type1",
  60 + "/Type": "/Font"
  61 + }
  62 + },
  63 + "trailer": {
  64 + "value": {
  65 + "/Root": "1 0 R",
  66 + "/Size": 7
  67 + }
  68 + }
  69 + },
  70 + "this doesn't belong here"
  71 + ]
  72 +}
... ...
qpdf/qtest/qpdf/qjson-qpdf-array-too-long.out 0 โ†’ 100644
  1 +WARNING: qjson-qpdf-array-too-long.json (offset 1348): "qpdf" must have two elements
  2 +qpdf: qjson-qpdf-array-too-long.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-qpdf-not-array.json 0 โ†’ 100644
  1 +{
  2 + "qpdf": {
  3 + "potato": "salad"
  4 + }
  5 +}
... ...
qpdf/qtest/qpdf/qjson-qpdf-not-array.out 0 โ†’ 100644
  1 +WARNING: qjson-qpdf-not-array.json (offset 12): "qpdf" must be an array
  2 +WARNING: qjson-qpdf-not-array.json: "qpdf[0].jsonversion" was not seen
  3 +WARNING: qjson-qpdf-not-array.json: "qpdf[0].pdfversion" was not seen
  4 +WARNING: qjson-qpdf-not-array.json: "qpdf[1]" was not seen
  5 +qpdf: qjson-qpdf-not-array.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-stream-dict-not-dict.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.7",
4   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.7"
  6 + },
  7 + {
5 8 "obj:1 0 R": {
6 9 "stream": {
7 10 "dict": "quack"
8 11 }
9 12 }
10 13 }
11   - }
  14 + ]
12 15 }
... ...
qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
1   -WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 118): "stream.dict" must be a dictionary
2   -WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 118): unrecognized string value
3   -WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 98): new "stream" must have exactly one of "data" or "datafile"
4   -WARNING: qjson-stream-dict-not-dict.json: "qpdf-v2.objects.trailer" was not seen
  1 +WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 142): "stream.dict" must be a dictionary
  2 +WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 142): unrecognized string value
  3 +WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 122): new "stream" must have exactly one of "data" or "datafile"
  4 +WARNING: qjson-stream-dict-not-dict.json: "qpdf[1].trailer" was not seen
5 5 qpdf: qjson-stream-dict-not-dict.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-stream-not-dict.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.7",
4   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.7"
  6 + },
  7 + {
5 8 "obj:1 0 R": {
6 9 "stream": 3
7 10 }
8 11 }
9   - }
  12 + ]
10 13 }
... ...
qpdf/qtest/qpdf/qjson-stream-not-dict.out
1   -WARNING: qjson-stream-not-dict.json (obj:1 0 R, offset 99): "stream" must be a dictionary
2   -WARNING: qjson-stream-not-dict.json: "qpdf-v2.objects.trailer" was not seen
  1 +WARNING: qjson-stream-not-dict.json (obj:1 0 R, offset 123): "stream" must be a dictionary
  2 +WARNING: qjson-stream-not-dict.json: "qpdf[1].trailer" was not seen
3 3 qpdf: qjson-stream-not-dict.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-trailer-not-dict.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -61,5 +64,5 @@
61 64 "value": false
62 65 }
63 66 }
64   - }
  67 + ]
65 68 }
... ...
qpdf/qtest/qpdf/qjson-trailer-not-dict.out
1   -WARNING: qjson-trailer-not-dict.json (trailer, offset 1243): "trailer.value" must be a dictionary
  1 +WARNING: qjson-trailer-not-dict.json (trailer, offset 1269): "trailer.value" must be a dictionary
2 2 qpdf: qjson-trailer-not-dict.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qjson-trailer-stream.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "1.3",
4   - "maxobjectid": 6,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "1.3",
  6 + "maxobjectid": 6
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -61,5 +64,5 @@
61 64 "stream": {}
62 65 }
63 66 }
64   - }
  67 + ]
65 68 }
... ...
qpdf/qtest/qpdf/qjson-trailer-stream.out
1   -WARNING: qjson-trailer-stream.json (trailer, offset 1243): the trailer may not be a stream
  1 +WARNING: qjson-trailer-stream.json (trailer, offset 1269): the trailer may not be a stream
2 2 qpdf: qjson-trailer-stream.json: errors found in JSON
... ...
qpdf/qtest/qpdf/qpdf-json-update-errors.json
1 1 {
2   - "qpdf-v2": {
3   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2
  5 + },
  6 + {
4 7 "obj:4 0 R": {
5 8 "stream": {
6 9 "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=",
... ... @@ -16,5 +19,5 @@
16 19 }
17 20 }
18 21 }
19   - }
  22 + ]
20 23 }
... ...
qpdf/qtest/qpdf/replace-with-stream.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 9,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "maxobjectid": 9
  7 + },
  8 + {
6 9 "obj:8 0 R": {
7 10 "stream": {
8 11 "data": "bmV3LXN0cmVhbS1oZXJlCg==",
... ... @@ -12,5 +15,5 @@
12 15 }
13 16 }
14 17 }
15   - }
  18 + ]
16 19 }
... ...
qpdf/qtest/qpdf/test-89.out
1   -WARNING: manual-qpdf-json.json, trailer at offset 1761: operation for array attempted on object of type dictionary: ignoring attempt to append item
2   -WARNING: manual-qpdf-json.json, obj:1 0 R at offset 1079: operation for array attempted on object of type dictionary: ignoring attempt to append item
3   -WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1404: operation for dictionary attempted on object of type array: ignoring key replacement request
4   -WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1416: operation for dictionary attempted on object of type name: ignoring key replacement request
  1 +WARNING: manual-qpdf-json.json, trailer at offset 1801: operation for array attempted on object of type dictionary: ignoring attempt to append item
  2 +WARNING: manual-qpdf-json.json, obj:1 0 R at offset 1119: operation for array attempted on object of type dictionary: ignoring attempt to append item
  3 +WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1444: operation for dictionary attempted on object of type array: ignoring key replacement request
  4 +WARNING: manual-qpdf-json.json, obj:5 0 R at offset 1456: operation for dictionary attempted on object of type name: ignoring key replacement request
5 5 test 89 done
... ...
qpdf/qtest/qpdf/test-90.out
1   -WARNING: various-updates.json, trailer at offset 580: operation for array attempted on object of type dictionary: ignoring attempt to append item
2   -WARNING: various-updates.json, obj:7 0 R at offset 171: operation for array attempted on object of type dictionary: ignoring attempt to append item
3   -WARNING: various-updates.json, obj:7 0 R at offset 283: operation for integer attempted on object of type array: returning 0
  1 +WARNING: various-updates.json, trailer at offset 606: operation for array attempted on object of type dictionary: ignoring attempt to append item
  2 +WARNING: various-updates.json, obj:7 0 R at offset 197: operation for array attempted on object of type dictionary: ignoring attempt to append item
  3 +WARNING: various-updates.json, obj:7 0 R at offset 309: operation for integer attempted on object of type array: returning 0
4 4 WARNING: good13.pdf, object 1 0 at offset 19: operation for array attempted on object of type dictionary: ignoring attempt to append item
5 5 test 90 done
... ...
qpdf/qtest/qpdf/update-from-json-errors.out
1   -WARNING: good13.pdf (obj:4 0 R from qpdf-json-update-errors.json, offset 73): existing "stream" may at most one of "data" or "datafile"
2   -WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 313): unrecognized string value
3   -WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 271): new "stream" must have exactly one of "data" or "datafile"
  1 +WARNING: good13.pdf (obj:4 0 R from qpdf-json-update-errors.json, offset 95): existing "stream" may at most one of "data" or "datafile"
  2 +WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 335): unrecognized string value
  3 +WARNING: good13.pdf (obj:20 0 R from qpdf-json-update-errors.json, offset 293): new "stream" must have exactly one of "data" or "datafile"
4 4 qpdf: qpdf-json-update-errors.json: errors found in JSON
... ...
qpdf/qtest/qpdf/update-stream-data.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 9,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "maxobjectid": 9
  7 + },
  8 + {
6 9 "obj:1 0 R": {
7 10 "value": {
8 11 "/Pages": "2 0 R",
... ... @@ -16,5 +19,5 @@
16 19 }
17 20 }
18 21 }
19   - }
  22 + ]
20 23 }
... ...
qpdf/qtest/qpdf/update-stream-dict-only.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 9,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "maxobjectid": 9
  7 + },
  8 + {
6 9 "obj:4 0 R": {
7 10 "stream": {
8 11 "dict": {
... ... @@ -11,5 +14,5 @@
11 14 }
12 15 }
13 16 }
14   - }
  17 + ]
15 18 }
... ...
qpdf/qtest/qpdf/various-updates.json
1 1 {
2   - "qpdf-v2": {
3   - "pdfversion": "2.0",
4   - "maxobjectid": 9,
5   - "objects": {
  2 + "qpdf": [
  3 + {
  4 + "jsonversion": 2,
  5 + "pdfversion": "2.0",
  6 + "maxobjectid": 9
  7 + },
  8 + {
6 9 "obj:5 0 R": {
7 10 "value": null
8 11 },
... ... @@ -35,5 +38,5 @@
35 38 }
36 39 }
37 40 }
38   - }
  41 + ]
39 42 }
... ...