diff --git a/ChangeLog b/ChangeLog index 1d551461..6c9e581e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2018-02-17 Jay Berkenbilt + * Add qpdf_check_pdf to the "C" API. This method just attempts to + read the entire file and produce no output, making possible to + assess whether the file has any errors that qpdf can detect. + * Major enhancements to handling of type errors within the qpdf library. This fix is intended to eliminate those annoying cases where qpdf would exit with a message like "operation for diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h index 4773809e..a6002a92 100644 --- a/include/qpdf/qpdf-c.h +++ b/include/qpdf/qpdf-c.h @@ -180,6 +180,14 @@ extern "C" { QPDF_DLL void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value); + /* CHECK FUNCTIONS */ + + /* Attempt to read the entire PDF file to see if there are any + * errors qpdf can detect. + */ + QPDF_DLL + QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf); + /* READ FUNCTIONS */ /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */ diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index a9883d32..1cc1e2b1 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -82,6 +83,15 @@ static void call_write(qpdf_data qpdf) qpdf->qpdf_writer->write(); } +static void call_check(qpdf_data qpdf) +{ + QPDFWriter w(*qpdf->qpdf); + Pl_Discard discard; + w.setOutputPipeline(&discard); + w.setDecodeLevel(qpdf_dl_all); + w.write(); +} + static QPDF_ERROR_CODE trap_errors(qpdf_data qpdf, void (*fn)(qpdf_data)) { QPDF_ERROR_CODE status = QPDF_SUCCESS; @@ -236,6 +246,13 @@ char const* qpdf_get_error_message_detail(qpdf_data qpdf, qpdf_error e) return e->exc->getMessageDetail().c_str(); } +QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf) +{ + QPDF_ERROR_CODE status = trap_errors(qpdf, &call_check); + QTC::TC("qpdf", "qpdf-c called qpdf_check_pdf"); + return status; +} + void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value) { QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings"); diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c index f7bfb5c4..8b9c36ce 100644 --- a/qpdf/qpdf-ctest.c +++ b/qpdf/qpdf-ctest.c @@ -484,6 +484,18 @@ static void test22(char const* infile, report_errors(); } +static void test23(char const* infile, + char const* password, + char const* outfile, + char const* outfile2) +{ + QPDF_ERROR_CODE status = 0; + qpdf_read(qpdf, infile, password); + status = qpdf_check_pdf(qpdf); + printf("status: %d\n", status); + report_errors(); +} + int main(int argc, char* argv[]) { char* p = 0; @@ -546,6 +558,7 @@ int main(int argc, char* argv[]) (n == 20) ? test20 : (n == 21) ? test21 : (n == 22) ? test22 : + (n == 23) ? test23 : 0); if (fn == 0) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 67cbfe7f..7e60953e 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -333,3 +333,4 @@ QPDFObjectHandle dictionary ignoring removeKey 0 QPDFObjectHandle dictionary ignoring removereplace 0 QPDFObjectHandle numeric non-numeric 0 QPDFObjectHandle erase array bounds 0 +qpdf-c called qpdf_check_pdf 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index bd341079..6854e651 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -2493,6 +2493,21 @@ foreach my $d (@enc_key) $td->NORMALIZE_NEWLINES); } +show_ntests(); +# ---------- +$td->notify("--- Check from C API ---"); +my @c_check_types = qw(warn clear); +$n_tests += scalar(@c_check_types); + +foreach my $i (@c_check_types) +{ + $td->runtest("C check $i", + {$td->COMMAND => "qpdf-ctest 23 c-check-$i-in.pdf '' -"}, + {$td->FILE => "c-check-$i.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +} + show_ntests(); # ---------- $td->notify("--- Content Preservation Tests ---"); diff --git a/qpdf/qtest/qpdf/c-check-clear-in.pdf b/qpdf/qtest/qpdf/c-check-clear-in.pdf new file mode 100644 index 00000000..a7e01f91 --- /dev/null +++ b/qpdf/qtest/qpdf/c-check-clear-in.pdf @@ -0,0 +1,79 @@ +%PDF-1.3 +1 0 obj +<< + /Type /Catalog + /Pages 2 0 R +>> +endobj + +2 0 obj +<< + /Type /Pages + /Kids [ + 3 0 R + ] + /Count 1 +>> +endobj + +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] + /Contents 4 0 R + /Resources << + /ProcSet 5 0 R + /Font << + /F1 6 0 R + >> + >> +>> +endobj + +4 0 obj +<< + /Length 44 +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +[ + /PDF + /Text +] +endobj + +6 0 obj +<< + /Type /Font + /Subtype /Type1 + /Name /F1 + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding +>> +endobj + +xref +0 7 +0000000000 65535 f +0000000009 00000 n +0000000063 00000 n +0000000135 00000 n +0000000307 00000 n +0000000403 00000 n +0000000438 00000 n +trailer << + /Size 7 + /Root 1 0 R +>> +startxref +556 +%%EOF diff --git a/qpdf/qtest/qpdf/c-check-clear.out b/qpdf/qtest/qpdf/c-check-clear.out new file mode 100644 index 00000000..934014b3 --- /dev/null +++ b/qpdf/qtest/qpdf/c-check-clear.out @@ -0,0 +1 @@ +status: 0 diff --git a/qpdf/qtest/qpdf/c-check-warn-in.pdf b/qpdf/qtest/qpdf/c-check-warn-in.pdf new file mode 100644 index 00000000..e8a7042c --- /dev/null +++ b/qpdf/qtest/qpdf/c-check-warn-in.pdf @@ -0,0 +1,79 @@ +%PDF-1.3 +1 0 obj +<< + /Type /Catalog + /Pages 2 0 R +>> +endobj + +2 0 obj +<< + /Type /Pages + /Kids [ + 3 0 R + ] + /Count 1 +>> +endobj + +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] + /Contents 4 0 R + /Resources << + /ProcSet 5 0 R + /Font << + /F1 6 0 R + >> + >> +>> +endobj + +4 0 obj +<< + /Length 44 +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +[ + /PDF + /Text +] +endobj + +6 0 obj +<< + /Type /Font + /Subtype /Type1 + /Name /F1 + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding +>> +endobj + +xref +0 7 +0000000000 65535 f +0000000009 00000 n +0000000063 00000 n +0000000135 00000 n +0000000307 00000 n +0000000403 00000 n +0000000438 00000 n +trailer << + /Size 7 + /Root 1 0 R +>> +startxref +1556 +%%EOF diff --git a/qpdf/qtest/qpdf/c-check-warn.out b/qpdf/qtest/qpdf/c-check-warn.out new file mode 100644 index 00000000..40e8eb35 --- /dev/null +++ b/qpdf/qtest/qpdf/c-check-warn.out @@ -0,0 +1,19 @@ +WARNING: c-check-warn-in.pdf: file is damaged +WARNING: c-check-warn-in.pdf (offset 1556): xref not found +WARNING: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table +status: 1 +warning: c-check-warn-in.pdf: file is damaged + code: 5 + file: c-check-warn-in.pdf + pos : 0 + text: file is damaged +warning: c-check-warn-in.pdf (offset 1556): xref not found + code: 5 + file: c-check-warn-in.pdf + pos : 1556 + text: xref not found +warning: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table + code: 5 + file: c-check-warn-in.pdf + pos : 0 + text: Attempting to reconstruct cross-reference table