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 6 2022-09-08 Jay Berkenbilt <ejb@ql.org>
2 7  
3 8 * Added new functions to the C API to support qpdf JSON:
... ...
... ... @@ -8,12 +8,7 @@ Always
8 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 13 Possible future JSON enhancements
19 14 =================================
... ...
include/qpdf/qpdf-c.h
... ... @@ -140,6 +140,7 @@
140 140 #include <qpdf/Constants.h>
141 141 #include <qpdf/DLL.h>
142 142 #include <qpdf/Types.h>
  143 +#include <qpdf/qpdflogger-c.h>
143 144 #include <string.h>
144 145  
145 146 #ifdef __cplusplus
... ... @@ -249,6 +250,20 @@ extern &quot;C&quot; {
249 250 QPDF_DLL
250 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 267 /* CHECK FUNCTIONS */
253 268  
254 269 /* Attempt to read the entire PDF file to see if there are any
... ...
include/qpdf/qpdfjob-c.h
... ... @@ -32,6 +32,7 @@
32 32 */
33 33  
34 34 #include <qpdf/DLL.h>
  35 +#include <qpdf/qpdflogger-c.h>
35 36 #include <string.h>
36 37 #ifndef QPDF_NO_WCHAR_T
37 38 # include <wchar.h>
... ... @@ -92,6 +93,18 @@ extern &quot;C&quot; {
92 93 QPDF_DLL
93 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 108 /* This function wraps QPDFJob::initializeFromArgv. The return
96 109 * value is the same as qpdfjob_run. If this returns an error, it
97 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 38  
39 39 /* To operate on a logger, you need a handle to it. call
40 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 52 typedef struct _qpdflogger_handle* qpdflogger_handle;
48 53 QPDF_DLL
49 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 63 QPDF_DLL
52 64 void qpdflogger_cleanup(qpdflogger_handle* l);
53 65  
... ... @@ -95,6 +107,10 @@ extern &quot;C&quot; {
95 107 void qpdflogger_save_to_standard_output(
96 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 114 #ifdef __cplusplus
99 115 }
100 116 #endif
... ...
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/qpdflogger-c_impl.hh>
15 16  
16 17 #include <cstring>
17 18 #include <functional>
... ... @@ -280,6 +281,18 @@ qpdf_check_pdf(qpdf_data qpdf)
280 281 }
281 282  
282 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 296 qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value)
284 297 {
285 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 4 #include <qpdf/QPDFLogger.hh>
5 5 #include <qpdf/QPDFUsage.hh>
6 6 #include <qpdf/QUtil.hh>
  7 +#include <qpdf/qpdflogger-c_impl.hh>
7 8  
8 9 #include <cstdio>
9 10 #include <cstring>
... ... @@ -41,6 +42,18 @@ wrap_qpdfjob(qpdfjob_handle j, std::function&lt;int(qpdfjob_handle j)&gt; fn)
41 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 57 int
45 58 qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[])
46 59 {
... ...
libqpdf/qpdflogger-c.cc
1 1 #include <qpdf/qpdflogger-c.h>
2 2  
  3 +#include <qpdf/qpdflogger-c_impl.hh>
  4 +
3 5 #include <qpdf/Pipeline.hh>
4 6 #include <qpdf/Pl_Function.hh>
5 7 #include <qpdf/QIntC.hh>
... ... @@ -7,14 +9,6 @@
7 9 #include <functional>
8 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 12 _qpdflogger_handle::_qpdflogger_handle(std::shared_ptr<QPDFLogger> l) :
19 13 l(l)
20 14 {
... ... @@ -26,6 +20,12 @@ qpdflogger_default_logger()
26 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 29 void
30 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 125 qpdflogger_set_save(
126 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 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 152 static void
144 153 test01(
145 154 char const* infile,
... ... @@ -583,6 +592,20 @@ test23(
583 592 char const* outfile,
584 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 609 QPDF_ERROR_CODE status = 0;
587 610 qpdf_read(qpdf, infile, password);
588 611 status = qpdf_check_pdf(qpdf);
... ...
qpdf/qpdfjob-ctest.c
... ... @@ -26,6 +26,15 @@ custom_progress(int progress, void* data)
26 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 38 static void
30 39 run_tests()
31 40 {
... ... @@ -55,6 +64,7 @@ run_tests()
55 64 \"objectStreams\": \"generate\"\n\
56 65 }") == 0);
57 66 printf("json test passed\n");
  67 + fflush(stdout);
58 68  
59 69 assert(qpdfjob_run_from_json("{\n\
60 70 \"inputFile\": \"xref-with-short-size.pdf\",\n\
... ... @@ -64,10 +74,28 @@ run_tests()
64 74 \"objectStreams\": \"generate\"\n\
65 75 }") == 3);
66 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 95 \"inputFile\": \"nothing-there.pdf\"\n\
70   -}") == 2);
  96 +}");
  97 + assert(qpdfjob_run(j) == 2);
  98 + qpdfjob_cleanup(&j);
71 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 4 status: 1
5 5 warning: c-check-warn-in.pdf: file is damaged
6 6 code: 5
... ...
qpdf/qtest/qpdf/qpdfjob-ctest.out
... ... @@ -6,5 +6,6 @@ json test passed
6 6 WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
7 7 qpdfjob json: operation succeeded with warnings; resulting file may have some problems
8 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 11 json error test passed
... ...