diff --git a/libqpdf/QPDFPageDocumentHelper.cc b/libqpdf/QPDFPageDocumentHelper.cc index 59189d6..12841ac 100644 --- a/libqpdf/QPDFPageDocumentHelper.cc +++ b/libqpdf/QPDFPageDocumentHelper.cc @@ -66,7 +66,7 @@ QPDFPageDocumentHelper::flattenAnnotations(int required_flags, int forbidden_fla for (auto& ph: getAllPages()) { QPDFObjectHandle resources = ph.getAttribute("/Resources", true); if (!resources.isDictionary()) { - QTC::TC("qpdf", "QPDFPageDocumentHelper flatten resources missing or invalid"); + // As of #1521, this should be impossible unless a user inserted an invalid page. resources = ph.getObjectHandle().replaceKeyAndGetNew( "/Resources", QPDFObjectHandle::newDictionary()); } diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index b3564ef..16e28ae 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -158,10 +158,38 @@ QPDF::getAllPagesInternal( QPDFObjectHandle::newArray(QPDFObjectHandle::Rectangle(0, 0, 612, 792))); ++errors; } - if (!resources && !kid.getKey("/Resources").isDictionary()) { - // Consider adding an information message - ++errors; + if (!resources) { + auto res = kid.getKey("/Resources"); + + if (!res.isDictionary()) { + ++errors; + kid.warn( + "kid " + std::to_string(i) + + " (from 0) Resources is missing or invalid; repairing"); + kid.replaceKey("/Resources", QPDFObjectHandle::newDictionary()); + } } + auto annots = kid.getKey("/Annots"); + if (!annots.null()) { + if (!annots.isArray()) { + kid.warn( + "kid " + std::to_string(i) + " (from 0) Annots is not an array; removing"); + kid.removeKey("/Annots"); + ++errors; + } else { + QPDFObjGen::set seen_annots; + for (auto& annot: annots.as_array()) { + if (!seen_annots.add(annot)) { + kid.warn( + "kid " + std::to_string(i) + + " (from 0) Annots has duplicate entry for annotation " + + annot.id_gen().unparse(' ')); + ++errors; + } + } + } + } + if (!seen.add(kid)) { // Make a copy of the page. This does the same as shallowCopyPage in // QPDFPageObjectHelper. diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index e39e04f..f9d7298 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -674,7 +674,6 @@ QPDFPageObjectHelper copied fallback 0 QPDFPageObjectHelper used fallback without copying 0 QPDF skipping cache for known unchecked object 0 QPDF fix dangling triggered xref reconstruction 0 -QPDFPageDocumentHelper flatten resources missing or invalid 0 QPDF recover xref stream 0 QPDFJob misplaced page range 0 QPDFJob duplicated range 0 diff --git a/qpdf/qtest/form-xobject.test b/qpdf/qtest/form-xobject.test index 8ae5da9..6417849 100644 --- a/qpdf/qtest/form-xobject.test +++ b/qpdf/qtest/form-xobject.test @@ -96,7 +96,7 @@ $td->runtest("overlay on page with no resources", {$td->COMMAND => "qpdf --deterministic-id page-with-no-resources.pdf" . " --overlay minimal.pdf -- a.pdf"}, - {$td->STRING => "", $td->EXIT_STATUS => 0}, + {$td->FILE => "page-with-no-resources.out", $td->EXIT_STATUS => 3}, $td->NORMALIZE_NEWLINES); $td->runtest("check overlay with no resources output", {$td->COMMAND => "qpdf-test-compare a.pdf overlay-no-resources.pdf"}, diff --git a/qpdf/qtest/many-nulls.test b/qpdf/qtest/many-nulls.test index 26ce5f8..87ded07 100644 --- a/qpdf/qtest/many-nulls.test +++ b/qpdf/qtest/many-nulls.test @@ -27,7 +27,7 @@ $td->runtest("compare output", {$td->FILE => "many-nulls.pdf", $td->EXIT_STATUS => 0}); $td->runtest("run check file", {$td->COMMAND => "qpdf --check a.pdf"}, - {$td->FILE => "many-nulls.out", $td->EXIT_STATUS => 0}, + {$td->FILE => "many-nulls.out", $td->EXIT_STATUS => 3}, $td->NORMALIZE_NEWLINES); $td->runtest("copy sparse array", {$td->COMMAND => "test_driver 97 many-nulls.pdf"}, diff --git a/qpdf/qtest/page-errors.test b/qpdf/qtest/page-errors.test index fdda4bc..d09b8e1 100644 --- a/qpdf/qtest/page-errors.test +++ b/qpdf/qtest/page-errors.test @@ -29,7 +29,7 @@ $td->runtest("check output", {$td->FILE => "page-missing-mediabox-out.pdf"}); $td->runtest("handle page with inherited MediaBox", {$td->COMMAND => "qpdf --static-id --empty --pages page-inherit-mediabox.pdf -- a.pdf"}, - {$td->STRING => "", $td->EXIT_STATUS => 0}, + {$td->FILE => "page-inherit-mediabox.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); $td->runtest("check output", {$td->COMMAND => "qpdf-test-compare a.pdf page-inherit-mediabox-out.pdf"}, diff --git a/qpdf/qtest/qpdf/annotation-no-resources-warn.out b/qpdf/qtest/qpdf/annotation-no-resources-warn.out new file mode 100644 index 0000000..13eef6a --- /dev/null +++ b/qpdf/qtest/qpdf/annotation-no-resources-warn.out @@ -0,0 +1,2 @@ +WARNING: annotation-no-resources.pdf, object 7 0 at offset 1526: kid 0 (from 0) Resources is missing or invalid; repairing +qpdf: operation succeeded with warnings; resulting file may have some problems diff --git a/qpdf/qtest/qpdf/issue-449.out b/qpdf/qtest/qpdf/issue-449.out index cd21280..b4ac51e 100644 --- a/qpdf/qtest/qpdf/issue-449.out +++ b/qpdf/qtest/qpdf/issue-449.out @@ -1,3 +1,5 @@ WARNING: issue-449.pdf, object 3 0 at offset 139: kid 0 (from 0) MediaBox is undefined; setting to letter / ANSI A +WARNING: issue-449.pdf, object 3 0 at offset 139: kid 0 (from 0) Resources is missing or invalid; repairing WARNING: issue-449.pdf, object 4 0 at offset 211: kid 1 (from 0) MediaBox is undefined; setting to letter / ANSI A +WARNING: issue-449.pdf, object 4 0 at offset 211: kid 1 (from 0) Resources is missing or invalid; repairing test 69 done diff --git a/qpdf/qtest/qpdf/many-nulls.out b/qpdf/qtest/qpdf/many-nulls.out index f95a8ec..400b9b8 100644 --- a/qpdf/qtest/qpdf/many-nulls.out +++ b/qpdf/qtest/qpdf/many-nulls.out @@ -2,5 +2,5 @@ checking a.pdf PDF Version: 1.5 File is not encrypted File is not linearized -No syntax or stream encoding errors found; the file may still contain -errors that qpdf cannot detect +WARNING: a.pdf object stream 1, object 5 0 at offset 2000188: kid 0 (from 0) Resources is missing or invalid; repairing +qpdf: operation succeeded with warnings diff --git a/qpdf/qtest/qpdf/overlay-no-resources.out b/qpdf/qtest/qpdf/overlay-no-resources.out new file mode 100644 index 0000000..ab6aa4c --- /dev/null +++ b/qpdf/qtest/qpdf/overlay-no-resources.out @@ -0,0 +1,2 @@ +WARNING: annotation-no-resources.pdf, object 7 0 at offset 1526: kid 0 (from 0) Resources is missing; repairing +qpdf: operation succeeded with warnings; resulting file may have some problems diff --git a/qpdf/qtest/qpdf/overlay-no-resources.pdf b/qpdf/qtest/qpdf/overlay-no-resources.pdf index 620bc7a..0beb651 100644 --- a/qpdf/qtest/qpdf/overlay-no-resources.pdf +++ b/qpdf/qtest/qpdf/overlay-no-resources.pdf diff --git a/qpdf/qtest/qpdf/page-inherit-mediabox-out.pdf b/qpdf/qtest/qpdf/page-inherit-mediabox-out.pdf index 67986cf..fbbf27b 100644 --- a/qpdf/qtest/qpdf/page-inherit-mediabox-out.pdf +++ b/qpdf/qtest/qpdf/page-inherit-mediabox-out.pdf diff --git a/qpdf/qtest/qpdf/page-inherit-mediabox.out b/qpdf/qtest/qpdf/page-inherit-mediabox.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/qpdf/qtest/qpdf/page-inherit-mediabox.out diff --git a/qpdf/qtest/qpdf/page-inherit-mediabox.pdf b/qpdf/qtest/qpdf/page-inherit-mediabox.pdf index b098ffb..cbc6a13 100644 --- a/qpdf/qtest/qpdf/page-inherit-mediabox.pdf +++ b/qpdf/qtest/qpdf/page-inherit-mediabox.pdf @@ -25,6 +25,8 @@ endobj 612 792 ] + /Resources << + >> /Type /Pages >> endobj @@ -163,22 +165,22 @@ xref 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000308 00000 n -0000000537 00000 n -0000000626 00000 n -0000000871 00000 n -0000000970 00000 n -0000001016 00000 n -0000001161 00000 n -0000001246 00000 n -0000001347 00000 n -0000001395 00000 n -0000001542 00000 n +0000000329 00000 n +0000000558 00000 n +0000000647 00000 n +0000000892 00000 n +0000000991 00000 n +0000001037 00000 n +0000001182 00000 n +0000001267 00000 n +0000001368 00000 n +0000001416 00000 n +0000001563 00000 n trailer << /Root 1 0 R /Size 14 /ID [<963eac977ec4dfaf9fbcb48aae925c7a>] >> startxref -1578 +1599 %%EOF diff --git a/qpdf/qtest/qpdf/page-missing-mediabox-out.pdf b/qpdf/qtest/qpdf/page-missing-mediabox-out.pdf index 8013e36..5444563 100644 --- a/qpdf/qtest/qpdf/page-missing-mediabox-out.pdf +++ b/qpdf/qtest/qpdf/page-missing-mediabox-out.pdf diff --git a/qpdf/qtest/qpdf/page-missing-mediabox.out b/qpdf/qtest/qpdf/page-missing-mediabox.out index 91e8570..5ab9ef7 100644 --- a/qpdf/qtest/qpdf/page-missing-mediabox.out +++ b/qpdf/qtest/qpdf/page-missing-mediabox.out @@ -1,2 +1,3 @@ WARNING: page-no-content.pdf, object 4 0 at offset 288: kid 1 (from 0) MediaBox is undefined; setting to letter / ANSI A +WARNING: page-no-content.pdf, object 4 0 at offset 288: kid 1 (from 0) Resources is missing or invalid; repairing qpdf: operation succeeded with warnings; resulting file may have some problems diff --git a/qpdf/qtest/qpdf/page-no-content.out b/qpdf/qtest/qpdf/page-no-content.out index 73f078c..b9e5f65 100644 --- a/qpdf/qtest/qpdf/page-no-content.out +++ b/qpdf/qtest/qpdf/page-no-content.out @@ -1,4 +1,5 @@ WARNING: page-no-content.pdf, object 4 0 at offset 288: kid 1 (from 0) MediaBox is undefined; setting to letter / ANSI A +WARNING: page-no-content.pdf, object 4 0 at offset 288: kid 1 (from 0) Resources is missing or invalid; repairing page 1: 3 0 R content: 6 0 R diff --git a/qpdf/qtest/qpdf/page-with-no-resources.out b/qpdf/qtest/qpdf/page-with-no-resources.out new file mode 100644 index 0000000..62cf308 --- /dev/null +++ b/qpdf/qtest/qpdf/page-with-no-resources.out @@ -0,0 +1,2 @@ +WARNING: page-with-no-resources.pdf, object 3 0 at offset 133: kid 0 (from 0) Resources is missing or invalid; repairing +qpdf: operation succeeded with warnings; resulting file may have some problems