Commit 2780a1871d2603e9b273580fb7978d277832c2fc

Authored by Jay Berkenbilt
1 parent b72a38bf

Add C API for checking PDF files

ChangeLog
1 2018-02-17 Jay Berkenbilt <ejb@ql.org> 1 2018-02-17 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add qpdf_check_pdf to the "C" API. This method just attempts to
  4 + read the entire file and produce no output, making possible to
  5 + assess whether the file has any errors that qpdf can detect.
  6 +
3 * Major enhancements to handling of type errors within the qpdf 7 * Major enhancements to handling of type errors within the qpdf
4 library. This fix is intended to eliminate those annoying cases 8 library. This fix is intended to eliminate those annoying cases
5 where qpdf would exit with a message like "operation for 9 where qpdf would exit with a message like "operation for
include/qpdf/qpdf-c.h
@@ -180,6 +180,14 @@ extern &quot;C&quot; { @@ -180,6 +180,14 @@ extern &quot;C&quot; {
180 QPDF_DLL 180 QPDF_DLL
181 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value); 181 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value);
182 182
  183 + /* CHECK FUNCTIONS */
  184 +
  185 + /* Attempt to read the entire PDF file to see if there are any
  186 + * errors qpdf can detect.
  187 + */
  188 + QPDF_DLL
  189 + QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf);
  190 +
183 /* READ FUNCTIONS */ 191 /* READ FUNCTIONS */
184 192
185 /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */ 193 /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */
libqpdf/qpdf-c.cc
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 #include <qpdf/QPDFWriter.hh> 4 #include <qpdf/QPDFWriter.hh>
5 #include <qpdf/QTC.hh> 5 #include <qpdf/QTC.hh>
6 #include <qpdf/QPDFExc.hh> 6 #include <qpdf/QPDFExc.hh>
  7 +#include <qpdf/Pl_Discard.hh>
7 8
8 #include <list> 9 #include <list>
9 #include <string> 10 #include <string>
@@ -82,6 +83,15 @@ static void call_write(qpdf_data qpdf) @@ -82,6 +83,15 @@ static void call_write(qpdf_data qpdf)
82 qpdf->qpdf_writer->write(); 83 qpdf->qpdf_writer->write();
83 } 84 }
84 85
  86 +static void call_check(qpdf_data qpdf)
  87 +{
  88 + QPDFWriter w(*qpdf->qpdf);
  89 + Pl_Discard discard;
  90 + w.setOutputPipeline(&discard);
  91 + w.setDecodeLevel(qpdf_dl_all);
  92 + w.write();
  93 +}
  94 +
85 static QPDF_ERROR_CODE trap_errors(qpdf_data qpdf, void (*fn)(qpdf_data)) 95 static QPDF_ERROR_CODE trap_errors(qpdf_data qpdf, void (*fn)(qpdf_data))
86 { 96 {
87 QPDF_ERROR_CODE status = QPDF_SUCCESS; 97 QPDF_ERROR_CODE status = QPDF_SUCCESS;
@@ -236,6 +246,13 @@ char const* qpdf_get_error_message_detail(qpdf_data qpdf, qpdf_error e) @@ -236,6 +246,13 @@ char const* qpdf_get_error_message_detail(qpdf_data qpdf, qpdf_error e)
236 return e->exc->getMessageDetail().c_str(); 246 return e->exc->getMessageDetail().c_str();
237 } 247 }
238 248
  249 +QPDF_ERROR_CODE qpdf_check_pdf(qpdf_data qpdf)
  250 +{
  251 + QPDF_ERROR_CODE status = trap_errors(qpdf, &call_check);
  252 + QTC::TC("qpdf", "qpdf-c called qpdf_check_pdf");
  253 + return status;
  254 +}
  255 +
239 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value) 256 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value)
240 { 257 {
241 QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings"); 258 QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings");
qpdf/qpdf-ctest.c
@@ -484,6 +484,18 @@ static void test22(char const* infile, @@ -484,6 +484,18 @@ static void test22(char const* infile,
484 report_errors(); 484 report_errors();
485 } 485 }
486 486
  487 +static void test23(char const* infile,
  488 + char const* password,
  489 + char const* outfile,
  490 + char const* outfile2)
  491 +{
  492 + QPDF_ERROR_CODE status = 0;
  493 + qpdf_read(qpdf, infile, password);
  494 + status = qpdf_check_pdf(qpdf);
  495 + printf("status: %d\n", status);
  496 + report_errors();
  497 +}
  498 +
487 int main(int argc, char* argv[]) 499 int main(int argc, char* argv[])
488 { 500 {
489 char* p = 0; 501 char* p = 0;
@@ -546,6 +558,7 @@ int main(int argc, char* argv[]) @@ -546,6 +558,7 @@ int main(int argc, char* argv[])
546 (n == 20) ? test20 : 558 (n == 20) ? test20 :
547 (n == 21) ? test21 : 559 (n == 21) ? test21 :
548 (n == 22) ? test22 : 560 (n == 22) ? test22 :
  561 + (n == 23) ? test23 :
549 0); 562 0);
550 563
551 if (fn == 0) 564 if (fn == 0)
qpdf/qpdf.testcov
@@ -333,3 +333,4 @@ QPDFObjectHandle dictionary ignoring removeKey 0 @@ -333,3 +333,4 @@ QPDFObjectHandle dictionary ignoring removeKey 0
333 QPDFObjectHandle dictionary ignoring removereplace 0 333 QPDFObjectHandle dictionary ignoring removereplace 0
334 QPDFObjectHandle numeric non-numeric 0 334 QPDFObjectHandle numeric non-numeric 0
335 QPDFObjectHandle erase array bounds 0 335 QPDFObjectHandle erase array bounds 0
  336 +qpdf-c called qpdf_check_pdf 0
qpdf/qtest/qpdf.test
@@ -2495,6 +2495,21 @@ foreach my $d (@enc_key) @@ -2495,6 +2495,21 @@ foreach my $d (@enc_key)
2495 2495
2496 show_ntests(); 2496 show_ntests();
2497 # ---------- 2497 # ----------
  2498 +$td->notify("--- Check from C API ---");
  2499 +my @c_check_types = qw(warn clear);
  2500 +$n_tests += scalar(@c_check_types);
  2501 +
  2502 +foreach my $i (@c_check_types)
  2503 +{
  2504 + $td->runtest("C check $i",
  2505 + {$td->COMMAND => "qpdf-ctest 23 c-check-$i-in.pdf '' -"},
  2506 + {$td->FILE => "c-check-$i.out",
  2507 + $td->EXIT_STATUS => 0},
  2508 + $td->NORMALIZE_NEWLINES);
  2509 +}
  2510 +
  2511 +show_ntests();
  2512 +# ----------
2498 $td->notify("--- Content Preservation Tests ---"); 2513 $td->notify("--- Content Preservation Tests ---");
2499 # $n_tests incremented below 2514 # $n_tests incremented below
2500 2515
qpdf/qtest/qpdf/c-check-clear-in.pdf 0 → 100644
  1 +%PDF-1.3
  2 +1 0 obj
  3 +<<
  4 + /Type /Catalog
  5 + /Pages 2 0 R
  6 +>>
  7 +endobj
  8 +
  9 +2 0 obj
  10 +<<
  11 + /Type /Pages
  12 + /Kids [
  13 + 3 0 R
  14 + ]
  15 + /Count 1
  16 +>>
  17 +endobj
  18 +
  19 +3 0 obj
  20 +<<
  21 + /Type /Page
  22 + /Parent 2 0 R
  23 + /MediaBox [0 0 612 792]
  24 + /Contents 4 0 R
  25 + /Resources <<
  26 + /ProcSet 5 0 R
  27 + /Font <<
  28 + /F1 6 0 R
  29 + >>
  30 + >>
  31 +>>
  32 +endobj
  33 +
  34 +4 0 obj
  35 +<<
  36 + /Length 44
  37 +>>
  38 +stream
  39 +BT
  40 + /F1 24 Tf
  41 + 72 720 Td
  42 + (Potato) Tj
  43 +ET
  44 +endstream
  45 +endobj
  46 +
  47 +5 0 obj
  48 +[
  49 + /PDF
  50 + /Text
  51 +]
  52 +endobj
  53 +
  54 +6 0 obj
  55 +<<
  56 + /Type /Font
  57 + /Subtype /Type1
  58 + /Name /F1
  59 + /BaseFont /Helvetica
  60 + /Encoding /WinAnsiEncoding
  61 +>>
  62 +endobj
  63 +
  64 +xref
  65 +0 7
  66 +0000000000 65535 f
  67 +0000000009 00000 n
  68 +0000000063 00000 n
  69 +0000000135 00000 n
  70 +0000000307 00000 n
  71 +0000000403 00000 n
  72 +0000000438 00000 n
  73 +trailer <<
  74 + /Size 7
  75 + /Root 1 0 R
  76 +>>
  77 +startxref
  78 +556
  79 +%%EOF
qpdf/qtest/qpdf/c-check-clear.out 0 → 100644
  1 +status: 0
qpdf/qtest/qpdf/c-check-warn-in.pdf 0 → 100644
  1 +%PDF-1.3
  2 +1 0 obj
  3 +<<
  4 + /Type /Catalog
  5 + /Pages 2 0 R
  6 +>>
  7 +endobj
  8 +
  9 +2 0 obj
  10 +<<
  11 + /Type /Pages
  12 + /Kids [
  13 + 3 0 R
  14 + ]
  15 + /Count 1
  16 +>>
  17 +endobj
  18 +
  19 +3 0 obj
  20 +<<
  21 + /Type /Page
  22 + /Parent 2 0 R
  23 + /MediaBox [0 0 612 792]
  24 + /Contents 4 0 R
  25 + /Resources <<
  26 + /ProcSet 5 0 R
  27 + /Font <<
  28 + /F1 6 0 R
  29 + >>
  30 + >>
  31 +>>
  32 +endobj
  33 +
  34 +4 0 obj
  35 +<<
  36 + /Length 44
  37 +>>
  38 +stream
  39 +BT
  40 + /F1 24 Tf
  41 + 72 720 Td
  42 + (Potato) Tj
  43 +ET
  44 +endstream
  45 +endobj
  46 +
  47 +5 0 obj
  48 +[
  49 + /PDF
  50 + /Text
  51 +]
  52 +endobj
  53 +
  54 +6 0 obj
  55 +<<
  56 + /Type /Font
  57 + /Subtype /Type1
  58 + /Name /F1
  59 + /BaseFont /Helvetica
  60 + /Encoding /WinAnsiEncoding
  61 +>>
  62 +endobj
  63 +
  64 +xref
  65 +0 7
  66 +0000000000 65535 f
  67 +0000000009 00000 n
  68 +0000000063 00000 n
  69 +0000000135 00000 n
  70 +0000000307 00000 n
  71 +0000000403 00000 n
  72 +0000000438 00000 n
  73 +trailer <<
  74 + /Size 7
  75 + /Root 1 0 R
  76 +>>
  77 +startxref
  78 +1556
  79 +%%EOF
qpdf/qtest/qpdf/c-check-warn.out 0 → 100644
  1 +WARNING: c-check-warn-in.pdf: file is damaged
  2 +WARNING: c-check-warn-in.pdf (offset 1556): xref not found
  3 +WARNING: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table
  4 +status: 1
  5 +warning: c-check-warn-in.pdf: file is damaged
  6 + code: 5
  7 + file: c-check-warn-in.pdf
  8 + pos : 0
  9 + text: file is damaged
  10 +warning: c-check-warn-in.pdf (offset 1556): xref not found
  11 + code: 5
  12 + file: c-check-warn-in.pdf
  13 + pos : 1556
  14 + text: xref not found
  15 +warning: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table
  16 + code: 5
  17 + file: c-check-warn-in.pdf
  18 + pos : 0
  19 + text: Attempting to reconstruct cross-reference table