Commit 7fa5d1773b599df51df21658dff53f5b66fdbba8
1 parent
8d42eb26
Implement top-level qpdf json parsing
Showing
37 changed files
with
1053 additions
and
8 deletions
TODO
| ... | ... | @@ -54,6 +54,13 @@ Soon: Break ground on "Document-level work" |
| 54 | 54 | Output JSON v2 |
| 55 | 55 | ============== |
| 56 | 56 | |
| 57 | +Try to never flatten pages tree. Make sure we do something reasonable | |
| 58 | +with pages tree repair. The problem is that if pages tree repair is | |
| 59 | +done as a side effect of running --json, the qpdf part of the json may | |
| 60 | +contain object numbers that aren't there. Maybe we need to indicate | |
| 61 | +whether pages tree repair has been done in the json, but this would | |
| 62 | +have to be known early in parsing, which is a problem. | |
| 63 | + | |
| 57 | 64 | General things to remember: |
| 58 | 65 | |
| 59 | 66 | * Make sure all the information from --check and other informational | ... | ... |
include/qpdf/QPDF.hh
| ... | ... | @@ -998,6 +998,7 @@ class QPDF |
| 998 | 998 | class JSONReactor: public JSON::Reactor |
| 999 | 999 | { |
| 1000 | 1000 | public: |
| 1001 | + JSONReactor(QPDF&, bool must_be_complete); | |
| 1001 | 1002 | virtual ~JSONReactor() = default; |
| 1002 | 1003 | virtual void dictionaryStart() override; |
| 1003 | 1004 | virtual void arrayStart() override; |
| ... | ... | @@ -1006,6 +1007,32 @@ class QPDF |
| 1006 | 1007 | virtual bool |
| 1007 | 1008 | dictionaryItem(std::string const& key, JSON const& value) override; |
| 1008 | 1009 | virtual bool arrayItem(JSON const& value) override; |
| 1010 | + | |
| 1011 | + private: | |
| 1012 | + enum state_e { | |
| 1013 | + st_initial, | |
| 1014 | + st_top, | |
| 1015 | + st_ignore, | |
| 1016 | + st_qpdf, | |
| 1017 | + st_objects_top, | |
| 1018 | + st_trailer_top, | |
| 1019 | + st_object_top, | |
| 1020 | + st_stream, | |
| 1021 | + st_object, | |
| 1022 | + }; | |
| 1023 | + | |
| 1024 | + void containerStart(); | |
| 1025 | + void nestedState(std::string const& key, JSON const& value, state_e); | |
| 1026 | + | |
| 1027 | + QPDF& pdf; | |
| 1028 | + bool must_be_complete; | |
| 1029 | + bool saw_qpdf; | |
| 1030 | + bool saw_json_version; | |
| 1031 | + bool saw_pdf_version; | |
| 1032 | + bool saw_trailer; | |
| 1033 | + state_e state; | |
| 1034 | + state_e next_state; | |
| 1035 | + std::vector<state_e> state_stack; | |
| 1009 | 1036 | }; |
| 1010 | 1037 | friend class JSONReactor; |
| 1011 | 1038 | ... | ... |
libqpdf/QPDF_json.cc
| 1 | 1 | #include <qpdf/QPDF.hh> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/FileInputSource.hh> |
| 4 | +#include <qpdf/QTC.hh> | |
| 5 | +#include <qpdf/QUtil.hh> | |
| 6 | +#include <regex> | |
| 7 | + | |
| 8 | +namespace | |
| 9 | +{ | |
| 10 | + class JSONExc: public std::runtime_error | |
| 11 | + { | |
| 12 | + public: | |
| 13 | + JSONExc(JSON const& value, std::string const& msg) : | |
| 14 | + std::runtime_error( | |
| 15 | + "offset " + QUtil::uint_to_string(value.getStart()) + ": " + | |
| 16 | + msg) | |
| 17 | + { | |
| 18 | + } | |
| 19 | + }; | |
| 20 | +} // namespace | |
| 21 | + | |
| 22 | +static std::regex PDF_VERSION_RE("^\\d+\\.\\d+$"); | |
| 23 | +static std::regex OBJ_KEY_RE("^obj:(\\d+) (\\d+) R$"); | |
| 24 | + | |
| 25 | +QPDF::JSONReactor::JSONReactor(QPDF& pdf, bool must_be_complete) : | |
| 26 | + pdf(pdf), | |
| 27 | + must_be_complete(must_be_complete), | |
| 28 | + saw_qpdf(false), | |
| 29 | + saw_json_version(false), | |
| 30 | + saw_pdf_version(false), | |
| 31 | + saw_trailer(false), | |
| 32 | + state(st_initial), | |
| 33 | + next_state(st_top) | |
| 34 | +{ | |
| 35 | + state_stack.push_back(st_initial); | |
| 36 | +} | |
| 37 | + | |
| 38 | +void | |
| 39 | +QPDF::JSONReactor::containerStart() | |
| 40 | +{ | |
| 41 | + state_stack.push_back(state); | |
| 42 | + state = next_state; | |
| 43 | +} | |
| 4 | 44 | |
| 5 | 45 | void |
| 6 | 46 | QPDF::JSONReactor::dictionaryStart() |
| 7 | 47 | { |
| 8 | - // QXXXXQ | |
| 48 | + containerStart(); | |
| 49 | + // QXXXQ | |
| 9 | 50 | } |
| 10 | 51 | |
| 11 | 52 | void |
| 12 | 53 | QPDF::JSONReactor::arrayStart() |
| 13 | 54 | { |
| 14 | - // QXXXXQ | |
| 55 | + containerStart(); | |
| 56 | + if (state == st_top) { | |
| 57 | + QTC::TC("qpdf", "QPDF_json top-level array"); | |
| 58 | + throw std::runtime_error("QPDF JSON must be a dictionary"); | |
| 59 | + } | |
| 60 | + // QXXXQ | |
| 15 | 61 | } |
| 16 | 62 | |
| 17 | 63 | void |
| 18 | 64 | QPDF::JSONReactor::containerEnd(JSON const& value) |
| 19 | 65 | { |
| 20 | - // QXXXXQ | |
| 66 | + state = state_stack.back(); | |
| 67 | + state_stack.pop_back(); | |
| 68 | + if (state == st_initial) { | |
| 69 | + if (!this->saw_qpdf) { | |
| 70 | + QTC::TC("qpdf", "QPDF_json missing qpdf"); | |
| 71 | + throw std::runtime_error("\"qpdf\" object was not seen"); | |
| 72 | + } | |
| 73 | + if (!this->saw_json_version) { | |
| 74 | + QTC::TC("qpdf", "QPDF_json missing json version"); | |
| 75 | + throw std::runtime_error("\"qpdf.jsonversion\" was not seen"); | |
| 76 | + } | |
| 77 | + if (must_be_complete && !this->saw_pdf_version) { | |
| 78 | + QTC::TC("qpdf", "QPDF_json missing pdf version"); | |
| 79 | + throw std::runtime_error("\"qpdf.pdfversion\" was not seen"); | |
| 80 | + } | |
| 81 | + if (must_be_complete && !this->saw_trailer) { | |
| 82 | + /// QTC::TC("qpdf", "QPDF_json missing trailer"); | |
| 83 | + throw std::runtime_error("\"qpdf.objects.trailer\" was not seen"); | |
| 84 | + } | |
| 85 | + } | |
| 86 | + | |
| 87 | + // QXXXQ | |
| 21 | 88 | } |
| 22 | 89 | |
| 23 | 90 | void |
| 24 | 91 | QPDF::JSONReactor::topLevelScalar() |
| 25 | 92 | { |
| 26 | - // QXXXXQ | |
| 93 | + QTC::TC("qpdf", "QPDF_json top-level scalar"); | |
| 94 | + throw std::runtime_error("QPDF JSON must be a dictionary"); | |
| 95 | +} | |
| 96 | + | |
| 97 | +void | |
| 98 | +QPDF::JSONReactor::nestedState( | |
| 99 | + std::string const& key, JSON const& value, state_e next) | |
| 100 | +{ | |
| 101 | + // Use this method when the next state is for processing a nested | |
| 102 | + // dictionary. | |
| 103 | + if (!value.isDictionary()) { | |
| 104 | + throw JSONExc(value, "\"" + key + "\" must be a dictionary"); | |
| 105 | + } | |
| 106 | + this->next_state = next; | |
| 27 | 107 | } |
| 28 | 108 | |
| 29 | 109 | bool |
| 30 | 110 | QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) |
| 31 | 111 | { |
| 32 | - // QXXXXQ | |
| 112 | + if (state == st_ignore) { | |
| 113 | + // ignore | |
| 114 | + } else if (state == st_top) { | |
| 115 | + if (key == "qpdf") { | |
| 116 | + this->saw_qpdf = true; | |
| 117 | + nestedState(key, value, st_qpdf); | |
| 118 | + } else { | |
| 119 | + // Ignore all other fields for forward compatibility. | |
| 120 | + // Don't use nestedState since this can be any type. | |
| 121 | + next_state = st_ignore; | |
| 122 | + } | |
| 123 | + } else if (state == st_qpdf) { | |
| 124 | + if (key == "jsonversion") { | |
| 125 | + this->saw_json_version = true; | |
| 126 | + std::string v; | |
| 127 | + if (!(value.getNumber(v) && (v == "2"))) { | |
| 128 | + QTC::TC("qpdf", "QPDF_json bad json version"); | |
| 129 | + throw JSONExc(value, "only JSON version 2 is supported"); | |
| 130 | + } | |
| 131 | + } else if (key == "pdfversion") { | |
| 132 | + this->saw_pdf_version = true; | |
| 133 | + bool version_okay = false; | |
| 134 | + std::string v; | |
| 135 | + if (value.getString(v)) { | |
| 136 | + std::smatch m; | |
| 137 | + if (std::regex_match(v, m, PDF_VERSION_RE)) { | |
| 138 | + version_okay = true; | |
| 139 | + this->pdf.m->pdf_version = v; | |
| 140 | + } | |
| 141 | + } | |
| 142 | + if (!version_okay) { | |
| 143 | + QTC::TC("qpdf", "QPDF_json bad pdf version"); | |
| 144 | + throw JSONExc(value, "invalid PDF version (must be x.y)"); | |
| 145 | + } | |
| 146 | + } else if (key == "objects") { | |
| 147 | + nestedState(key, value, st_objects_top); | |
| 148 | + } else { | |
| 149 | + // ignore unknown keys for forward compatibility | |
| 150 | + } | |
| 151 | + } else if (state == st_objects_top) { | |
| 152 | + std::smatch m; | |
| 153 | + if (key == "trailer") { | |
| 154 | + this->saw_trailer = true; | |
| 155 | + nestedState(key, value, st_trailer_top); | |
| 156 | + // QXXXQ | |
| 157 | + } else if (std::regex_match(key, m, OBJ_KEY_RE)) { | |
| 158 | + nestedState(key, value, st_object_top); | |
| 159 | + // QXXXQ | |
| 160 | + } else { | |
| 161 | + QTC::TC("qpdf", "QPDF_json bad object key"); | |
| 162 | + throw JSONExc( | |
| 163 | + value, "object key should be \"trailer\" or \"obj:n n R\""); | |
| 164 | + } | |
| 165 | + } else if (state == st_object_top) { | |
| 166 | + if (key == "value") { | |
| 167 | + // Don't use nestedState since this can have any type. | |
| 168 | + next_state = st_object; | |
| 169 | + // QXXXQ | |
| 170 | + } else if (key == "stream") { | |
| 171 | + nestedState(key, value, st_stream); | |
| 172 | + // QXXXQ | |
| 173 | + } else { | |
| 174 | + // Ignore unknown keys for forward compatibility | |
| 175 | + } | |
| 176 | + } else if (state == st_trailer_top) { | |
| 177 | + if (key == "value") { | |
| 178 | + // The trailer must be a dictionary, so we can use nestedState. | |
| 179 | + nestedState("trailer.value", value, st_object); | |
| 180 | + // QXXXQ | |
| 181 | + } else if (key == "stream") { | |
| 182 | + QTC::TC("qpdf", "QPDF_json trailer stream"); | |
| 183 | + throw JSONExc(value, "the trailer may not be a stream"); | |
| 184 | + } else { | |
| 185 | + // Ignore unknown keys for forward compatibility | |
| 186 | + } | |
| 187 | + } else if (state == st_stream) { | |
| 188 | + if (key == "dict") { | |
| 189 | + // Since a stream dictionary must be a dictionary, we can | |
| 190 | + // use nestedState to transition to st_value. | |
| 191 | + nestedState("stream.dict", value, st_object); | |
| 192 | + // QXXXQ | |
| 193 | + } else if (key == "data") { | |
| 194 | + // QXXXQ | |
| 195 | + } else if (key == "datafile") { | |
| 196 | + // QXXXQ | |
| 197 | + } else { | |
| 198 | + // Ignore unknown keys for forward compatibility. | |
| 199 | + next_state = st_ignore; | |
| 200 | + } | |
| 201 | + } else if (state == st_object) { | |
| 202 | + // QXXXQ | |
| 203 | + } else { | |
| 204 | + throw std::logic_error( | |
| 205 | + "QPDF_json: unknown state " + QUtil::int_to_string(state)); | |
| 206 | + } | |
| 207 | + | |
| 208 | + // QXXXQ | |
| 33 | 209 | return true; |
| 34 | 210 | } |
| 35 | 211 | |
| 36 | 212 | bool |
| 37 | 213 | QPDF::JSONReactor::arrayItem(JSON const& value) |
| 38 | 214 | { |
| 39 | - // QXXXXQ | |
| 215 | + // QXXXQ | |
| 40 | 216 | return true; |
| 41 | 217 | } |
| 42 | 218 | |
| ... | ... | @@ -65,7 +241,12 @@ QPDF::updateFromJSON(std::shared_ptr<InputSource> is) |
| 65 | 241 | } |
| 66 | 242 | |
| 67 | 243 | void |
| 68 | -QPDF::importJSON(std::shared_ptr<InputSource>, bool must_be_complete) | |
| 244 | +QPDF::importJSON(std::shared_ptr<InputSource> is, bool must_be_complete) | |
| 69 | 245 | { |
| 70 | - // QXXXQ | |
| 246 | + JSONReactor reactor(*this, must_be_complete); | |
| 247 | + try { | |
| 248 | + JSON::parse(*is, &reactor); | |
| 249 | + } catch (std::runtime_error& e) { | |
| 250 | + throw std::runtime_error(is->getName() + ": " + e.what()); | |
| 251 | + } | |
| 71 | 252 | } | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -650,3 +650,12 @@ QPDFJob json encrypt duplicate key length 0 |
| 650 | 650 | QPDFJob json encrypt missing password 0 |
| 651 | 651 | QPDFJob json pages no file 0 |
| 652 | 652 | qpdf-c called qpdf_empty_pdf 0 |
| 653 | +QPDF_json missing qpdf 0 | |
| 654 | +QPDF_json missing json version 0 | |
| 655 | +QPDF_json missing pdf version 0 | |
| 656 | +QPDF_json top-level scalar 0 | |
| 657 | +QPDF_json bad json version 0 | |
| 658 | +QPDF_json bad pdf version 0 | |
| 659 | +QPDF_json top-level array 0 | |
| 660 | +QPDF_json bad object key 0 | |
| 661 | +QPDF_json trailer stream 0 | ... | ... |
qpdf/qtest/qpdf-json.test
0 โ 100644
| 1 | +#!/usr/bin/env perl | |
| 2 | +require 5.008; | |
| 3 | +use warnings; | |
| 4 | +use strict; | |
| 5 | + | |
| 6 | +unshift(@INC, '.'); | |
| 7 | +require qpdf_test_helpers; | |
| 8 | + | |
| 9 | +chdir("qpdf") or die "chdir testdir failed: $!\n"; | |
| 10 | + | |
| 11 | +require TestDriver; | |
| 12 | + | |
| 13 | +cleanup(); | |
| 14 | + | |
| 15 | +my $td = new TestDriver('qpdf-json'); | |
| 16 | + | |
| 17 | +my $n_tests = 0; | |
| 18 | + | |
| 19 | +my @badfiles = ( | |
| 20 | + 'no-qpdf-object', | |
| 21 | + 'no-json-version', | |
| 22 | + 'no-pdf-version', | |
| 23 | + 'top-level-scalar', | |
| 24 | + 'bad-json-version1', | |
| 25 | + 'bad-json-version2', | |
| 26 | + 'bad-pdf-version1', | |
| 27 | + 'bad-pdf-version2', | |
| 28 | + 'top-level-array', | |
| 29 | + 'objects-not-dict', | |
| 30 | + 'bad-object-key', | |
| 31 | + 'object-not-dict', | |
| 32 | + 'stream-not-dict', | |
| 33 | + 'stream-dict-not-dict', | |
| 34 | + 'trailer-not-dict', | |
| 35 | + 'trailer-stream', | |
| 36 | + ); | |
| 37 | + | |
| 38 | +$n_tests += scalar(@badfiles); | |
| 39 | + | |
| 40 | +foreach my $f (@badfiles) | |
| 41 | +{ | |
| 42 | + $td->runtest("bad: $f", | |
| 43 | + {$td->COMMAND => | |
| 44 | + "qpdf --create-from-json=qjson-$f.json a.pdf"}, | |
| 45 | + {$td->FILE => "qjson-$f.out", $td->EXIT_STATUS => 2}, | |
| 46 | + $td->NORMALIZE_NEWLINES); | |
| 47 | +} | |
| 48 | + | |
| 49 | +cleanup(); | |
| 50 | +$td->report($n_tests); | ... | ... |
qpdf/qtest/qpdf/qjson-bad-json-version1.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 16059, | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "value": { | |
| 67 | + "/Root": "1 0 R", | |
| 68 | + "/Size": 7 | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-bad-json-version1.out
0 โ 100644
| 1 | +qpdf: qjson-bad-json-version1.json: offset 98: only JSON version 2 is supported | ... | ... |
qpdf/qtest/qpdf/qjson-bad-json-version2.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": "potato", | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "value": { | |
| 67 | + "/Root": "1 0 R", | |
| 68 | + "/Size": 7 | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-bad-json-version2.out
0 โ 100644
| 1 | +qpdf: qjson-bad-json-version2.json: offset 98: only JSON version 2 is supported | ... | ... |
qpdf/qtest/qpdf/qjson-bad-object-key.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "potato": { | |
| 12 | + }, | |
| 13 | + "obj:1 0 R": { | |
| 14 | + "value": { | |
| 15 | + "/Pages": "2 0 R", | |
| 16 | + "/Type": "/Catalog" | |
| 17 | + } | |
| 18 | + }, | |
| 19 | + "obj:2 0 R": { | |
| 20 | + "value": { | |
| 21 | + "/Count": 1, | |
| 22 | + "/Kids": [ | |
| 23 | + "3 0 R" | |
| 24 | + ], | |
| 25 | + "/Type": "/Pages" | |
| 26 | + } | |
| 27 | + }, | |
| 28 | + "obj:3 0 R": { | |
| 29 | + "value": { | |
| 30 | + "/Contents": "4 0 R", | |
| 31 | + "/MediaBox": [ | |
| 32 | + 0, | |
| 33 | + 0, | |
| 34 | + 612, | |
| 35 | + 792 | |
| 36 | + ], | |
| 37 | + "/Parent": "2 0 R", | |
| 38 | + "/Resources": { | |
| 39 | + "/Font": { | |
| 40 | + "/F1": "6 0 R" | |
| 41 | + }, | |
| 42 | + "/ProcSet": "5 0 R" | |
| 43 | + }, | |
| 44 | + "/Type": "/Page" | |
| 45 | + } | |
| 46 | + }, | |
| 47 | + "obj:4 0 R": { | |
| 48 | + "stream": { | |
| 49 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 50 | + "dict": {} | |
| 51 | + } | |
| 52 | + }, | |
| 53 | + "obj:5 0 R": { | |
| 54 | + "value": [ | |
| 55 | + "/PDF", | |
| 56 | + "/Text" | |
| 57 | + ] | |
| 58 | + }, | |
| 59 | + "obj:6 0 R": { | |
| 60 | + "value": { | |
| 61 | + "/BaseFont": "/Helvetica", | |
| 62 | + "/Encoding": "/WinAnsiEncoding", | |
| 63 | + "/Subtype": "/Type1", | |
| 64 | + "/Type": "/Font" | |
| 65 | + } | |
| 66 | + }, | |
| 67 | + "trailer": { | |
| 68 | + "value": { | |
| 69 | + "/Root": "1 0 R", | |
| 70 | + "/Size": 7 | |
| 71 | + } | |
| 72 | + } | |
| 73 | + } | |
| 74 | + } | |
| 75 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-bad-object-key.out
0 โ 100644
| 1 | +qpdf: qjson-bad-object-key.json: offset 181: object key should be "trailer" or "obj:n n R" | ... | ... |
qpdf/qtest/qpdf/qjson-bad-pdf-version1.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": "potato", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "value": { | |
| 67 | + "/Root": "1 0 R", | |
| 68 | + "/Size": 7 | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-bad-pdf-version1.out
0 โ 100644
| 1 | +qpdf: qjson-bad-pdf-version1.json: offset 119: invalid PDF version (must be x.y) | ... | ... |
qpdf/qtest/qpdf/qjson-bad-pdf-version2.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": [], | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "value": { | |
| 67 | + "/Root": "1 0 R", | |
| 68 | + "/Size": 7 | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-bad-pdf-version2.out
0 โ 100644
| 1 | +qpdf: qjson-bad-pdf-version2.json: offset 119: invalid PDF version (must be x.y) | ... | ... |
qpdf/qtest/qpdf/qjson-no-json-version.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "pdfversion": "1.3", | |
| 8 | + "maxobjectid": 6, | |
| 9 | + "objects": { | |
| 10 | + "obj:1 0 R": { | |
| 11 | + "value": { | |
| 12 | + "/Pages": "2 0 R", | |
| 13 | + "/Type": "/Catalog" | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + "obj:2 0 R": { | |
| 17 | + "value": { | |
| 18 | + "/Count": 1, | |
| 19 | + "/Kids": [ | |
| 20 | + "3 0 R" | |
| 21 | + ], | |
| 22 | + "/Type": "/Pages" | |
| 23 | + } | |
| 24 | + }, | |
| 25 | + "obj:3 0 R": { | |
| 26 | + "value": { | |
| 27 | + "/Contents": "4 0 R", | |
| 28 | + "/MediaBox": [ | |
| 29 | + 0, | |
| 30 | + 0, | |
| 31 | + 612, | |
| 32 | + 792 | |
| 33 | + ], | |
| 34 | + "/Parent": "2 0 R", | |
| 35 | + "/Resources": { | |
| 36 | + "/Font": { | |
| 37 | + "/F1": "6 0 R" | |
| 38 | + }, | |
| 39 | + "/ProcSet": "5 0 R" | |
| 40 | + }, | |
| 41 | + "/Type": "/Page" | |
| 42 | + } | |
| 43 | + }, | |
| 44 | + "obj:4 0 R": { | |
| 45 | + "stream": { | |
| 46 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 47 | + "dict": {} | |
| 48 | + } | |
| 49 | + }, | |
| 50 | + "obj:5 0 R": { | |
| 51 | + "value": [ | |
| 52 | + "/PDF", | |
| 53 | + "/Text" | |
| 54 | + ] | |
| 55 | + }, | |
| 56 | + "obj:6 0 R": { | |
| 57 | + "value": { | |
| 58 | + "/BaseFont": "/Helvetica", | |
| 59 | + "/Encoding": "/WinAnsiEncoding", | |
| 60 | + "/Subtype": "/Type1", | |
| 61 | + "/Type": "/Font" | |
| 62 | + } | |
| 63 | + }, | |
| 64 | + "trailer": { | |
| 65 | + "value": { | |
| 66 | + "/Root": "1 0 R", | |
| 67 | + "/Size": 7 | |
| 68 | + } | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-no-json-version.out
0 โ 100644
| 1 | +qpdf: qjson-no-json-version.json: "qpdf.jsonversion" was not seen | ... | ... |
qpdf/qtest/qpdf/qjson-no-pdf-version.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "maxobjectid": 6, | |
| 9 | + "objects": { | |
| 10 | + "obj:1 0 R": { | |
| 11 | + "value": { | |
| 12 | + "/Pages": "2 0 R", | |
| 13 | + "/Type": "/Catalog" | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + "obj:2 0 R": { | |
| 17 | + "value": { | |
| 18 | + "/Count": 1, | |
| 19 | + "/Kids": [ | |
| 20 | + "3 0 R" | |
| 21 | + ], | |
| 22 | + "/Type": "/Pages" | |
| 23 | + } | |
| 24 | + }, | |
| 25 | + "obj:3 0 R": { | |
| 26 | + "value": { | |
| 27 | + "/Contents": "4 0 R", | |
| 28 | + "/MediaBox": [ | |
| 29 | + 0, | |
| 30 | + 0, | |
| 31 | + 612, | |
| 32 | + 792 | |
| 33 | + ], | |
| 34 | + "/Parent": "2 0 R", | |
| 35 | + "/Resources": { | |
| 36 | + "/Font": { | |
| 37 | + "/F1": "6 0 R" | |
| 38 | + }, | |
| 39 | + "/ProcSet": "5 0 R" | |
| 40 | + }, | |
| 41 | + "/Type": "/Page" | |
| 42 | + } | |
| 43 | + }, | |
| 44 | + "obj:4 0 R": { | |
| 45 | + "stream": { | |
| 46 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 47 | + "dict": {} | |
| 48 | + } | |
| 49 | + }, | |
| 50 | + "obj:5 0 R": { | |
| 51 | + "value": [ | |
| 52 | + "/PDF", | |
| 53 | + "/Text" | |
| 54 | + ] | |
| 55 | + }, | |
| 56 | + "obj:6 0 R": { | |
| 57 | + "value": { | |
| 58 | + "/BaseFont": "/Helvetica", | |
| 59 | + "/Encoding": "/WinAnsiEncoding", | |
| 60 | + "/Subtype": "/Type1", | |
| 61 | + "/Type": "/Font" | |
| 62 | + } | |
| 63 | + }, | |
| 64 | + "trailer": { | |
| 65 | + "value": { | |
| 66 | + "/Root": "1 0 R", | |
| 67 | + "/Size": 7 | |
| 68 | + } | |
| 69 | + } | |
| 70 | + } | |
| 71 | + } | |
| 72 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-no-pdf-version.out
0 โ 100644
| 1 | +qpdf: qjson-no-pdf-version.json: "qpdf.pdfversion" was not seen | ... | ... |
qpdf/qtest/qpdf/qjson-no-qpdf-object.json
0 โ 100644
qpdf/qtest/qpdf/qjson-no-qpdf-object.out
0 โ 100644
| 1 | +qpdf: qjson-no-qpdf-object.json: "qpdf" object was not seen | ... | ... |
qpdf/qtest/qpdf/qjson-object-not-dict.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": "potato", | |
| 12 | + "obj:2 0 R": { | |
| 13 | + "value": { | |
| 14 | + "/Count": 1, | |
| 15 | + "/Kids": [ | |
| 16 | + "3 0 R" | |
| 17 | + ], | |
| 18 | + "/Type": "/Pages" | |
| 19 | + } | |
| 20 | + }, | |
| 21 | + "obj:3 0 R": { | |
| 22 | + "value": { | |
| 23 | + "/Contents": "4 0 R", | |
| 24 | + "/MediaBox": [ | |
| 25 | + 0, | |
| 26 | + 0, | |
| 27 | + 612, | |
| 28 | + 792 | |
| 29 | + ], | |
| 30 | + "/Parent": "2 0 R", | |
| 31 | + "/Resources": { | |
| 32 | + "/Font": { | |
| 33 | + "/F1": "6 0 R" | |
| 34 | + }, | |
| 35 | + "/ProcSet": "5 0 R" | |
| 36 | + }, | |
| 37 | + "/Type": "/Page" | |
| 38 | + } | |
| 39 | + }, | |
| 40 | + "obj:4 0 R": { | |
| 41 | + "stream": { | |
| 42 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 43 | + "dict": {} | |
| 44 | + } | |
| 45 | + }, | |
| 46 | + "obj:5 0 R": { | |
| 47 | + "value": [ | |
| 48 | + "/PDF", | |
| 49 | + "/Text" | |
| 50 | + ] | |
| 51 | + }, | |
| 52 | + "obj:6 0 R": { | |
| 53 | + "value": { | |
| 54 | + "/BaseFont": "/Helvetica", | |
| 55 | + "/Encoding": "/WinAnsiEncoding", | |
| 56 | + "/Subtype": "/Type1", | |
| 57 | + "/Type": "/Font" | |
| 58 | + } | |
| 59 | + }, | |
| 60 | + "trailer": { | |
| 61 | + "value": { | |
| 62 | + "/Root": "1 0 R", | |
| 63 | + "/Size": 7 | |
| 64 | + } | |
| 65 | + } | |
| 66 | + } | |
| 67 | + } | |
| 68 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-object-not-dict.out
0 โ 100644
| 1 | +qpdf: qjson-object-not-dict.json: offset 184: "obj:1 0 R" must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-objects-not-dict.json
0 โ 100644
qpdf/qtest/qpdf/qjson-objects-not-dict.out
0 โ 100644
| 1 | +qpdf: qjson-objects-not-dict.json: offset 77: "objects" must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-stream-dict-not-dict.json
0 โ 100644
qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
0 โ 100644
| 1 | +qpdf: qjson-stream-dict-not-dict.json: offset 137: "stream.dict" must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-stream-not-dict.json
0 โ 100644
qpdf/qtest/qpdf/qjson-stream-not-dict.out
0 โ 100644
| 1 | +qpdf: qjson-stream-not-dict.json: offset 118: "stream" must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-top-level-array.json
0 โ 100644
| 1 | +["potato"] | ... | ... |
qpdf/qtest/qpdf/qjson-top-level-array.out
0 โ 100644
| 1 | +qpdf: qjson-top-level-array.json: QPDF JSON must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-top-level-scalar.json
0 โ 100644
| 1 | +"potato" | ... | ... |
qpdf/qtest/qpdf/qjson-top-level-scalar.out
0 โ 100644
| 1 | +qpdf: qjson-top-level-scalar.json: QPDF JSON must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-trailer-not-dict.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "value": false, | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-trailer-not-dict.out
0 โ 100644
| 1 | +qpdf: qjson-trailer-not-dict.json: offset 1326: "trailer.value" must be a dictionary | ... | ... |
qpdf/qtest/qpdf/qjson-trailer-stream.json
0 โ 100644
| 1 | +{ | |
| 2 | + "version": 2, | |
| 3 | + "parameters": { | |
| 4 | + "decodelevel": "none" | |
| 5 | + }, | |
| 6 | + "qpdf": { | |
| 7 | + "jsonversion": 2, | |
| 8 | + "pdfversion": "1.3", | |
| 9 | + "maxobjectid": 6, | |
| 10 | + "objects": { | |
| 11 | + "obj:1 0 R": { | |
| 12 | + "value": { | |
| 13 | + "/Pages": "2 0 R", | |
| 14 | + "/Type": "/Catalog" | |
| 15 | + } | |
| 16 | + }, | |
| 17 | + "obj:2 0 R": { | |
| 18 | + "value": { | |
| 19 | + "/Count": 1, | |
| 20 | + "/Kids": [ | |
| 21 | + "3 0 R" | |
| 22 | + ], | |
| 23 | + "/Type": "/Pages" | |
| 24 | + } | |
| 25 | + }, | |
| 26 | + "obj:3 0 R": { | |
| 27 | + "value": { | |
| 28 | + "/Contents": "4 0 R", | |
| 29 | + "/MediaBox": [ | |
| 30 | + 0, | |
| 31 | + 0, | |
| 32 | + 612, | |
| 33 | + 792 | |
| 34 | + ], | |
| 35 | + "/Parent": "2 0 R", | |
| 36 | + "/Resources": { | |
| 37 | + "/Font": { | |
| 38 | + "/F1": "6 0 R" | |
| 39 | + }, | |
| 40 | + "/ProcSet": "5 0 R" | |
| 41 | + }, | |
| 42 | + "/Type": "/Page" | |
| 43 | + } | |
| 44 | + }, | |
| 45 | + "obj:4 0 R": { | |
| 46 | + "stream": { | |
| 47 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 48 | + "dict": {} | |
| 49 | + } | |
| 50 | + }, | |
| 51 | + "obj:5 0 R": { | |
| 52 | + "value": [ | |
| 53 | + "/PDF", | |
| 54 | + "/Text" | |
| 55 | + ] | |
| 56 | + }, | |
| 57 | + "obj:6 0 R": { | |
| 58 | + "value": { | |
| 59 | + "/BaseFont": "/Helvetica", | |
| 60 | + "/Encoding": "/WinAnsiEncoding", | |
| 61 | + "/Subtype": "/Type1", | |
| 62 | + "/Type": "/Font" | |
| 63 | + } | |
| 64 | + }, | |
| 65 | + "trailer": { | |
| 66 | + "stream": {}, | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | +} | ... | ... |
qpdf/qtest/qpdf/qjson-trailer-stream.out
0 โ 100644
| 1 | +qpdf: qjson-trailer-stream.json: offset 1327: the trailer may not be a stream | ... | ... |