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,6 +32,7 @@ | ||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #include <qpdf/DLL.h> | 34 | #include <qpdf/DLL.h> |
| 35 | +#include <qpdf/qpdf-c.h> | ||
| 35 | #include <qpdf/qpdflogger-c.h> | 36 | #include <qpdf/qpdflogger-c.h> |
| 36 | #include <string.h> | 37 | #include <string.h> |
| 37 | #ifndef QPDF_NO_WCHAR_T | 38 | #ifndef QPDF_NO_WCHAR_T |
| @@ -138,6 +139,28 @@ extern "C" { | @@ -138,6 +139,28 @@ extern "C" { | ||
| 138 | QPDF_DLL | 139 | QPDF_DLL |
| 139 | int qpdfjob_run(qpdfjob_handle j); | 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 | /* Allow specification of a custom progress reporter. The progress | 164 | /* Allow specification of a custom progress reporter. The progress |
| 142 | * reporter is only used if progress is otherwise requested (with | 165 | * reporter is only used if progress is otherwise requested (with |
| 143 | * the --progress option or "progress": "" in the JSON). | 166 | * the --progress option or "progress": "" in the JSON). |
libqpdf/qpdf-c.cc
| @@ -12,6 +12,7 @@ | @@ -12,6 +12,7 @@ | ||
| 12 | #include <qpdf/QPDFWriter.hh> | 12 | #include <qpdf/QPDFWriter.hh> |
| 13 | #include <qpdf/QTC.hh> | 13 | #include <qpdf/QTC.hh> |
| 14 | #include <qpdf/QUtil.hh> | 14 | #include <qpdf/QUtil.hh> |
| 15 | +#include <qpdf/qpdf-c_impl.hh> | ||
| 15 | #include <qpdf/qpdflogger-c_impl.hh> | 16 | #include <qpdf/qpdflogger-c_impl.hh> |
| 16 | 17 | ||
| 17 | #include <cstring> | 18 | #include <cstring> |
| @@ -20,50 +21,6 @@ | @@ -20,50 +21,6 @@ | ||
| 20 | #include <stdexcept> | 21 | #include <stdexcept> |
| 21 | #include <string> | 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 | // must set qpdf->filename and qpdf->password | 24 | // must set qpdf->filename and qpdf->password |
| 68 | static void | 25 | static void |
| 69 | call_read(qpdf_data qpdf) | 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,6 +4,7 @@ | ||
| 4 | #include <qpdf/QPDFLogger.hh> | 4 | #include <qpdf/QPDFLogger.hh> |
| 5 | #include <qpdf/QPDFUsage.hh> | 5 | #include <qpdf/QPDFUsage.hh> |
| 6 | #include <qpdf/QUtil.hh> | 6 | #include <qpdf/QUtil.hh> |
| 7 | +#include <qpdf/qpdf-c_impl.hh> | ||
| 7 | #include <qpdf/qpdflogger-c_impl.hh> | 8 | #include <qpdf/qpdflogger-c_impl.hh> |
| 8 | 9 | ||
| 9 | #include <cstdio> | 10 | #include <cstdio> |
| @@ -98,6 +99,30 @@ qpdfjob_run(qpdfjob_handle j) | @@ -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 | static int | 126 | static int |
| 102 | run_with_handle(std::function<int(qpdfjob_handle)> fn) | 127 | run_with_handle(std::function<int(qpdfjob_handle)> fn) |
| 103 | { | 128 | { |
qpdf/qpdfjob-ctest.c
| @@ -97,6 +97,33 @@ run_tests() | @@ -97,6 +97,33 @@ run_tests() | ||
| 97 | assert(qpdfjob_run(j) == 2); | 97 | assert(qpdfjob_run(j) == 2); |
| 98 | qpdfjob_cleanup(&j); | 98 | qpdfjob_cleanup(&j); |
| 99 | printf("json error test passed\n"); | 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 | int | 129 | int |
qpdf/qtest/qpdf/qpdfjob-ctest.out
| @@ -9,3 +9,8 @@ json warn test passed | @@ -9,3 +9,8 @@ json warn test passed | ||
| 9 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| | 9 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| |
| 10 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| | 10 | |custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom| |
| 11 | json error test passed | 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,7 +43,7 @@ my @good_json = ( | ||
| 43 | "underlay-overlay-password", | 43 | "underlay-overlay-password", |
| 44 | "misc-options", | 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 | foreach my $i (@bad_json) | 49 | foreach my $i (@bad_json) |
| @@ -104,7 +104,7 @@ $td->runtest("C job API", | @@ -104,7 +104,7 @@ $td->runtest("C job API", | ||
| 104 | $td->FILTER => "perl filter-progress.pl"}, | 104 | $td->FILTER => "perl filter-progress.pl"}, |
| 105 | {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, | 105 | {$td->FILE => "qpdfjob-ctest.out", $td->EXIT_STATUS => 0}, |
| 106 | $td->NORMALIZE_NEWLINES); | 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 | $td->runtest("check output", | 109 | $td->runtest("check output", |
| 110 | {$td->FILE => $i->[0]}, | 110 | {$td->FILE => $i->[0]}, |