Commit 230f1ab29039c30c5974d17ddcb0667ceedccf79
Committed by
GitHub
Merge pull request #933 from m-holger/c_job
C-API : expose QPDFJob::createQPDF and writeQPDF
Showing
8 changed files
with
130 additions
and
46 deletions
include/qpdf/qpdfjob-c.h
| ... | ... | @@ -32,6 +32,7 @@ |
| 32 | 32 | */ |
| 33 | 33 | |
| 34 | 34 | #include <qpdf/DLL.h> |
| 35 | +#include <qpdf/qpdf-c.h> | |
| 35 | 36 | #include <qpdf/qpdflogger-c.h> |
| 36 | 37 | #include <string.h> |
| 37 | 38 | #ifndef QPDF_NO_WCHAR_T |
| ... | ... | @@ -138,6 +139,28 @@ extern "C" { |
| 138 | 139 | QPDF_DLL |
| 139 | 140 | int qpdfjob_run(qpdfjob_handle j); |
| 140 | 141 | |
| 142 | + /* The following two functions allow a job to be run in two stages - | |
| 143 | + * creation of a qpdf_data object and writing of the qpdf_data object. This | |
| 144 | + * allows the qpdf_data object to be modified prior to writing it out. See | |
| 145 | + * examples/qpdfjob-remove-annotations for a C++ illustration of its use. | |
| 146 | + * | |
| 147 | + * This function wraps QPDFJob::createQPDF. It runs the first stage of the | |
| 148 | + * job. A nullptr is returned if the job did not produce any pdf file to be | |
| 149 | + * written. | |
| 150 | + */ | |
| 151 | + QPDF_DLL | |
| 152 | + qpdf_data qpdfjob_create_qpdf(qpdfjob_handle j); | |
| 153 | + | |
| 154 | + /* This function wraps QPDFJob::writeQPDF. It returns the error code that | |
| 155 | + * qpdf would return with the equivalent command-line invocation. Exit code | |
| 156 | + * values are defined in Constants.h in the qpdf_exit_code_e type. NOTE it | |
| 157 | + * is the callers responsibility to clean up the resources associated | |
| 158 | + * qpdf_data object by calling qpdf_cleanup after the call to | |
| 159 | + * qpdfjob_write_qpdf. | |
| 160 | + */ | |
| 161 | + QPDF_DLL | |
| 162 | + int qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf); | |
| 163 | + | |
| 141 | 164 | /* Allow specification of a custom progress reporter. The progress |
| 142 | 165 | * reporter is only used if progress is otherwise requested (with |
| 143 | 166 | * the --progress option or "progress": "" in the JSON). | ... | ... |
libqpdf/qpdf-c.cc
| ... | ... | @@ -12,6 +12,7 @@ |
| 12 | 12 | #include <qpdf/QPDFWriter.hh> |
| 13 | 13 | #include <qpdf/QTC.hh> |
| 14 | 14 | #include <qpdf/QUtil.hh> |
| 15 | +#include <qpdf/qpdf-c_impl.hh> | |
| 15 | 16 | #include <qpdf/qpdflogger-c_impl.hh> |
| 16 | 17 | |
| 17 | 18 | #include <cstring> |
| ... | ... | @@ -20,50 +21,6 @@ |
| 20 | 21 | #include <stdexcept> |
| 21 | 22 | #include <string> |
| 22 | 23 | |
| 23 | -struct _qpdf_error | |
| 24 | -{ | |
| 25 | - std::shared_ptr<QPDFExc> exc; | |
| 26 | -}; | |
| 27 | - | |
| 28 | -struct _qpdf_data | |
| 29 | -{ | |
| 30 | - _qpdf_data(); | |
| 31 | - ~_qpdf_data() = default; | |
| 32 | - | |
| 33 | - std::shared_ptr<QPDF> qpdf; | |
| 34 | - std::shared_ptr<QPDFWriter> qpdf_writer; | |
| 35 | - | |
| 36 | - std::shared_ptr<QPDFExc> error; | |
| 37 | - _qpdf_error tmp_error; | |
| 38 | - std::list<QPDFExc> warnings; | |
| 39 | - std::string tmp_string; | |
| 40 | - | |
| 41 | - // Parameters for functions we call | |
| 42 | - char const* filename; // or description | |
| 43 | - char const* buffer; | |
| 44 | - unsigned long long size; | |
| 45 | - char const* password; | |
| 46 | - bool write_memory; | |
| 47 | - std::shared_ptr<Buffer> output_buffer; | |
| 48 | - | |
| 49 | - // QPDFObjectHandle support | |
| 50 | - bool silence_errors; | |
| 51 | - bool oh_error_occurred; | |
| 52 | - std::map<qpdf_oh, std::shared_ptr<QPDFObjectHandle>> oh_cache; | |
| 53 | - qpdf_oh next_oh; | |
| 54 | - std::set<std::string> cur_iter_dict_keys; | |
| 55 | - std::set<std::string>::const_iterator dict_iter; | |
| 56 | - std::string cur_dict_key; | |
| 57 | -}; | |
| 58 | - | |
| 59 | -_qpdf_data::_qpdf_data() : | |
| 60 | - write_memory(false), | |
| 61 | - silence_errors(false), | |
| 62 | - oh_error_occurred(false), | |
| 63 | - next_oh(0) | |
| 64 | -{ | |
| 65 | -} | |
| 66 | - | |
| 67 | 24 | // must set qpdf->filename and qpdf->password |
| 68 | 25 | static void |
| 69 | 26 | call_read(qpdf_data qpdf) | ... | ... |
libqpdf/qpdf/qpdf-c_impl.hh
0 → 100644
| 1 | +#include <qpdf/qpdf-c.h> | |
| 2 | + | |
| 3 | +#include <memory> | |
| 4 | + | |
| 5 | +#include <qpdf/QPDF.hh> | |
| 6 | +#include <qpdf/QPDFExc.hh> | |
| 7 | +#include <qpdf/QPDFWriter.hh> | |
| 8 | + | |
| 9 | +struct _qpdf_error | |
| 10 | +{ | |
| 11 | + std::shared_ptr<QPDFExc> exc; | |
| 12 | +}; | |
| 13 | + | |
| 14 | +struct _qpdf_data | |
| 15 | +{ | |
| 16 | + _qpdf_data() = default; | |
| 17 | + | |
| 18 | + _qpdf_data(std::unique_ptr<QPDF>&& qpdf) : | |
| 19 | + qpdf(std::move(qpdf)){}; | |
| 20 | + | |
| 21 | + ~_qpdf_data() = default; | |
| 22 | + | |
| 23 | + std::shared_ptr<QPDF> qpdf; | |
| 24 | + std::shared_ptr<QPDFWriter> qpdf_writer; | |
| 25 | + | |
| 26 | + std::shared_ptr<QPDFExc> error; | |
| 27 | + _qpdf_error tmp_error; | |
| 28 | + std::list<QPDFExc> warnings; | |
| 29 | + std::string tmp_string; | |
| 30 | + | |
| 31 | + // Parameters for functions we call | |
| 32 | + char const* filename{nullptr}; // or description | |
| 33 | + char const* buffer{nullptr}; | |
| 34 | + unsigned long long size{0}; | |
| 35 | + char const* password{nullptr}; | |
| 36 | + bool write_memory{false}; | |
| 37 | + std::shared_ptr<Buffer> output_buffer; | |
| 38 | + | |
| 39 | + // QPDFObjectHandle support | |
| 40 | + bool silence_errors{false}; | |
| 41 | + bool oh_error_occurred{false}; | |
| 42 | + std::map<qpdf_oh, std::shared_ptr<QPDFObjectHandle>> oh_cache; | |
| 43 | + qpdf_oh next_oh{0}; | |
| 44 | + std::set<std::string> cur_iter_dict_keys; | |
| 45 | + std::set<std::string>::const_iterator dict_iter; | |
| 46 | + std::string cur_dict_key; | |
| 47 | +}; | ... | ... |
libqpdf/qpdfjob-c.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/QPDFLogger.hh> |
| 5 | 5 | #include <qpdf/QPDFUsage.hh> |
| 6 | 6 | #include <qpdf/QUtil.hh> |
| 7 | +#include <qpdf/qpdf-c_impl.hh> | |
| 7 | 8 | #include <qpdf/qpdflogger-c_impl.hh> |
| 8 | 9 | |
| 9 | 10 | #include <cstdio> |
| ... | ... | @@ -98,6 +99,30 @@ qpdfjob_run(qpdfjob_handle j) |
| 98 | 99 | }); |
| 99 | 100 | } |
| 100 | 101 | |
| 102 | +qpdf_data | |
| 103 | +qpdfjob_create_qpdf(qpdfjob_handle j) | |
| 104 | +{ | |
| 105 | + QUtil::setLineBuf(stdout); | |
| 106 | + try { | |
| 107 | + auto qpdf = j->j.createQPDF(); | |
| 108 | + return qpdf ? new _qpdf_data(std::move(qpdf)) : nullptr; | |
| 109 | + } catch (std::exception& e) { | |
| 110 | + *j->j.getLogger()->getError() | |
| 111 | + << j->j.getMessagePrefix() << ": " << e.what() << "\n"; | |
| 112 | + } | |
| 113 | + return nullptr; | |
| 114 | +} | |
| 115 | + | |
| 116 | +int | |
| 117 | +qpdfjob_write_qpdf(qpdfjob_handle j, qpdf_data qpdf) | |
| 118 | +{ | |
| 119 | + QUtil::setLineBuf(stdout); | |
| 120 | + return wrap_qpdfjob(j, [qpdf](qpdfjob_handle jh) { | |
| 121 | + jh->j.writeQPDF(*(qpdf->qpdf)); | |
| 122 | + return jh->j.getExitCode(); | |
| 123 | + }); | |
| 124 | +} | |
| 125 | + | |
| 101 | 126 | static int |
| 102 | 127 | run_with_handle(std::function<int(qpdfjob_handle)> fn) |
| 103 | 128 | { | ... | ... |
qpdf/qpdfjob-ctest.c
| ... | ... | @@ -97,6 +97,33 @@ run_tests() |
| 97 | 97 | assert(qpdfjob_run(j) == 2); |
| 98 | 98 | qpdfjob_cleanup(&j); |
| 99 | 99 | printf("json error test passed\n"); |
| 100 | + | |
| 101 | + /* qpdfjob_create_qpdf and qpdfjob_write_qpdf test */ | |
| 102 | + argv[0] = "qpdfjob"; | |
| 103 | + argv[1] = "minimal.pdf"; | |
| 104 | + argv[2] = "d.pdf"; | |
| 105 | + argv[3] = "--deterministic-id"; | |
| 106 | + argv[4] = "--progress"; | |
| 107 | + argv[5] = NULL; | |
| 108 | + j = qpdfjob_init(); | |
| 109 | + assert(qpdfjob_initialize_from_argv(j, argv) == 0); | |
| 110 | + qpdf_data qpdf = qpdfjob_create_qpdf(j); | |
| 111 | + assert(qpdfjob_write_qpdf(j, qpdf) == 0); | |
| 112 | + qpdf_cleanup(&qpdf); | |
| 113 | + qpdfjob_cleanup(&j); | |
| 114 | + | |
| 115 | + /* Try to open a missing file to test case of QPDFJob::createQPDF returning | |
| 116 | + * nullptr. | |
| 117 | + */ | |
| 118 | + argv[0] = "qpdfjob"; | |
| 119 | + argv[1] = "m.pdf"; | |
| 120 | + argv[2] = "--check"; | |
| 121 | + argv[3] = NULL; | |
| 122 | + j = qpdfjob_init(); | |
| 123 | + assert(qpdfjob_initialize_from_argv(j, argv) == 0); | |
| 124 | + assert(qpdfjob_create_qpdf(j) == NULL); | |
| 125 | + qpdfjob_cleanup(&j); | |
| 126 | + printf("qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed\n"); | |
| 100 | 127 | } |
| 101 | 128 | |
| 102 | 129 | int | ... | ... |
qpdf/qtest/qpdf/qpdfjob-ctest.out
| ... | ... | @@ -9,3 +9,8 @@ json warn test passed |
| 9 | 9 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| |
| 10 | 10 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| |
| 11 | 11 | json error test passed |
| 12 | +qpdfjob: d.pdf: write progress: 0% | |
| 13 | +....other write progress.... | |
| 14 | +qpdfjob: d.pdf: write progress: 100% | |
| 15 | +qpdfjob: open m.pdf: No such file or directory | |
| 16 | +qpdfjob_create_qpdf and qpdfjob_write_qpdf test passed | ... | ... |
qpdf/qtest/qpdf/qpdfjob-ctest4.pdf
0 → 100644
No preview for this file type
qpdf/qtest/qpdfjob.test
| ... | ... | @@ -43,7 +43,7 @@ my @good_json = ( |
| 43 | 43 | "underlay-overlay-password", |
| 44 | 44 | "misc-options", |
| 45 | 45 | ); |
| 46 | -my $n_tests = 10 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 46 | +my $n_tests = 11 + scalar(@bad_json) + (2 * scalar(@good_json)); | |
| 47 | 47 | |
| 48 | 48 | |
| 49 | 49 | foreach my $i (@bad_json) |
| ... | ... | @@ -104,7 +104,7 @@ $td->runtest("C job API", |
| 104 | 104 | $td->FILTER => "perl filter-progress.pl"}, |
| 105 | 105 | {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, |
| 106 | 106 | $td->NORMALIZE_NEWLINES); |
| 107 | -foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3]) | |
| 107 | +foreach my $i (['a.pdf', 1], ['b.pdf', 2], ['c.pdf', 3], ['d.pdf', 4]) | |
| 108 | 108 | { |
| 109 | 109 | $td->runtest("check output", |
| 110 | 110 | {$td->FILE => $i->[0]}, | ... | ... |