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,15 +58,10 @@ Some of this documentation has drifted from the actual implementation. | ||
| 58 | 58 | ||
| 59 | Make sure pages tree repair generates warnings. | 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 | * Have a test case if possible that exercises the object description | 61 | * Have a test case if possible that exercises the object description |
| 65 | which means we need some kind of semantic error that gets caught | 62 | which means we need some kind of semantic error that gets caught |
| 66 | after creation. | 63 | after creation. |
| 67 | * Test invalid data, invalid data file | 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 | Try to never flatten pages tree. Make sure we do something reasonable | 66 | Try to never flatten pages tree. Make sure we do something reasonable |
| 72 | with pages tree repair. The problem is that if pages tree repair is | 67 | with pages tree repair. The problem is that if pages tree repair is |
| @@ -104,22 +99,20 @@ JSON to PDF: | @@ -104,22 +99,20 @@ JSON to PDF: | ||
| 104 | 99 | ||
| 105 | Have --json-input and --update-from-json. With --json-input, the json | 100 | Have --json-input and --update-from-json. With --json-input, the json |
| 106 | file must be complete, meaning all stream data, the trailer, and the | 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 | When reading a JSON string, any string that doesn't look like a name | 117 | When reading a JSON string, any string that doesn't look like a name |
| 125 | or indirect object or start with "b:" or "u:" should be considered an | 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,6 +1065,7 @@ class QPDF | ||
| 1065 | bool saw_dict; | 1065 | bool saw_dict; |
| 1066 | bool saw_data; | 1066 | bool saw_data; |
| 1067 | bool saw_datafile; | 1067 | bool saw_datafile; |
| 1068 | + bool this_stream_needs_data; | ||
| 1068 | std::vector<state_e> state_stack; | 1069 | std::vector<state_e> state_stack; |
| 1069 | std::vector<QPDFObjectHandle> object_stack; | 1070 | std::vector<QPDFObjectHandle> object_stack; |
| 1070 | std::set<QPDFObjGen> reserved; | 1071 | std::set<QPDFObjGen> reserved; |
libqpdf/QPDF_json.cc
| @@ -102,7 +102,8 @@ QPDF::JSONReactor::JSONReactor( | @@ -102,7 +102,8 @@ QPDF::JSONReactor::JSONReactor( | ||
| 102 | saw_stream(false), | 102 | saw_stream(false), |
| 103 | saw_dict(false), | 103 | saw_dict(false), |
| 104 | saw_data(false), | 104 | saw_data(false), |
| 105 | - saw_datafile(false) | 105 | + saw_datafile(false), |
| 106 | + this_stream_needs_data(false) | ||
| 106 | { | 107 | { |
| 107 | state_stack.push_back(st_initial); | 108 | state_stack.push_back(st_initial); |
| 108 | } | 109 | } |
| @@ -111,8 +112,11 @@ void | @@ -111,8 +112,11 @@ void | ||
| 111 | QPDF::JSONReactor::error(size_t offset, std::string const& msg) | 112 | QPDF::JSONReactor::error(size_t offset, std::string const& msg) |
| 112 | { | 113 | { |
| 113 | this->errors = true; | 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 | bool | 122 | bool |
| @@ -196,20 +200,22 @@ QPDF::JSONReactor::containerEnd(JSON const& value) | @@ -196,20 +200,22 @@ QPDF::JSONReactor::containerEnd(JSON const& value) | ||
| 196 | QTC::TC("qpdf", "QPDF_json stream no dict"); | 200 | QTC::TC("qpdf", "QPDF_json stream no dict"); |
| 197 | error(value.getStart(), "\"stream\" is missing \"dict\""); | 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 | QTC::TC("qpdf", "QPDF_json data datafile both or neither"); | 205 | QTC::TC("qpdf", "QPDF_json data datafile both or neither"); |
| 202 | error( | 206 | error( |
| 203 | value.getStart(), | 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 | "\"datafile\""); | 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 | } else if ((state == st_stream) || (state == st_object)) { | 221 | } else if ((state == st_stream) || (state == st_object)) { |
| @@ -320,7 +326,6 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | @@ -320,7 +326,6 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | ||
| 320 | nestedState(key, value, st_trailer); | 326 | nestedState(key, value, st_trailer); |
| 321 | this->cur_object = "trailer"; | 327 | this->cur_object = "trailer"; |
| 322 | } else if (std::regex_match(key, m, OBJ_KEY_RE)) { | 328 | } else if (std::regex_match(key, m, OBJ_KEY_RE)) { |
| 323 | - // QXXXQ remember to handle null for delete | ||
| 324 | object_stack.push_back(reserveObject(m[1].str(), m[2].str())); | 329 | object_stack.push_back(reserveObject(m[1].str(), m[2].str())); |
| 325 | nestedState(key, value, st_object_top); | 330 | nestedState(key, value, st_object_top); |
| 326 | this->cur_object = key; | 331 | this->cur_object = key; |
| @@ -347,9 +352,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | @@ -347,9 +352,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | ||
| 347 | } else if (key == "stream") { | 352 | } else if (key == "stream") { |
| 348 | this->saw_stream = true; | 353 | this->saw_stream = true; |
| 349 | nestedState(key, value, st_stream); | 354 | nestedState(key, value, st_stream); |
| 355 | + this->this_stream_needs_data = false; | ||
| 350 | if (tos.isStream()) { | 356 | if (tos.isStream()) { |
| 351 | - // QXXXQ reusing -- need QTC | 357 | + QTC::TC("qpdf", "QPDF_json updating existing stream"); |
| 352 | } else { | 358 | } else { |
| 359 | + this->this_stream_needs_data = true; | ||
| 353 | replacement = | 360 | replacement = |
| 354 | pdf.reserveStream(tos.getObjectID(), tos.getGeneration()); | 361 | pdf.reserveStream(tos.getObjectID(), tos.getGeneration()); |
| 355 | replaceObject(tos, replacement); | 362 | replaceObject(tos, replacement); |
| @@ -386,12 +393,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | @@ -386,12 +393,11 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) | ||
| 386 | throw std::logic_error("no object on stack in st_stream"); | 393 | throw std::logic_error("no object on stack in st_stream"); |
| 387 | } | 394 | } |
| 388 | auto tos = object_stack.back(); | 395 | auto tos = object_stack.back(); |
| 389 | - auto uninitialized = QPDFObjectHandle(); | ||
| 390 | if (!tos.isStream()) { | 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 | this->saw_dict = true; | 401 | this->saw_dict = true; |
| 396 | // Since a stream dictionary must be a dictionary, we can | 402 | // Since a stream dictionary must be a dictionary, we can |
| 397 | // use nestedState to transition to st_value. | 403 | // use nestedState to transition to st_value. |
| @@ -509,11 +515,12 @@ QPDF::JSONReactor::makeObject(JSON const& value) | @@ -509,11 +515,12 @@ QPDF::JSONReactor::makeObject(JSON const& value) | ||
| 509 | "JSONReactor::makeObject didn't initialize the object"); | 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 | return result; | 524 | return result; |
| 518 | } | 525 | } |
| 519 | 526 |
qpdf/qpdf.testcov
| @@ -676,3 +676,6 @@ QPDF_json ignore unknown key in object_top 0 | @@ -676,3 +676,6 @@ QPDF_json ignore unknown key in object_top 0 | ||
| 676 | QPDF_json ignore unknown key in trailer 0 | 676 | QPDF_json ignore unknown key in trailer 0 |
| 677 | QPDF_json ignore unknown key in stream 0 | 677 | QPDF_json ignore unknown key in stream 0 |
| 678 | QPDF_json non-trivial null reserved 0 | 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,5 +171,35 @@ $td->runtest("check PDF", | ||
| 171 | {$td->FILE => "a.pdf"}, | 171 | {$td->FILE => "a.pdf"}, |
| 172 | {$td->FILE => "b.pdf"}); | 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 | cleanup(); | 204 | cleanup(); |
| 175 | $td->report($n_tests); | 205 | $td->report($n_tests); |
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" | 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" | 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" | 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 | WARNING: qjson-obj-key-errors.json (trailer, offset 1152): "trailer" is missing "value" | 6 | WARNING: qjson-obj-key-errors.json (trailer, offset 1152): "trailer" is missing "value" |
| 7 | qpdf: qjson-obj-key-errors.json: errors found in JSON | 7 | qpdf: qjson-obj-key-errors.json: errors found in JSON |
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 | 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 | 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 | WARNING: qjson-stream-dict-not-dict.json: "qpdf-v2.objects.trailer" was not seen | 4 | WARNING: qjson-stream-dict-not-dict.json: "qpdf-v2.objects.trailer" was not seen |
| 5 | qpdf: qjson-stream-dict-not-dict.json: errors found in JSON | 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 | +} |