diff --git a/include/qpdf/qpdfjob-c.h b/include/qpdf/qpdfjob-c.h index 8408f0d6..a251bd93 100644 --- a/include/qpdf/qpdfjob-c.h +++ b/include/qpdf/qpdfjob-c.h @@ -32,6 +32,7 @@ */ #include +#include #include #include #ifndef QPDF_NO_WCHAR_T @@ -138,6 +139,28 @@ extern "C" { QPDF_DLL int qpdfjob_run(qpdfjob_handle j); + /* The following two functions allow a job to be run in two stages - + * creation of a qpdf_data object and writing of the qpdf_data object. This + * allows the qpdf_data object to be modified prior to writing it out. See + * examples/qpdfjob-remove-annotations for a C++ illustration of its use. + * + * This function wraps QPDFJob::createQPDF. It runs the first stage of the + * job. A nullptr is returned if the job did not produce any pdf file to be + * written. + */ + QPDF_DLL + qpdf_data qpdfjob_create_qpdf(qpdfjob_handle j); + + /* This function wraps QPDFJob::writeQPDF. It returns the error code that + * qpdf would return with the equivalent command-line invocation. Exit code + * values are defined in Constants.h in the qpdf_exit_code_e type. NOTE it + * is the callers responsibility to clean up the resources associated + * qpdf_data object by calling qpdf_cleanup after the call to + * qpdfjob_write_qpdf. + */ + QPDF_DLL + int qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf); + /* Allow specification of a custom progress reporter. The progress * reporter is only used if progress is otherwise requested (with * the --progress option or "progress": "" in the JSON). diff --git a/libqpdf/qpdfjob-c.cc b/libqpdf/qpdfjob-c.cc index 889afec6..ddb33349 100644 --- a/libqpdf/qpdfjob-c.cc +++ b/libqpdf/qpdfjob-c.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -98,6 +99,30 @@ qpdfjob_run(qpdfjob_handle j) }); } +qpdf_data +qpdfjob_create_qpdf(qpdfjob_handle j) +{ + QUtil::setLineBuf(stdout); + try { + auto qpdf = j->j.createQPDF(); + return qpdf ? new _qpdf_data(std::move(qpdf)) : nullptr; + } catch (std::exception& e) { + *j->j.getLogger()->getError() + << j->j.getMessagePrefix() << ": " << e.what() << "\n"; + } + return nullptr; +} + +int +qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf) +{ + QUtil::setLineBuf(stdout); + return wrap_qpdfjob(j, [qpdf](qpdfjob_handle jh) { + jh->j.writeQPDF(*(qpdf->qpdf)); + return jh->j.getExitCode(); + }); +} + static int run_with_handle(std::function fn) { diff --git a/qpdf/qpdfjob-ctest.c b/qpdf/qpdfjob-ctest.c index 708d5fa6..31f22d28 100644 --- a/qpdf/qpdfjob-ctest.c +++ b/qpdf/qpdfjob-ctest.c @@ -97,6 +97,33 @@ run_tests() assert(qpdfjob_run(j) == 2); qpdfjob_cleanup(&j); printf("json error test passed\n"); + + /* qpdfjob_create_qpdf and qpdfjob_write_qpdf test */ + argv[0] = "qpdfjob"; + argv[1] = "minimal.pdf"; + argv[2] = "d.pdf"; + argv[3] = "--deterministic-id"; + argv[4] = "--progress"; + argv[5] = NULL; + j = qpdfjob_init(); + assert(qpdfjob_initialize_from_argv(j, argv) == 0); + qpdf_data qpdf = qpdfjob_create_qpdf(j); + assert(qpdfjob_write_qpdf(j, qpdf) == 0); + qpdf_cleanup(&qpdf); + qpdfjob_cleanup(&j); + + /* Try to open a missing file to test case of QPDFJob::createQPDF returning + * nullptr. + */ + argv[0] = "qpdfjob"; + argv[1] = "m.pdf"; + argv[2] = "--check"; + argv[3] = NULL; + j = qpdfjob_init(); + assert(qpdfjob_initialize_from_argv(j, argv) == 0); + assert(qpdfjob_create_qpdf(j) == NULL); + qpdfjob_cleanup(&j); + printf("qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed\n"); } int diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest.out b/qpdf/qtest/qpdf/qpdfjob-ctest.out index 1778e70a..125e6257 100644 --- a/qpdf/qtest/qpdf/qpdfjob-ctest.out +++ b/qpdf/qtest/qpdf/qpdfjob-ctest.out @@ -9,3 +9,8 @@ json warn test passed |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| json error test passed +qpdfjob: d.pdf: write progress: 0% +....other write progress.... +qpdfjob: d.pdf: write progress: 100% +qpdfjob: open m.pdf: No such file or directory +qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest4.pdf b/qpdf/qtest/qpdf/qpdfjob-ctest4.pdf new file mode 100644 index 00000000..b2c4c2c0 Binary files /dev/null and b/qpdf/qtest/qpdf/qpdfjob-ctest4.pdf differ diff --git a/qpdf/qtest/qpdfjob.test b/qpdf/qtest/qpdfjob.test index 0724ba9f..2aea654b 100644 --- a/qpdf/qtest/qpdfjob.test +++ b/qpdf/qtest/qpdfjob.test @@ -43,7 +43,7 @@ my @good_json = ( "underlay-overlay-password", "misc-options", ); -my $n_tests = 10 + scalar(@bad_json) + (2 * scalar(@good_json)); +my $n_tests = 11 + scalar(@bad_json) + (2 * scalar(@good_json)); foreach my $i (@bad_json) @@ -104,7 +104,7 @@ $td->runtest("C job API", $td->FILTER => "perl filter-progress.pl"}, {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); -foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3]) +foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3], ['d.pdf', 4]) { $td->runtest("check output", {$td->FILE => $i->[0]},