Commit 2780a1871d2603e9b273580fb7978d277832c2fc

Authored by Jay Berkenbilt
1 parent b72a38bf

Add C API for checking PDF files

ChangeLog
1 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 7 * Major enhancements to handling of type errors within the qpdf
4 8 library. This fix is intended to eliminate those annoying cases
5 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 180 QPDF_DLL
181 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 191 /* READ FUNCTIONS */
184 192  
185 193 /* READ PARAMETER FUNCTIONS -- must be called before qpdf_read */
... ...
libqpdf/qpdf-c.cc
... ... @@ -4,6 +4,7 @@
4 4 #include <qpdf/QPDFWriter.hh>
5 5 #include <qpdf/QTC.hh>
6 6 #include <qpdf/QPDFExc.hh>
  7 +#include <qpdf/Pl_Discard.hh>
7 8  
8 9 #include <list>
9 10 #include <string>
... ... @@ -82,6 +83,15 @@ static void call_write(qpdf_data qpdf)
82 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 95 static QPDF_ERROR_CODE trap_errors(qpdf_data qpdf, void (*fn)(qpdf_data))
86 96 {
87 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 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 256 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value)
240 257 {
241 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 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 499 int main(int argc, char* argv[])
488 500 {
489 501 char* p = 0;
... ... @@ -546,6 +558,7 @@ int main(int argc, char* argv[])
546 558 (n == 20) ? test20 :
547 559 (n == 21) ? test21 :
548 560 (n == 22) ? test22 :
  561 + (n == 23) ? test23 :
549 562 0);
550 563  
551 564 if (fn == 0)
... ...
qpdf/qpdf.testcov
... ... @@ -333,3 +333,4 @@ QPDFObjectHandle dictionary ignoring removeKey 0
333 333 QPDFObjectHandle dictionary ignoring removereplace 0
334 334 QPDFObjectHandle numeric non-numeric 0
335 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 2495  
2496 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 2513 $td->notify("--- Content Preservation Tests ---");
2499 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
... ...