Commit 3dbab589e32d3ed5bd98e0634255ba7dfab4c892

Authored by Jay Berkenbilt
1 parent 0ad4e190

Add C API functions for using custom loggers

Expose functions to the C API to create new loggers and to setLogger
and getLogger for QPDF and QPDFJob.
ChangeLog
  1 +2022-09-09 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Expose ability to create custom loggers and to get and set the
  4 + logger for QPDF and QPDFJob through the C API.
  5 +
1 2022-09-08 Jay Berkenbilt <ejb@ql.org> 6 2022-09-08 Jay Berkenbilt <ejb@ql.org>
2 7
3 * Added new functions to the C API to support qpdf JSON: 8 * Added new functions to the C API to support qpdf JSON:
@@ -8,12 +8,7 @@ Always @@ -8,12 +8,7 @@ Always
8 Next 8 Next
9 ==== 9 ====
10 10
11 -Pending changes:  
12 -  
13 -* Consider also exposing a way to set a new logger and to get the  
14 - logger from QPDF and QPDFJob in the C API.  
15 -  
16 -Soon: Break ground on "Document-level work" 11 +* Break ground on "Document-level work"
17 12
18 Possible future JSON enhancements 13 Possible future JSON enhancements
19 ================================= 14 =================================
include/qpdf/qpdf-c.h
@@ -140,6 +140,7 @@ @@ -140,6 +140,7 @@
140 #include <qpdf/Constants.h> 140 #include <qpdf/Constants.h>
141 #include <qpdf/DLL.h> 141 #include <qpdf/DLL.h>
142 #include <qpdf/Types.h> 142 #include <qpdf/Types.h>
  143 +#include <qpdf/qpdflogger-c.h>
143 #include <string.h> 144 #include <string.h>
144 145
145 #ifdef __cplusplus 146 #ifdef __cplusplus
@@ -249,6 +250,20 @@ extern &quot;C&quot; { @@ -249,6 +250,20 @@ extern &quot;C&quot; {
249 QPDF_DLL 250 QPDF_DLL
250 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value); 251 void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value);
251 252
  253 + /* LOG FUNCTIONS */
  254 +
  255 + /* Set or get the current logger. You need to call
  256 + * qpdflogger_cleanup on the logger handles when you are done with
  257 + * the handles. The underlying logger is cleaned up automatically
  258 + * and persists if needed after the logger handle is destroyed.
  259 + * See comments in qpdflogger-c.h for details.
  260 + */
  261 +
  262 + QPDF_DLL
  263 + void qpdf_set_logger(qpdf_data qpdf, qpdflogger_handle logger);
  264 + QPDF_DLL
  265 + qpdflogger_handle qpdf_get_logger(qpdf_data qpdf);
  266 +
252 /* CHECK FUNCTIONS */ 267 /* CHECK FUNCTIONS */
253 268
254 /* Attempt to read the entire PDF file to see if there are any 269 /* Attempt to read the entire PDF file to see if there are any
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/qpdflogger-c.h>
35 #include <string.h> 36 #include <string.h>
36 #ifndef QPDF_NO_WCHAR_T 37 #ifndef QPDF_NO_WCHAR_T
37 # include <wchar.h> 38 # include <wchar.h>
@@ -92,6 +93,18 @@ extern &quot;C&quot; { @@ -92,6 +93,18 @@ extern &quot;C&quot; {
92 QPDF_DLL 93 QPDF_DLL
93 void qpdfjob_cleanup(qpdfjob_handle* j); 94 void qpdfjob_cleanup(qpdfjob_handle* j);
94 95
  96 + /* Set or get the current logger. You need to call
  97 + * qpdflogger_cleanup on the logger handles when you are done with
  98 + * the handles. The underlying logger is cleaned up automatically
  99 + * and persists if needed after the logger handle is destroyed.
  100 + * See comments in qpdflogger-c.h for details.
  101 + */
  102 +
  103 + QPDF_DLL
  104 + void qpdfjob_set_logger(qpdfjob_handle j, qpdflogger_handle logger);
  105 + QPDF_DLL
  106 + qpdflogger_handle qpdfjob_get_logger(qpdfjob_handle j);
  107 +
95 /* This function wraps QPDFJob::initializeFromArgv. The return 108 /* This function wraps QPDFJob::initializeFromArgv. The return
96 * value is the same as qpdfjob_run. If this returns an error, it 109 * value is the same as qpdfjob_run. If this returns an error, it
97 * is invalid to call any other functions this job handle. 110 * is invalid to call any other functions this job handle.
include/qpdf/qpdflogger-c.h
@@ -38,16 +38,28 @@ extern &quot;C&quot; { @@ -38,16 +38,28 @@ extern &quot;C&quot; {
38 38
39 /* To operate on a logger, you need a handle to it. call 39 /* To operate on a logger, you need a handle to it. call
40 * qpdflogger_default_logger to get a handle for the default 40 * qpdflogger_default_logger to get a handle for the default
41 - * logger. The qpdf and qpdfjob functions may offer ways to get  
42 - * other logger handles. When you're done with the logger handler,  
43 - * call qpdflogger_cleanup. This does not destroy the underlying  
44 - * log object. It just cleans up the handle to it. 41 + * logger. There are functions in qpdf-c.h and qpdfjob-c.h that
  42 + * also take or return logger handles. When you're done with the
  43 + * logger handler, call qpdflogger_cleanup. This cleans up the
  44 + * handle but leaves the underlying log object intact. (It uses a
  45 + * shared pointer and will be cleaned up automatically when it is
  46 + * no longer in use.) That means you can create a logger with
  47 + * qpdflogger_create(), pass the logger handle to a function in
  48 + * qpdf-c.h or qpdfjob-c.h, and then clean it up, subject to
  49 + * constraints imposed by the other function.
45 */ 50 */
46 51
47 typedef struct _qpdflogger_handle* qpdflogger_handle; 52 typedef struct _qpdflogger_handle* qpdflogger_handle;
48 QPDF_DLL 53 QPDF_DLL
49 qpdflogger_handle qpdflogger_default_logger(); 54 qpdflogger_handle qpdflogger_default_logger();
50 55
  56 + /* Calling cleanup on the handle returned by qpdflogger_create
  57 + * destroys the handle but not the underlying logger. See comments
  58 + * above.
  59 + */
  60 + QPDF_DLL
  61 + qpdflogger_handle qpdflogger_create();
  62 +
51 QPDF_DLL 63 QPDF_DLL
52 void qpdflogger_cleanup(qpdflogger_handle* l); 64 void qpdflogger_cleanup(qpdflogger_handle* l);
53 65
@@ -95,6 +107,10 @@ extern &quot;C&quot; { @@ -95,6 +107,10 @@ extern &quot;C&quot; {
95 void qpdflogger_save_to_standard_output( 107 void qpdflogger_save_to_standard_output(
96 qpdflogger_handle l, int only_if_not_set); 108 qpdflogger_handle l, int only_if_not_set);
97 109
  110 + /* For testing */
  111 + QPDF_DLL
  112 + int qpdflogger_equal(qpdflogger_handle l1, qpdflogger_handle l2);
  113 +
98 #ifdef __cplusplus 114 #ifdef __cplusplus
99 } 115 }
100 #endif 116 #endif
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/qpdflogger-c_impl.hh>
15 16
16 #include <cstring> 17 #include <cstring>
17 #include <functional> 18 #include <functional>
@@ -280,6 +281,18 @@ qpdf_check_pdf(qpdf_data qpdf) @@ -280,6 +281,18 @@ qpdf_check_pdf(qpdf_data qpdf)
280 } 281 }
281 282
282 void 283 void
  284 +qpdf_set_logger(qpdf_data qpdf, qpdflogger_handle logger)
  285 +{
  286 + qpdf->qpdf->setLogger(logger->l);
  287 +}
  288 +
  289 +qpdflogger_handle
  290 +qpdf_get_logger(qpdf_data qpdf)
  291 +{
  292 + return new _qpdflogger_handle(qpdf->qpdf->getLogger());
  293 +}
  294 +
  295 +void
283 qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value) 296 qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value)
284 { 297 {
285 QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings"); 298 QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings");
libqpdf/qpdf/qpdflogger-c_impl.hh 0 โ†’ 100644
  1 +#include <qpdf/qpdflogger-c.h>
  2 +
  3 +#include <qpdf/QPDFLogger.hh>
  4 +
  5 +struct _qpdflogger_handle
  6 +{
  7 + _qpdflogger_handle(std::shared_ptr<QPDFLogger> l);
  8 + ~_qpdflogger_handle() = default;
  9 +
  10 + std::shared_ptr<QPDFLogger> l;
  11 +};
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/qpdflogger-c_impl.hh>
7 8
8 #include <cstdio> 9 #include <cstdio>
9 #include <cstring> 10 #include <cstring>
@@ -41,6 +42,18 @@ wrap_qpdfjob(qpdfjob_handle j, std::function&lt;int(qpdfjob_handle j)&gt; fn) @@ -41,6 +42,18 @@ wrap_qpdfjob(qpdfjob_handle j, std::function&lt;int(qpdfjob_handle j)&gt; fn)
41 return QPDFJob::EXIT_ERROR; 42 return QPDFJob::EXIT_ERROR;
42 } 43 }
43 44
  45 +void
  46 +qpdfjob_set_logger(qpdfjob_handle j, qpdflogger_handle logger)
  47 +{
  48 + j->j.setLogger(logger->l);
  49 +}
  50 +
  51 +qpdflogger_handle
  52 +qpdfjob_get_logger(qpdfjob_handle j)
  53 +{
  54 + return new _qpdflogger_handle(j->j.getLogger());
  55 +}
  56 +
44 int 57 int
45 qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[]) 58 qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[])
46 { 59 {
libqpdf/qpdflogger-c.cc
1 #include <qpdf/qpdflogger-c.h> 1 #include <qpdf/qpdflogger-c.h>
2 2
  3 +#include <qpdf/qpdflogger-c_impl.hh>
  4 +
3 #include <qpdf/Pipeline.hh> 5 #include <qpdf/Pipeline.hh>
4 #include <qpdf/Pl_Function.hh> 6 #include <qpdf/Pl_Function.hh>
5 #include <qpdf/QIntC.hh> 7 #include <qpdf/QIntC.hh>
@@ -7,14 +9,6 @@ @@ -7,14 +9,6 @@
7 #include <functional> 9 #include <functional>
8 #include <memory> 10 #include <memory>
9 11
10 -struct _qpdflogger_handle  
11 -{  
12 - _qpdflogger_handle(std::shared_ptr<QPDFLogger> l);  
13 - ~_qpdflogger_handle() = default;  
14 -  
15 - std::shared_ptr<QPDFLogger> l;  
16 -};  
17 -  
18 _qpdflogger_handle::_qpdflogger_handle(std::shared_ptr<QPDFLogger> l) : 12 _qpdflogger_handle::_qpdflogger_handle(std::shared_ptr<QPDFLogger> l) :
19 l(l) 13 l(l)
20 { 14 {
@@ -26,6 +20,12 @@ qpdflogger_default_logger() @@ -26,6 +20,12 @@ qpdflogger_default_logger()
26 return new _qpdflogger_handle(QPDFLogger::defaultLogger()); 20 return new _qpdflogger_handle(QPDFLogger::defaultLogger());
27 } 21 }
28 22
  23 +qpdflogger_handle
  24 +qpdflogger_create()
  25 +{
  26 + return new _qpdflogger_handle(QPDFLogger::create());
  27 +}
  28 +
29 void 29 void
30 qpdflogger_cleanup(qpdflogger_handle* l) 30 qpdflogger_cleanup(qpdflogger_handle* l)
31 { 31 {
@@ -125,3 +125,9 @@ qpdflogger_save_to_standard_output(qpdflogger_handle l, int only_if_not_set) @@ -125,3 +125,9 @@ qpdflogger_save_to_standard_output(qpdflogger_handle l, int only_if_not_set)
125 qpdflogger_set_save( 125 qpdflogger_set_save(
126 l, qpdf_log_dest_stdout, nullptr, nullptr, only_if_not_set); 126 l, qpdf_log_dest_stdout, nullptr, nullptr, only_if_not_set);
127 } 127 }
  128 +
  129 +int
  130 +qpdflogger_equal(qpdflogger_handle l1, qpdflogger_handle l2)
  131 +{
  132 + return l1->l.get() == l2->l.get();
  133 +}
qpdf/qpdf-ctest.c
@@ -140,6 +140,15 @@ write_to_file(char const* data, size_t size, void* udata) @@ -140,6 +140,15 @@ write_to_file(char const* data, size_t size, void* udata)
140 return fwrite(data, 1, size, f) != size; 140 return fwrite(data, 1, size, f) != size;
141 } 141 }
142 142
  143 +static int
  144 +custom_log(char const* data, size_t size, void* udata)
  145 +{
  146 + fprintf(stderr, "|custom|");
  147 + fwrite(data, 1, size, stderr);
  148 + fflush(stderr);
  149 + return 0;
  150 +}
  151 +
143 static void 152 static void
144 test01( 153 test01(
145 char const* infile, 154 char const* infile,
@@ -583,6 +592,20 @@ test23( @@ -583,6 +592,20 @@ test23(
583 char const* outfile, 592 char const* outfile,
584 char const* xarg) 593 char const* xarg)
585 { 594 {
  595 + /* Test check and also exercise custom logger */
  596 + qpdflogger_handle l1 = qpdf_get_logger(qpdf);
  597 + qpdflogger_handle l2 = qpdflogger_default_logger();
  598 + assert(qpdflogger_equal(l1, l2));
  599 + qpdflogger_cleanup(&l1);
  600 + qpdflogger_cleanup(&l2);
  601 + qpdflogger_handle l = qpdflogger_create();
  602 + qpdflogger_set_warn(l, qpdf_log_dest_custom, custom_log, NULL);
  603 + qpdf_set_logger(qpdf, l);
  604 + qpdflogger_handle l3 = qpdf_get_logger(qpdf);
  605 + assert(qpdflogger_equal(l, l3));
  606 + qpdflogger_cleanup(&l);
  607 + qpdflogger_cleanup(&l3);
  608 +
586 QPDF_ERROR_CODE status = 0; 609 QPDF_ERROR_CODE status = 0;
587 qpdf_read(qpdf, infile, password); 610 qpdf_read(qpdf, infile, password);
588 status = qpdf_check_pdf(qpdf); 611 status = qpdf_check_pdf(qpdf);
qpdf/qpdfjob-ctest.c
@@ -26,6 +26,15 @@ custom_progress(int progress, void* data) @@ -26,6 +26,15 @@ custom_progress(int progress, void* data)
26 printf("%s: write progress: %d%%\n", (char const*)data, progress); 26 printf("%s: write progress: %d%%\n", (char const*)data, progress);
27 } 27 }
28 28
  29 +static int
  30 +custom_log(char const* data, size_t size, void* udata)
  31 +{
  32 + fprintf(stderr, "|custom|");
  33 + fwrite(data, 1, size, stderr);
  34 + fflush(stderr);
  35 + return 0;
  36 +}
  37 +
29 static void 38 static void
30 run_tests() 39 run_tests()
31 { 40 {
@@ -55,6 +64,7 @@ run_tests() @@ -55,6 +64,7 @@ run_tests()
55 \"objectStreams\": \"generate\"\n\ 64 \"objectStreams\": \"generate\"\n\
56 }") == 0); 65 }") == 0);
57 printf("json test passed\n"); 66 printf("json test passed\n");
  67 + fflush(stdout);
58 68
59 assert(qpdfjob_run_from_json("{\n\ 69 assert(qpdfjob_run_from_json("{\n\
60 \"inputFile\": \"xref-with-short-size.pdf\",\n\ 70 \"inputFile\": \"xref-with-short-size.pdf\",\n\
@@ -64,10 +74,28 @@ run_tests() @@ -64,10 +74,28 @@ run_tests()
64 \"objectStreams\": \"generate\"\n\ 74 \"objectStreams\": \"generate\"\n\
65 }") == 3); 75 }") == 3);
66 printf("json warn test passed\n"); 76 printf("json warn test passed\n");
  77 + fflush(stdout);
67 78
68 - assert(qpdfjob_run_from_json("{\n\ 79 + /* Also exercise custom logger */
  80 + j = qpdfjob_init();
  81 + qpdflogger_handle l1 = qpdfjob_get_logger(j);
  82 + qpdflogger_handle l2 = qpdflogger_default_logger();
  83 + assert(qpdflogger_equal(l1, l2));
  84 + qpdflogger_cleanup(&l1);
  85 + qpdflogger_cleanup(&l2);
  86 + qpdflogger_handle l = qpdflogger_create();
  87 + qpdflogger_set_error(l, qpdf_log_dest_custom, custom_log, NULL);
  88 + qpdfjob_set_logger(j, l);
  89 + qpdflogger_handle l3 = qpdfjob_get_logger(j);
  90 + assert(qpdflogger_equal(l, l3));
  91 + qpdflogger_cleanup(&l);
  92 + qpdflogger_cleanup(&l3);
  93 +
  94 + qpdfjob_initialize_from_json(j, "{\n\
69 \"inputFile\": \"nothing-there.pdf\"\n\ 95 \"inputFile\": \"nothing-there.pdf\"\n\
70 -}") == 2); 96 +}");
  97 + assert(qpdfjob_run(j) == 2);
  98 + qpdfjob_cleanup(&j);
71 printf("json error test passed\n"); 99 printf("json error test passed\n");
72 } 100 }
73 101
qpdf/qtest/qpdf/c-check-warn.out
1 -WARNING: c-check-warn-in.pdf: file is damaged  
2 -WARNING: c-check-warn-in.pdf (offset 1556): xref not found  
3 -WARNING: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table 1 +|custom|WARNING: |custom|c-check-warn-in.pdf: file is damaged|custom|
  2 +|custom|WARNING: |custom|c-check-warn-in.pdf (offset 1556): xref not found|custom|
  3 +|custom|WARNING: |custom|c-check-warn-in.pdf: Attempting to reconstruct cross-reference table|custom|
4 status: 1 4 status: 1
5 warning: c-check-warn-in.pdf: file is damaged 5 warning: c-check-warn-in.pdf: file is damaged
6 code: 5 6 code: 5
qpdf/qtest/qpdf/qpdfjob-ctest.out
@@ -6,5 +6,6 @@ json test passed @@ -6,5 +6,6 @@ json test passed
6 WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56 6 WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
7 qpdfjob json: operation succeeded with warnings; resulting file may have some problems 7 qpdfjob json: operation succeeded with warnings; resulting file may have some problems
8 json warn test passed 8 json warn test passed
9 -qpdfjob json: an output file name is required; use - for standard output 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 json error test passed 11 json error test passed