From b48a0ff0e8e1861884b2dac62d98d39f8e194086 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 5 Feb 2022 08:50:39 -0500 Subject: [PATCH] Add qpdf_empty_pdf to C API --- ChangeLog | 2 ++ TODO | 3 --- include/qpdf/qpdf-c.h | 13 ++++++++++--- libqpdf/qpdf-c.cc | 8 ++++++++ qpdf/qpdf-ctest.c | 14 ++++++++++++++ qpdf/qpdf.testcov | 1 + qpdf/qtest/qpdf.test | 10 +++++++++- qpdf/qtest/qpdf/c-empty.pdf | 17 +++++++++++++++++ 8 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 qpdf/qtest/qpdf/c-empty.pdf diff --git a/ChangeLog b/ChangeLog index 3bc733e0..7b40e1c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2022-02-05 Jay Berkenbilt + * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf() + * Add comments letting people know that the version string returned by QPDF::QPDFVersion and qpdf_get_qpdf_version is static. diff --git a/TODO b/TODO index 8166f090..9bbaecc7 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,6 @@ 10.6 ==== -* Expose emptyPDF to the C API. Ensure that qpdf_get_qpdf_version is - always static. - * Consider doing one big commit to reformat the entire codebase using clang-format or a similar tool. Consider using blame.ignoreRevsFile or similar (or otherwise study git blame to see how to minimize the diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h index 5a0595b2..982f0c90 100644 --- a/include/qpdf/qpdf-c.h +++ b/include/qpdf/qpdf-c.h @@ -178,9 +178,9 @@ extern "C" { char const* qpdf_get_qpdf_version(); /* Returns dynamically allocated qpdf_data pointer; must be freed - * by calling qpdf_cleanup. You must call qpdf_read or one of the - * other qpdf_read_* functions before calling any function that - * would need to operate on the PDF file. + * by calling qpdf_cleanup. You must call qpdf_read, one of the + * other qpdf_read_* functions, or qpdf_empty_pdf before calling + * any function that would need to operate on the PDF file. */ QPDF_DLL qpdf_data qpdf_init(); @@ -289,6 +289,13 @@ extern "C" { unsigned long long size, char const* password); + /* Calling qpdf_empty_pdf initializes this qpdf object with an + * empty PDF, making it possible to create a PDF from scratch + * using the C API. Added in 10.6. + */ + QPDF_DLL + QPDF_ERROR_CODE qpdf_empty_pdf(qpdf_data qpdf); + /* Read functions below must be called after qpdf_read or * qpdf_read_memory. */ diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index f03ed845..8ca8fb42 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -356,6 +356,14 @@ QPDF_ERROR_CODE qpdf_read_memory(qpdf_data qpdf, return status; } +QPDF_ERROR_CODE qpdf_empty_pdf(qpdf_data qpdf) +{ + qpdf->filename = "empty PDF"; + qpdf->qpdf->emptyPDF(); + QTC::TC("qpdf", "qpdf-c called qpdf_empty_pdf"); + return QPDF_SUCCESS; +} + char const* qpdf_get_pdf_version(qpdf_data qpdf) { QTC::TC("qpdf", "qpdf-c called qpdf_get_pdf_version"); diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c index 414c0eaa..502cede9 100644 --- a/qpdf/qpdf-ctest.c +++ b/qpdf/qpdf-ctest.c @@ -1242,6 +1242,19 @@ static void test40(char const* infile, report_errors(); } +static void test41(char const* infile, + char const* password, + char const* outfile, + char const* xarg) +{ + /* Empty PDF -- infile is ignored*/ + assert(qpdf_empty_pdf(qpdf) == 0); + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_write(qpdf); + report_errors(); +} + int main(int argc, char* argv[]) { char* p = 0; @@ -1322,6 +1335,7 @@ int main(int argc, char* argv[]) (n == 38) ? test38 : (n == 39) ? test39 : (n == 40) ? test40 : + (n == 41) ? test41 : 0); if (fn == 0) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 1e0f336e..77ef2fc9 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -639,3 +639,4 @@ QPDFJob json encrypt no key length 0 QPDFJob json encrypt duplicate key length 0 QPDFJob json encrypt missing password 0 QPDFJob json pages no file 0 +qpdf-c called qpdf_empty_pdf 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index bf386168..b211f33f 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -3553,7 +3553,7 @@ my @capi = ( [8, 'no original object ids'], [9, 'uncompressed streams'], ); -$n_tests += (2 * @capi) + 3; +$n_tests += (2 * @capi) + 5; foreach my $d (@capi) { my ($n, $description) = @$d; @@ -3590,6 +3590,14 @@ $td->runtest("write damaged", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); +$td->runtest("empty PDF", + {$td->COMMAND => "qpdf-ctest 41 - '' a.pdf"}, + {$td->STRING => "C test 41 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "c-empty.pdf"}); + show_ntests(); # ---------- $td->notify("--- Deterministic ID Tests ---"); diff --git a/qpdf/qtest/qpdf/c-empty.pdf b/qpdf/qtest/qpdf/c-empty.pdf new file mode 100644 index 00000000..a60e8169 --- /dev/null +++ b/qpdf/qtest/qpdf/c-empty.pdf @@ -0,0 +1,17 @@ +%PDF-1.3 +%¿÷¢þ +1 0 obj +<< /Pages 2 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Count 0 /Kids [ ] /Type /Pages >> +endobj +xref +0 3 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +trailer << /Root 1 0 R /Size 3 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> +startxref +117 +%%EOF