Commit d06509808957305ed01497568ddd81a2590362f8
1 parent
ef955b04
Test --update-from-json
Showing
17 changed files
with
849 additions
and
48 deletions
TODO
| ... | ... | @@ -58,15 +58,10 @@ Some of this documentation has drifted from the actual implementation. |
| 58 | 58 | |
| 59 | 59 | Make sure pages tree repair generates warnings. |
| 60 | 60 | |
| 61 | -* Reread from perspective of update | |
| 62 | -* Test all ignore cases with QTC | |
| 63 | -* Test case of correct file with dict before data/datafile | |
| 64 | 61 | * Have a test case if possible that exercises the object description |
| 65 | 62 | which means we need some kind of semantic error that gets caught |
| 66 | 63 | after creation. |
| 67 | 64 | * Test invalid data, invalid data file |
| 68 | -* Tests: round-trip through json, round-trip through qpdf --qdf | |
| 69 | -* Test to see if we get CR/NL on Windows, which is okay | |
| 70 | 65 | |
| 71 | 66 | Try to never flatten pages tree. Make sure we do something reasonable |
| 72 | 67 | with pages tree repair. The problem is that if pages tree repair is |
| ... | ... | @@ -104,22 +99,20 @@ JSON to PDF: |
| 104 | 99 | |
| 105 | 100 | Have --json-input and --update-from-json. With --json-input, the json |
| 106 | 101 | file must be complete, meaning all stream data, the trailer, and the |
| 107 | -PDF version must be present. In --update-from-json, an object | |
| 108 | -explicitly set to null (not "value": null) is deleted. For streams | |
| 109 | -with no stream data, the dictionary is updated but the data is left | |
| 110 | -untouched. Other things that are omitted are left alone. Make sure | |
| 111 | -document that, when writing a PDF file from QPDF, there is no | |
| 112 | -expectation of object numbers being preserved. As such, | |
| 113 | ---update-from-json can only be used to update the exact file that the | |
| 114 | -json was created from. You can put multiple objects in the update | |
| 115 | -file, but you can't use a json from one file to update the output of a | |
| 116 | -previous update since the object numbers will have changed. Note that, | |
| 117 | -when creating from a JSON, object numbers are preserved in the | |
| 118 | -resulting QPDF object but still modified by QPDFWriter for the output. | |
| 119 | -This would be visible by combining --json-output and --json-input. | |
| 120 | -Also using --qdf with --create-from-json would show original object | |
| 121 | -IDs in comments. It will be important to capture this in the | |
| 122 | -documentation. | |
| 102 | +PDF version must be present. For streams with no stream data, the | |
| 103 | +dictionary is updated but the data is left untouched. Other things | |
| 104 | +that are omitted are left alone. Make sure document that, when writing | |
| 105 | +a PDF file from QPDF, there is no expectation of object numbers being | |
| 106 | +preserved. As such, --update-from-json can only be used to update the | |
| 107 | +exact file that the json was created from. You can put multiple | |
| 108 | +objects in the update file, but you can't use a json from one file to | |
| 109 | +update the output of a previous update since the object numbers will | |
| 110 | +have changed. Note that, when creating from a JSON, object numbers are | |
| 111 | +preserved in the resulting QPDF object but still modified by | |
| 112 | +QPDFWriter for the output. This would be visible by combining | |
| 113 | +--json-output and --json-input. Also using --qdf with | |
| 114 | +--create-from-json would show original object IDs in comments. It will | |
| 115 | +be important to capture this in the documentation. | |
| 123 | 116 | |
| 124 | 117 | When reading a JSON string, any string that doesn't look like a name |
| 125 | 118 | or indirect object or start with "b:" or "u:" should be considered an | ... | ... |
include/qpdf/QPDF.hh
| ... | ... | @@ -1065,6 +1065,7 @@ class QPDF |
| 1065 | 1065 | bool saw_dict; |
| 1066 | 1066 | bool saw_data; |
| 1067 | 1067 | bool saw_datafile; |
| 1068 | + bool this_stream_needs_data; | |
| 1068 | 1069 | std::vector<state_e> state_stack; |
| 1069 | 1070 | std::vector<QPDFObjectHandle> object_stack; |
| 1070 | 1071 | std::set<QPDFObjGen> reserved; | ... | ... |
libqpdf/QPDF_json.cc
| ... | ... | @@ -102,7 +102,8 @@ QPDF::JSONReactor::JSONReactor( |
| 102 | 102 | saw_stream(false), |
| 103 | 103 | saw_dict(false), |
| 104 | 104 | saw_data(false), |
| 105 | - saw_datafile(false) | |
| 105 | + saw_datafile(false), | |
| 106 | + this_stream_needs_data(false) | |
| 106 | 107 | { |
| 107 | 108 | state_stack.push_back(st_initial); |
| 108 | 109 | } |
| ... | ... | @@ -111,8 +112,11 @@ void |
| 111 | 112 | QPDF::JSONReactor::error(size_t offset, std::string const& msg) |
| 112 | 113 | { |
| 113 | 114 | this->errors = true; |
| 114 | - this->pdf.warn( | |
| 115 | - qpdf_e_json, this->cur_object, QIntC::to_offset(offset), msg); | |
| 115 | + std::string object = this->cur_object; | |
| 116 | + if (is->getName() != pdf.getFilename()) { | |
| 117 | + object += " from " + is->getName(); | |
| 118 | + } | |
| 119 | + this->pdf.warn(qpdf_e_json, object, QIntC::to_offset(offset), msg); | |
| 116 | 120 | } |
| 117 | 121 | |
| 118 | 122 | bool |
| ... | ... | @@ -196,20 +200,22 @@ QPDF::JSONReactor::containerEnd(JSON const& value) |
| 196 | 200 | QTC::TC("qpdf", "QPDF_json stream no dict"); |
| 197 | 201 | error(value.getStart(), "\"stream\" is missing \"dict\""); |
| 198 | 202 | } |
| 199 | - if (must_be_complete) { | |
| 200 | - if (saw_data == saw_datafile) { | |
| 203 | + if (saw_data == saw_datafile) { | |
| 204 | + if (this_stream_needs_data) { | |
| 201 | 205 | QTC::TC("qpdf", "QPDF_json data datafile both or neither"); |
| 202 | 206 | error( |
| 203 | 207 | value.getStart(), |
| 204 | - "\"stream\" must have exactly one of \"data\" or " | |
| 208 | + "new \"stream\" must have exactly one of \"data\" or " | |
| 209 | + "\"datafile\""); | |
| 210 | + } else if (saw_datafile) { | |
| 211 | + QTC::TC("qpdf", "QPDF_json data and datafile"); | |
| 212 | + error( | |
| 213 | + value.getStart(), | |
| 214 | + "existing \"stream\" may at most one of \"data\" or " | |
| 205 | 215 | "\"datafile\""); |
| 216 | + } else { | |
| 217 | + QTC::TC("qpdf", "QPDF_json no stream data in update mode"); | |
| 206 | 218 | } |
| 207 | - } else if (saw_data && saw_datafile) { | |
| 208 | - // QXXXQ | |
| 209 | - /// QTC::TC("qpdf", "QPDF_json data and datafile"); | |
| 210 | - error( | |
| 211 | - value.getStart(), | |
| 212 | - "\"stream\" may at most one of \"data\" or \"datafile\""); | |
| 213 | 219 | } |
| 214 | 220 | } |
| 215 | 221 | } else if ((state == st_stream) || (state == st_object)) { |
| ... | ... | @@ -320,7 +326,6 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) |
| 320 | 326 | nestedState(key, value, st_trailer); |
| 321 | 327 | this->cur_object = "trailer"; |
| 322 | 328 | } else if (std::regex_match(key, m, OBJ_KEY_RE)) { |
| 323 | - // QXXXQ remember to handle null for delete | |
| 324 | 329 | object_stack.push_back(reserveObject(m[1].str(), m[2].str())); |
| 325 | 330 | nestedState(key, value, st_object_top); |
| 326 | 331 | this->cur_object = key; |
| ... | ... | @@ -347,9 +352,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) |
| 347 | 352 | } else if (key == "stream") { |
| 348 | 353 | this->saw_stream = true; |
| 349 | 354 | nestedState(key, value, st_stream); |
| 355 | + this->this_stream_needs_data = false; | |
| 350 | 356 | if (tos.isStream()) { |
| 351 | - // QXXXQ reusing -- need QTC | |
| 357 | + QTC::TC("qpdf", "QPDF_json updating existing stream"); | |
| 352 | 358 | } else { |
| 359 | + this->this_stream_needs_data = true; | |
| 353 | 360 | replacement = |
| 354 | 361 | pdf.reserveStream(tos.getObjectID(), tos.getGeneration()); |
| 355 | 362 | replaceObject(tos, replacement); |
| ... | ... | @@ -386,12 +393,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) |
| 386 | 393 | throw std::logic_error("no object on stack in st_stream"); |
| 387 | 394 | } |
| 388 | 395 | auto tos = object_stack.back(); |
| 389 | - auto uninitialized = QPDFObjectHandle(); | |
| 390 | 396 | if (!tos.isStream()) { |
| 391 | - // QXXXQ QTC in update mode | |
| 392 | - error(value.getStart(), "this object is not a stream"); | |
| 393 | - parse_error = true; | |
| 394 | - } else if (key == "dict") { | |
| 397 | + throw std::logic_error("top of stack is not stream in st_stream"); | |
| 398 | + } | |
| 399 | + auto uninitialized = QPDFObjectHandle(); | |
| 400 | + if (key == "dict") { | |
| 395 | 401 | this->saw_dict = true; |
| 396 | 402 | // Since a stream dictionary must be a dictionary, we can |
| 397 | 403 | // use nestedState to transition to st_value. |
| ... | ... | @@ -509,11 +515,12 @@ QPDF::JSONReactor::makeObject(JSON const& value) |
| 509 | 515 | "JSONReactor::makeObject didn't initialize the object"); |
| 510 | 516 | } |
| 511 | 517 | |
| 512 | - // QXXXQ include object number in description | |
| 513 | - result.setObjectDescription( | |
| 514 | - &this->pdf, | |
| 515 | - this->is->getName() + " offset " + | |
| 516 | - QUtil::uint_to_string(value.getStart())); | |
| 518 | + std::string description = this->is->getName(); | |
| 519 | + if (!this->cur_object.empty()) { | |
| 520 | + description += " " + this->cur_object + ","; | |
| 521 | + } | |
| 522 | + description += " offset " + QUtil::uint_to_string(value.getStart()); | |
| 523 | + result.setObjectDescription(&this->pdf, description); | |
| 517 | 524 | return result; |
| 518 | 525 | } |
| 519 | 526 | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -676,3 +676,6 @@ QPDF_json ignore unknown key in object_top 0 |
| 676 | 676 | QPDF_json ignore unknown key in trailer 0 |
| 677 | 677 | QPDF_json ignore unknown key in stream 0 |
| 678 | 678 | QPDF_json non-trivial null reserved 0 |
| 679 | +QPDF_json data and datafile 0 | |
| 680 | +QPDF_json no stream data in update mode 0 | |
| 681 | +QPDF_json updating existing stream 0 | ... | ... |
qpdf/qtest/qpdf-json.test
| ... | ... | @@ -171,5 +171,35 @@ $td->runtest("check PDF", |
| 171 | 171 | {$td->FILE => "a.pdf"}, |
| 172 | 172 | {$td->FILE => "b.pdf"}); |
| 173 | 173 | |
| 174 | +# Replace mode tests | |
| 175 | + | |
| 176 | +$n_tests += 1; | |
| 177 | +$td->runtest("create PDF for replace", | |
| 178 | + {$td->COMMAND => "qpdf good13.pdf a.pdf" . | |
| 179 | + " --update-from-json=qpdf-json-update-errors.json"}, | |
| 180 | + {$td->FILE => "update-from-json-errors.out", | |
| 181 | + $td->EXIT_STATUS => 2}, | |
| 182 | + $td->NORMALIZE_NEWLINES); | |
| 183 | + | |
| 184 | +my @update_files = ( | |
| 185 | + "update-stream-dict-only", | |
| 186 | + "update-stream-data", | |
| 187 | + "replace-with-stream", | |
| 188 | + "various-updates", | |
| 189 | + ); | |
| 190 | +$n_tests += 2 * scalar(@update_files); | |
| 191 | + | |
| 192 | +foreach my $f (@update_files) { | |
| 193 | + $td->runtest("update: $f", | |
| 194 | + {$td->COMMAND => | |
| 195 | + "qpdf good13.pdf a.pdf --qdf --static-id" . | |
| 196 | + " --update-from-json=$f.json"}, | |
| 197 | + {$td->STRING => "", $td->EXIT_STATUS => 0}); | |
| 198 | + $td->runtest("$f: check updated", | |
| 199 | + {$td->FILE => "a.pdf"}, | |
| 200 | + {$td->FILE => "$f-updated.pdf"}); | |
| 201 | +} | |
| 202 | + | |
| 203 | + | |
| 174 | 204 | cleanup(); |
| 175 | 205 | $td->report($n_tests); | ... | ... |
qpdf/qtest/qpdf/qjson-obj-key-errors.out
| 1 | 1 | WARNING: qjson-obj-key-errors.json (obj:2 0 R, offset 218): object must have exactly one of "value" or "stream" |
| 2 | 2 | WARNING: qjson-obj-key-errors.json (obj:3 0 R, offset 516): object must have exactly one of "value" or "stream" |
| 3 | 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): "stream" must have exactly one of "data" or "datafile" | |
| 5 | -WARNING: qjson-obj-key-errors.json (obj:5 0 R, offset 774): "stream" must have exactly one of "data" or "datafile" | |
| 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 | 6 | WARNING: qjson-obj-key-errors.json (trailer, offset 1152): "trailer" is missing "value" |
| 7 | 7 | qpdf: qjson-obj-key-errors.json: errors found in JSON | ... | ... |
qpdf/qtest/qpdf/qjson-stream-dict-not-dict.out
| 1 | 1 | WARNING: qjson-stream-dict-not-dict.json (obj:1 0 R, offset 118): "stream.dict" must be a dictionary |
| 2 | 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): "stream" must have exactly one of "data" or "datafile" | |
| 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 | 4 | WARNING: qjson-stream-dict-not-dict.json: "qpdf-v2.objects.trailer" was not seen |
| 5 | 5 | qpdf: qjson-stream-dict-not-dict.json: errors found in JSON | ... | ... |
qpdf/qtest/qpdf/qpdf-json-update-errors.json
0 → 100644
| 1 | +{ | |
| 2 | + "qpdf-v2": { | |
| 3 | + "objects": { | |
| 4 | + "obj:4 0 R": { | |
| 5 | + "stream": { | |
| 6 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoUG90YXRvKSBUagpFVAo=", | |
| 7 | + "datafile": "file-too", | |
| 8 | + "dict": {} | |
| 9 | + } | |
| 10 | + }, | |
| 11 | + "obj:20 0 R": { | |
| 12 | + "stream": { | |
| 13 | + "dict": { | |
| 14 | + "/Bad": "string-value" | |
| 15 | + } | |
| 16 | + } | |
| 17 | + } | |
| 18 | + } | |
| 19 | + } | |
| 20 | +} | ... | ... |
qpdf/qtest/qpdf/replace-with-stream-updated.pdf
0 → 100644
| 1 | +%PDF-2.0 | |
| 2 | +%¿÷¢þ | |
| 3 | +%QDF-1.0 | |
| 4 | + | |
| 5 | +%% Original object ID: 1 0 | |
| 6 | +1 0 obj | |
| 7 | +<< | |
| 8 | + /Pages 3 0 R | |
| 9 | + /Type /Catalog | |
| 10 | +>> | |
| 11 | +endobj | |
| 12 | + | |
| 13 | +%% Original object ID: 7 0 | |
| 14 | +2 0 obj | |
| 15 | +<< | |
| 16 | + /dangling-ref-for-json-test [ | |
| 17 | + 4 0 R | |
| 18 | + ] | |
| 19 | + /hex#20strings [ | |
| 20 | + (Potato) | |
| 21 | + <01020300040560> | |
| 22 | + (AB) | |
| 23 | + ] | |
| 24 | + /indirect 5 0 R | |
| 25 | + /names [ | |
| 26 | + /nesting | |
| 27 | + /hex#20strings | |
| 28 | + /text#2fplain | |
| 29 | + ] | |
| 30 | + /nesting << | |
| 31 | + /a [ | |
| 32 | + 1 | |
| 33 | + 2 | |
| 34 | + << | |
| 35 | + /x (y) | |
| 36 | + >> | |
| 37 | + [ | |
| 38 | + (z) | |
| 39 | + ] | |
| 40 | + ] | |
| 41 | + /b << | |
| 42 | + / (legal) | |
| 43 | + /a [ | |
| 44 | + 1 | |
| 45 | + 2 | |
| 46 | + ] | |
| 47 | + >> | |
| 48 | + >> | |
| 49 | + /strings [ | |
| 50 | + (one) | |
| 51 | + <24a2> | |
| 52 | + () | |
| 53 | + (\(\)) | |
| 54 | + (\() | |
| 55 | + (\)) | |
| 56 | + (a\f\b\t\r\nb) | |
| 57 | + (") | |
| 58 | + ("") | |
| 59 | + ("\("\)") | |
| 60 | + <410042> | |
| 61 | + (a\nb) | |
| 62 | + (a b) | |
| 63 | + <efbbbfcf80> | |
| 64 | + <efbbbff09fa594> | |
| 65 | + ] | |
| 66 | +>> | |
| 67 | +endobj | |
| 68 | + | |
| 69 | +%% Original object ID: 2 0 | |
| 70 | +3 0 obj | |
| 71 | +<< | |
| 72 | + /Count 1 | |
| 73 | + /Kids [ | |
| 74 | + 7 0 R | |
| 75 | + ] | |
| 76 | + /Type /Pages | |
| 77 | +>> | |
| 78 | +endobj | |
| 79 | + | |
| 80 | +%% Original object ID: 9 0 | |
| 81 | +4 0 obj | |
| 82 | +null | |
| 83 | +endobj | |
| 84 | + | |
| 85 | +%% Original object ID: 8 0 | |
| 86 | +5 0 obj | |
| 87 | +<< | |
| 88 | + /K /V | |
| 89 | + /Length 6 0 R | |
| 90 | +>> | |
| 91 | +stream | |
| 92 | +new-stream-here | |
| 93 | +endstream | |
| 94 | +endobj | |
| 95 | + | |
| 96 | +6 0 obj | |
| 97 | +16 | |
| 98 | +endobj | |
| 99 | + | |
| 100 | +%% Page 1 | |
| 101 | +%% Original object ID: 3 0 | |
| 102 | +7 0 obj | |
| 103 | +<< | |
| 104 | + /Contents 8 0 R | |
| 105 | + /MediaBox [ | |
| 106 | + 0 | |
| 107 | + 0 | |
| 108 | + 612 | |
| 109 | + 792 | |
| 110 | + ] | |
| 111 | + /Parent 3 0 R | |
| 112 | + /Resources << | |
| 113 | + /Font << | |
| 114 | + /F1 10 0 R | |
| 115 | + >> | |
| 116 | + /ProcSet 11 0 R | |
| 117 | + >> | |
| 118 | + /Type /Page | |
| 119 | +>> | |
| 120 | +endobj | |
| 121 | + | |
| 122 | +%% Contents for page 1 | |
| 123 | +%% Original object ID: 4 0 | |
| 124 | +8 0 obj | |
| 125 | +<< | |
| 126 | + /Length 9 0 R | |
| 127 | +>> | |
| 128 | +stream | |
| 129 | +BT | |
| 130 | + /F1 24 Tf | |
| 131 | + 72 720 Td | |
| 132 | + (Potato) Tj | |
| 133 | +ET | |
| 134 | +endstream | |
| 135 | +endobj | |
| 136 | + | |
| 137 | +9 0 obj | |
| 138 | +44 | |
| 139 | +endobj | |
| 140 | + | |
| 141 | +%% Original object ID: 6 0 | |
| 142 | +10 0 obj | |
| 143 | +<< | |
| 144 | + /BaseFont /Helvetica | |
| 145 | + /Encoding /WinAnsiEncoding | |
| 146 | + /Name /F1 | |
| 147 | + /Subtype /Type1 | |
| 148 | + /Type /Font | |
| 149 | +>> | |
| 150 | +endobj | |
| 151 | + | |
| 152 | +%% Original object ID: 5 0 | |
| 153 | +11 0 obj | |
| 154 | +[ | |
| 155 | ||
| 156 | + /Text | |
| 157 | +] | |
| 158 | +endobj | |
| 159 | + | |
| 160 | +xref | |
| 161 | +0 12 | |
| 162 | +0000000000 65535 f | |
| 163 | +0000000052 00000 n | |
| 164 | +0000000133 00000 n | |
| 165 | +0000000756 00000 n | |
| 166 | +0000000855 00000 n | |
| 167 | +0000000903 00000 n | |
| 168 | +0000000982 00000 n | |
| 169 | +0000001038 00000 n | |
| 170 | +0000001282 00000 n | |
| 171 | +0000001381 00000 n | |
| 172 | +0000001427 00000 n | |
| 173 | +0000001573 00000 n | |
| 174 | +trailer << | |
| 175 | + /QTest 2 0 R | |
| 176 | + /Root 1 0 R | |
| 177 | + /Size 12 | |
| 178 | + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] | |
| 179 | +>> | |
| 180 | +startxref | |
| 181 | +1609 | |
| 182 | +%%EOF | ... | ... |
qpdf/qtest/qpdf/replace-with-stream.json
0 → 100644
qpdf/qtest/qpdf/update-from-json-errors.out
0 → 100644
| 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" | |
| 4 | +qpdf: qpdf-json-update-errors.json: errors found in JSON | ... | ... |
qpdf/qtest/qpdf/update-stream-data-updated.pdf
0 → 100644
| 1 | +%PDF-2.0 | |
| 2 | +%¿÷¢þ | |
| 3 | +%QDF-1.0 | |
| 4 | + | |
| 5 | +%% Original object ID: 1 0 | |
| 6 | +1 0 obj | |
| 7 | +<< | |
| 8 | + /Pages 3 0 R | |
| 9 | + /Type /Catalog | |
| 10 | +>> | |
| 11 | +endobj | |
| 12 | + | |
| 13 | +%% Original object ID: 7 0 | |
| 14 | +2 0 obj | |
| 15 | +<< | |
| 16 | + /dangling-ref-for-json-test [ | |
| 17 | + 4 0 R | |
| 18 | + ] | |
| 19 | + /hex#20strings [ | |
| 20 | + (Potato) | |
| 21 | + <01020300040560> | |
| 22 | + (AB) | |
| 23 | + ] | |
| 24 | + /indirect 5 0 R | |
| 25 | + /names [ | |
| 26 | + /nesting | |
| 27 | + /hex#20strings | |
| 28 | + /text#2fplain | |
| 29 | + ] | |
| 30 | + /nesting << | |
| 31 | + /a [ | |
| 32 | + 1 | |
| 33 | + 2 | |
| 34 | + << | |
| 35 | + /x (y) | |
| 36 | + >> | |
| 37 | + [ | |
| 38 | + (z) | |
| 39 | + ] | |
| 40 | + ] | |
| 41 | + /b << | |
| 42 | + / (legal) | |
| 43 | + /a [ | |
| 44 | + 1 | |
| 45 | + 2 | |
| 46 | + ] | |
| 47 | + >> | |
| 48 | + >> | |
| 49 | + /strings [ | |
| 50 | + (one) | |
| 51 | + <24a2> | |
| 52 | + () | |
| 53 | + (\(\)) | |
| 54 | + (\() | |
| 55 | + (\)) | |
| 56 | + (a\f\b\t\r\nb) | |
| 57 | + (") | |
| 58 | + ("") | |
| 59 | + ("\("\)") | |
| 60 | + <410042> | |
| 61 | + (a\nb) | |
| 62 | + (a b) | |
| 63 | + <efbbbfcf80> | |
| 64 | + <efbbbff09fa594> | |
| 65 | + ] | |
| 66 | +>> | |
| 67 | +endobj | |
| 68 | + | |
| 69 | +%% Original object ID: 2 0 | |
| 70 | +3 0 obj | |
| 71 | +<< | |
| 72 | + /Count 1 | |
| 73 | + /Kids [ | |
| 74 | + 6 0 R | |
| 75 | + ] | |
| 76 | + /Type /Pages | |
| 77 | +>> | |
| 78 | +endobj | |
| 79 | + | |
| 80 | +%% Original object ID: 9 0 | |
| 81 | +4 0 obj | |
| 82 | +null | |
| 83 | +endobj | |
| 84 | + | |
| 85 | +%% Original object ID: 8 0 | |
| 86 | +5 0 obj | |
| 87 | +(hello) | |
| 88 | +endobj | |
| 89 | + | |
| 90 | +%% Page 1 | |
| 91 | +%% Original object ID: 3 0 | |
| 92 | +6 0 obj | |
| 93 | +<< | |
| 94 | + /Contents 7 0 R | |
| 95 | + /MediaBox [ | |
| 96 | + 0 | |
| 97 | + 0 | |
| 98 | + 612 | |
| 99 | + 792 | |
| 100 | + ] | |
| 101 | + /Parent 3 0 R | |
| 102 | + /Resources << | |
| 103 | + /Font << | |
| 104 | + /F1 9 0 R | |
| 105 | + >> | |
| 106 | + /ProcSet 10 0 R | |
| 107 | + >> | |
| 108 | + /Type /Page | |
| 109 | +>> | |
| 110 | +endobj | |
| 111 | + | |
| 112 | +%% Contents for page 1 | |
| 113 | +%% Original object ID: 4 0 | |
| 114 | +7 0 obj | |
| 115 | +<< | |
| 116 | + /Length 8 0 R | |
| 117 | +>> | |
| 118 | +stream | |
| 119 | +BT | |
| 120 | + /F1 24 Tf | |
| 121 | + 72 720 Td | |
| 122 | + (Salad) Tj | |
| 123 | +ET | |
| 124 | +endstream | |
| 125 | +endobj | |
| 126 | + | |
| 127 | +8 0 obj | |
| 128 | +43 | |
| 129 | +endobj | |
| 130 | + | |
| 131 | +%% Original object ID: 6 0 | |
| 132 | +9 0 obj | |
| 133 | +<< | |
| 134 | + /BaseFont /Helvetica | |
| 135 | + /Encoding /WinAnsiEncoding | |
| 136 | + /Name /F1 | |
| 137 | + /Subtype /Type1 | |
| 138 | + /Type /Font | |
| 139 | +>> | |
| 140 | +endobj | |
| 141 | + | |
| 142 | +%% Original object ID: 5 0 | |
| 143 | +10 0 obj | |
| 144 | +[ | |
| 145 | ||
| 146 | + /Text | |
| 147 | +] | |
| 148 | +endobj | |
| 149 | + | |
| 150 | +xref | |
| 151 | +0 11 | |
| 152 | +0000000000 65535 f | |
| 153 | +0000000052 00000 n | |
| 154 | +0000000133 00000 n | |
| 155 | +0000000756 00000 n | |
| 156 | +0000000855 00000 n | |
| 157 | +0000000903 00000 n | |
| 158 | +0000000964 00000 n | |
| 159 | +0000001207 00000 n | |
| 160 | +0000001305 00000 n | |
| 161 | +0000001351 00000 n | |
| 162 | +0000001496 00000 n | |
| 163 | +trailer << | |
| 164 | + /QTest 2 0 R | |
| 165 | + /Root 1 0 R | |
| 166 | + /Size 11 | |
| 167 | + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] | |
| 168 | +>> | |
| 169 | +startxref | |
| 170 | +1532 | |
| 171 | +%%EOF | ... | ... |
qpdf/qtest/qpdf/update-stream-data.json
0 → 100644
| 1 | +{ | |
| 2 | + "qpdf-v2": { | |
| 3 | + "pdfversion": "2.0", | |
| 4 | + "maxobjectid": 9, | |
| 5 | + "objects": { | |
| 6 | + "obj:1 0 R": { | |
| 7 | + "value": { | |
| 8 | + "/Pages": "2 0 R", | |
| 9 | + "/Type": "/Catalog" | |
| 10 | + } | |
| 11 | + }, | |
| 12 | + "obj:4 0 R": { | |
| 13 | + "stream": { | |
| 14 | + "data": "QlQKICAvRjEgMjQgVGYKICA3MiA3MjAgVGQKICAoU2FsYWQpIFRqCkVUCg==", | |
| 15 | + "dict": {} | |
| 16 | + } | |
| 17 | + } | |
| 18 | + } | |
| 19 | + } | |
| 20 | +} | ... | ... |
qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf
0 → 100644
| 1 | +%PDF-2.0 | |
| 2 | +%¿÷¢þ | |
| 3 | +%QDF-1.0 | |
| 4 | + | |
| 5 | +%% Original object ID: 1 0 | |
| 6 | +1 0 obj | |
| 7 | +<< | |
| 8 | + /Pages 3 0 R | |
| 9 | + /Type /Catalog | |
| 10 | +>> | |
| 11 | +endobj | |
| 12 | + | |
| 13 | +%% Original object ID: 7 0 | |
| 14 | +2 0 obj | |
| 15 | +<< | |
| 16 | + /dangling-ref-for-json-test [ | |
| 17 | + 4 0 R | |
| 18 | + ] | |
| 19 | + /hex#20strings [ | |
| 20 | + (Potato) | |
| 21 | + <01020300040560> | |
| 22 | + (AB) | |
| 23 | + ] | |
| 24 | + /indirect 5 0 R | |
| 25 | + /names [ | |
| 26 | + /nesting | |
| 27 | + /hex#20strings | |
| 28 | + /text#2fplain | |
| 29 | + ] | |
| 30 | + /nesting << | |
| 31 | + /a [ | |
| 32 | + 1 | |
| 33 | + 2 | |
| 34 | + << | |
| 35 | + /x (y) | |
| 36 | + >> | |
| 37 | + [ | |
| 38 | + (z) | |
| 39 | + ] | |
| 40 | + ] | |
| 41 | + /b << | |
| 42 | + / (legal) | |
| 43 | + /a [ | |
| 44 | + 1 | |
| 45 | + 2 | |
| 46 | + ] | |
| 47 | + >> | |
| 48 | + >> | |
| 49 | + /strings [ | |
| 50 | + (one) | |
| 51 | + <24a2> | |
| 52 | + () | |
| 53 | + (\(\)) | |
| 54 | + (\() | |
| 55 | + (\)) | |
| 56 | + (a\f\b\t\r\nb) | |
| 57 | + (") | |
| 58 | + ("") | |
| 59 | + ("\("\)") | |
| 60 | + <410042> | |
| 61 | + (a\nb) | |
| 62 | + (a b) | |
| 63 | + <efbbbfcf80> | |
| 64 | + <efbbbff09fa594> | |
| 65 | + ] | |
| 66 | +>> | |
| 67 | +endobj | |
| 68 | + | |
| 69 | +%% Original object ID: 2 0 | |
| 70 | +3 0 obj | |
| 71 | +<< | |
| 72 | + /Count 1 | |
| 73 | + /Kids [ | |
| 74 | + 6 0 R | |
| 75 | + ] | |
| 76 | + /Type /Pages | |
| 77 | +>> | |
| 78 | +endobj | |
| 79 | + | |
| 80 | +%% Original object ID: 9 0 | |
| 81 | +4 0 obj | |
| 82 | +null | |
| 83 | +endobj | |
| 84 | + | |
| 85 | +%% Original object ID: 8 0 | |
| 86 | +5 0 obj | |
| 87 | +(hello) | |
| 88 | +endobj | |
| 89 | + | |
| 90 | +%% Page 1 | |
| 91 | +%% Original object ID: 3 0 | |
| 92 | +6 0 obj | |
| 93 | +<< | |
| 94 | + /Contents 7 0 R | |
| 95 | + /MediaBox [ | |
| 96 | + 0 | |
| 97 | + 0 | |
| 98 | + 612 | |
| 99 | + 792 | |
| 100 | + ] | |
| 101 | + /Parent 3 0 R | |
| 102 | + /Resources << | |
| 103 | + /Font << | |
| 104 | + /F1 9 0 R | |
| 105 | + >> | |
| 106 | + /ProcSet 10 0 R | |
| 107 | + >> | |
| 108 | + /Type /Page | |
| 109 | +>> | |
| 110 | +endobj | |
| 111 | + | |
| 112 | +%% Contents for page 1 | |
| 113 | +%% Original object ID: 4 0 | |
| 114 | +7 0 obj | |
| 115 | +<< | |
| 116 | + /Potato (salad) | |
| 117 | + /Length 8 0 R | |
| 118 | +>> | |
| 119 | +stream | |
| 120 | +BT | |
| 121 | + /F1 24 Tf | |
| 122 | + 72 720 Td | |
| 123 | + (Potato) Tj | |
| 124 | +ET | |
| 125 | +endstream | |
| 126 | +endobj | |
| 127 | + | |
| 128 | +8 0 obj | |
| 129 | +44 | |
| 130 | +endobj | |
| 131 | + | |
| 132 | +%% Original object ID: 6 0 | |
| 133 | +9 0 obj | |
| 134 | +<< | |
| 135 | + /BaseFont /Helvetica | |
| 136 | + /Encoding /WinAnsiEncoding | |
| 137 | + /Name /F1 | |
| 138 | + /Subtype /Type1 | |
| 139 | + /Type /Font | |
| 140 | +>> | |
| 141 | +endobj | |
| 142 | + | |
| 143 | +%% Original object ID: 5 0 | |
| 144 | +10 0 obj | |
| 145 | +[ | |
| 146 | ||
| 147 | + /Text | |
| 148 | +] | |
| 149 | +endobj | |
| 150 | + | |
| 151 | +xref | |
| 152 | +0 11 | |
| 153 | +0000000000 65535 f | |
| 154 | +0000000052 00000 n | |
| 155 | +0000000133 00000 n | |
| 156 | +0000000756 00000 n | |
| 157 | +0000000855 00000 n | |
| 158 | +0000000903 00000 n | |
| 159 | +0000000964 00000 n | |
| 160 | +0000001207 00000 n | |
| 161 | +0000001324 00000 n | |
| 162 | +0000001370 00000 n | |
| 163 | +0000001515 00000 n | |
| 164 | +trailer << | |
| 165 | + /QTest 2 0 R | |
| 166 | + /Root 1 0 R | |
| 167 | + /Size 11 | |
| 168 | + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] | |
| 169 | +>> | |
| 170 | +startxref | |
| 171 | +1551 | |
| 172 | +%%EOF | ... | ... |
qpdf/qtest/qpdf/update-stream-dict-only.json
0 → 100644
qpdf/qtest/qpdf/various-updates-updated.pdf
0 → 100644
| 1 | +%PDF-2.0 | |
| 2 | +%¿÷¢þ | |
| 3 | +%QDF-1.0 | |
| 4 | + | |
| 5 | +%% Original object ID: 1 0 | |
| 6 | +1 0 obj | |
| 7 | +<< | |
| 8 | + /Pages 3 0 R | |
| 9 | + /Type /Catalog | |
| 10 | +>> | |
| 11 | +endobj | |
| 12 | + | |
| 13 | +%% Original object ID: 7 0 | |
| 14 | +2 0 obj | |
| 15 | +<< | |
| 16 | + /indirect 4 0 R | |
| 17 | + /now-#cf#80 [ | |
| 18 | + 5 0 R | |
| 19 | + ] | |
| 20 | + /strings [ | |
| 21 | + (one) | |
| 22 | + <feff03c0> | |
| 23 | + ] | |
| 24 | +>> | |
| 25 | +endobj | |
| 26 | + | |
| 27 | +%% Original object ID: 2 0 | |
| 28 | +3 0 obj | |
| 29 | +<< | |
| 30 | + /Count 1 | |
| 31 | + /Kids [ | |
| 32 | + 6 0 R | |
| 33 | + ] | |
| 34 | + /Type /Pages | |
| 35 | +>> | |
| 36 | +endobj | |
| 37 | + | |
| 38 | +%% Original object ID: 8 0 | |
| 39 | +4 0 obj | |
| 40 | +[ | |
| 41 | + (hello) | |
| 42 | + 7 0 R | |
| 43 | +] | |
| 44 | +endobj | |
| 45 | + | |
| 46 | +%% Original object ID: 9 0 | |
| 47 | +5 0 obj | |
| 48 | +3.14159 | |
| 49 | +endobj | |
| 50 | + | |
| 51 | +%% Page 1 | |
| 52 | +%% Original object ID: 3 0 | |
| 53 | +6 0 obj | |
| 54 | +<< | |
| 55 | + /Contents 8 0 R | |
| 56 | + /MediaBox [ | |
| 57 | + 0 | |
| 58 | + 0 | |
| 59 | + 612 | |
| 60 | + 792 | |
| 61 | + ] | |
| 62 | + /Parent 3 0 R | |
| 63 | + /Resources << | |
| 64 | + /Font << | |
| 65 | + /F1 10 0 R | |
| 66 | + >> | |
| 67 | + >> | |
| 68 | + /Type /Page | |
| 69 | +>> | |
| 70 | +endobj | |
| 71 | + | |
| 72 | +%% Original object ID: 10 0 | |
| 73 | +7 0 obj | |
| 74 | +(this is new) | |
| 75 | +endobj | |
| 76 | + | |
| 77 | +%% Contents for page 1 | |
| 78 | +%% Original object ID: 4 0 | |
| 79 | +8 0 obj | |
| 80 | +<< | |
| 81 | + /Length 9 0 R | |
| 82 | +>> | |
| 83 | +stream | |
| 84 | +BT | |
| 85 | + /F1 24 Tf | |
| 86 | + 72 720 Td | |
| 87 | + (Potato) Tj | |
| 88 | +ET | |
| 89 | +endstream | |
| 90 | +endobj | |
| 91 | + | |
| 92 | +9 0 obj | |
| 93 | +44 | |
| 94 | +endobj | |
| 95 | + | |
| 96 | +%% Original object ID: 6 0 | |
| 97 | +10 0 obj | |
| 98 | +<< | |
| 99 | + /BaseFont /Helvetica | |
| 100 | + /Encoding /WinAnsiEncoding | |
| 101 | + /Name /F1 | |
| 102 | + /Subtype /Type1 | |
| 103 | + /Type /Font | |
| 104 | +>> | |
| 105 | +endobj | |
| 106 | + | |
| 107 | +xref | |
| 108 | +0 11 | |
| 109 | +0000000000 65535 f | |
| 110 | +0000000052 00000 n | |
| 111 | +0000000133 00000 n | |
| 112 | +0000000272 00000 n | |
| 113 | +0000000371 00000 n | |
| 114 | +0000000436 00000 n | |
| 115 | +0000000497 00000 n | |
| 116 | +0000000699 00000 n | |
| 117 | +0000000779 00000 n | |
| 118 | +0000000878 00000 n | |
| 119 | +0000000924 00000 n | |
| 120 | +trailer << | |
| 121 | + /QTest 2 0 R | |
| 122 | + /Root 1 0 R | |
| 123 | + /Size 11 | |
| 124 | + /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] | |
| 125 | +>> | |
| 126 | +startxref | |
| 127 | +1043 | |
| 128 | +%%EOF | ... | ... |
qpdf/qtest/qpdf/various-updates.json
0 → 100644
| 1 | +{ | |
| 2 | + "qpdf-v2": { | |
| 3 | + "pdfversion": "2.0", | |
| 4 | + "maxobjectid": 9, | |
| 5 | + "objects": { | |
| 6 | + "obj:5 0 R": { | |
| 7 | + "value": null | |
| 8 | + }, | |
| 9 | + "obj:7 0 R": { | |
| 10 | + "value": { | |
| 11 | + "/now-π": [ | |
| 12 | + "9 0 R" | |
| 13 | + ], | |
| 14 | + "/indirect": "8 0 R", | |
| 15 | + "/strings": [ | |
| 16 | + "u:one", | |
| 17 | + "u:π" | |
| 18 | + ] | |
| 19 | + } | |
| 20 | + }, | |
| 21 | + "obj:8 0 R": { | |
| 22 | + "value": ["u:hello", "10 0 R"] | |
| 23 | + }, | |
| 24 | + "obj:9 0 R": { | |
| 25 | + "value": 3.14159 | |
| 26 | + }, | |
| 27 | + "obj:10 0 R": { | |
| 28 | + "value": "u:this is new" | |
| 29 | + }, | |
| 30 | + "trailer": { | |
| 31 | + "value": { | |
| 32 | + "/QTest": "7 0 R", | |
| 33 | + "/Root": "1 0 R", | |
| 34 | + "/Size": 9 | |
| 35 | + } | |
| 36 | + } | |
| 37 | + } | |
| 38 | + } | |
| 39 | +} | ... | ... |