Commit 230f1ab29039c30c5974d17ddcb0667ceedccf79

Authored by Jay Berkenbilt
Committed by GitHub
2 parents f8e39253 41f79bed

Merge pull request #933 from m-holger/c_job

C-API : expose QPDFJob::createQPDF and writeQPDF
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 &quot;C&quot; { @@ -138,6 +139,28 @@ extern &quot;C&quot; {
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-&gt;runtest(&quot;C job API&quot;, @@ -104,7 +104,7 @@ $td-&gt;runtest(&quot;C job API&quot;,
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]},