aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-09-09 14:03:21 +0200
committerJay Berkenbilt <ejb@ql.org>2022-09-09 16:49:25 +0200
commit3dbab589e32d3ed5bd98e0634255ba7dfab4c892 (patch)
tree132391fe89db1b2fbf50929721e0eb8bb167e47d
parent0ad4e190ffbb85ea2db5a05d43cd4f81d98cfe63 (diff)
downloadqpdf-3dbab589e32d3ed5bd98e0634255ba7dfab4c892.tar.zst
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.
-rw-r--r--ChangeLog5
-rw-r--r--TODO7
-rw-r--r--include/qpdf/qpdf-c.h15
-rw-r--r--include/qpdf/qpdfjob-c.h13
-rw-r--r--include/qpdf/qpdflogger-c.h24
-rw-r--r--libqpdf/qpdf-c.cc13
-rw-r--r--libqpdf/qpdf/qpdflogger-c_impl.hh11
-rw-r--r--libqpdf/qpdfjob-c.cc13
-rw-r--r--libqpdf/qpdflogger-c.cc22
-rw-r--r--qpdf/qpdf-ctest.c23
-rw-r--r--qpdf/qpdfjob-ctest.c32
-rw-r--r--qpdf/qtest/qpdf/c-check-warn.out6
-rw-r--r--qpdf/qtest/qpdf/qpdfjob-ctest.out3
13 files changed, 163 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index b7e793a8..db589d34 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2022-09-09 Jay Berkenbilt <ejb@ql.org>
+
+ * Expose ability to create custom loggers and to get and set the
+ logger for QPDF and QPDFJob through the C API.
+
2022-09-08 Jay Berkenbilt <ejb@ql.org>
* Added new functions to the C API to support qpdf JSON:
diff --git a/TODO b/TODO
index 5f3cd99a..49e70d27 100644
--- a/TODO
+++ b/TODO
@@ -8,12 +8,7 @@ Always
Next
====
-Pending changes:
-
-* Consider also exposing a way to set a new logger and to get the
- logger from QPDF and QPDFJob in the C API.
-
-Soon: Break ground on "Document-level work"
+* Break ground on "Document-level work"
Possible future JSON enhancements
=================================
diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h
index 434c4ede..8d1b0e2f 100644
--- a/include/qpdf/qpdf-c.h
+++ b/include/qpdf/qpdf-c.h
@@ -140,6 +140,7 @@
#include <qpdf/Constants.h>
#include <qpdf/DLL.h>
#include <qpdf/Types.h>
+#include <qpdf/qpdflogger-c.h>
#include <string.h>
#ifdef __cplusplus
@@ -249,6 +250,20 @@ extern "C" {
QPDF_DLL
void qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value);
+ /* LOG FUNCTIONS */
+
+ /* Set or get the current logger. You need to call
+ * qpdflogger_cleanup on the logger handles when you are done with
+ * the handles. The underlying logger is cleaned up automatically
+ * and persists if needed after the logger handle is destroyed.
+ * See comments in qpdflogger-c.h for details.
+ */
+
+ QPDF_DLL
+ void qpdf_set_logger(qpdf_data qpdf, qpdflogger_handle logger);
+ QPDF_DLL
+ qpdflogger_handle qpdf_get_logger(qpdf_data qpdf);
+
/* CHECK FUNCTIONS */
/* Attempt to read the entire PDF file to see if there are any
diff --git a/include/qpdf/qpdfjob-c.h b/include/qpdf/qpdfjob-c.h
index 961fece4..a1540d84 100644
--- a/include/qpdf/qpdfjob-c.h
+++ b/include/qpdf/qpdfjob-c.h
@@ -32,6 +32,7 @@
*/
#include <qpdf/DLL.h>
+#include <qpdf/qpdflogger-c.h>
#include <string.h>
#ifndef QPDF_NO_WCHAR_T
# include <wchar.h>
@@ -92,6 +93,18 @@ extern "C" {
QPDF_DLL
void qpdfjob_cleanup(qpdfjob_handle* j);
+ /* Set or get the current logger. You need to call
+ * qpdflogger_cleanup on the logger handles when you are done with
+ * the handles. The underlying logger is cleaned up automatically
+ * and persists if needed after the logger handle is destroyed.
+ * See comments in qpdflogger-c.h for details.
+ */
+
+ QPDF_DLL
+ void qpdfjob_set_logger(qpdfjob_handle j, qpdflogger_handle logger);
+ QPDF_DLL
+ qpdflogger_handle qpdfjob_get_logger(qpdfjob_handle j);
+
/* This function wraps QPDFJob::initializeFromArgv. The return
* value is the same as qpdfjob_run. If this returns an error, it
* is invalid to call any other functions this job handle.
diff --git a/include/qpdf/qpdflogger-c.h b/include/qpdf/qpdflogger-c.h
index 6bf456e7..235efac1 100644
--- a/include/qpdf/qpdflogger-c.h
+++ b/include/qpdf/qpdflogger-c.h
@@ -38,16 +38,28 @@ extern "C" {
/* To operate on a logger, you need a handle to it. call
* qpdflogger_default_logger to get a handle for the default
- * logger. The qpdf and qpdfjob functions may offer ways to get
- * other logger handles. When you're done with the logger handler,
- * call qpdflogger_cleanup. This does not destroy the underlying
- * log object. It just cleans up the handle to it.
+ * logger. There are functions in qpdf-c.h and qpdfjob-c.h that
+ * also take or return logger handles. When you're done with the
+ * logger handler, call qpdflogger_cleanup. This cleans up the
+ * handle but leaves the underlying log object intact. (It uses a
+ * shared pointer and will be cleaned up automatically when it is
+ * no longer in use.) That means you can create a logger with
+ * qpdflogger_create(), pass the logger handle to a function in
+ * qpdf-c.h or qpdfjob-c.h, and then clean it up, subject to
+ * constraints imposed by the other function.
*/
typedef struct _qpdflogger_handle* qpdflogger_handle;
QPDF_DLL
qpdflogger_handle qpdflogger_default_logger();
+ /* Calling cleanup on the handle returned by qpdflogger_create
+ * destroys the handle but not the underlying logger. See comments
+ * above.
+ */
+ QPDF_DLL
+ qpdflogger_handle qpdflogger_create();
+
QPDF_DLL
void qpdflogger_cleanup(qpdflogger_handle* l);
@@ -95,6 +107,10 @@ extern "C" {
void qpdflogger_save_to_standard_output(
qpdflogger_handle l, int only_if_not_set);
+ /* For testing */
+ QPDF_DLL
+ int qpdflogger_equal(qpdflogger_handle l1, qpdflogger_handle l2);
+
#ifdef __cplusplus
}
#endif
diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc
index a8ae8102..b183c8fb 100644
--- a/libqpdf/qpdf-c.cc
+++ b/libqpdf/qpdf-c.cc
@@ -12,6 +12,7 @@
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
+#include <qpdf/qpdflogger-c_impl.hh>
#include <cstring>
#include <functional>
@@ -280,6 +281,18 @@ qpdf_check_pdf(qpdf_data qpdf)
}
void
+qpdf_set_logger(qpdf_data qpdf, qpdflogger_handle logger)
+{
+ qpdf->qpdf->setLogger(logger->l);
+}
+
+qpdflogger_handle
+qpdf_get_logger(qpdf_data qpdf)
+{
+ return new _qpdflogger_handle(qpdf->qpdf->getLogger());
+}
+
+void
qpdf_set_suppress_warnings(qpdf_data qpdf, QPDF_BOOL value)
{
QTC::TC("qpdf", "qpdf-c called qpdf_set_suppress_warnings");
diff --git a/libqpdf/qpdf/qpdflogger-c_impl.hh b/libqpdf/qpdf/qpdflogger-c_impl.hh
new file mode 100644
index 00000000..d9787a2d
--- /dev/null
+++ b/libqpdf/qpdf/qpdflogger-c_impl.hh
@@ -0,0 +1,11 @@
+#include <qpdf/qpdflogger-c.h>
+
+#include <qpdf/QPDFLogger.hh>
+
+struct _qpdflogger_handle
+{
+ _qpdflogger_handle(std::shared_ptr<QPDFLogger> l);
+ ~_qpdflogger_handle() = default;
+
+ std::shared_ptr<QPDFLogger> l;
+};
diff --git a/libqpdf/qpdfjob-c.cc b/libqpdf/qpdfjob-c.cc
index 9367547c..889afec6 100644
--- a/libqpdf/qpdfjob-c.cc
+++ b/libqpdf/qpdfjob-c.cc
@@ -4,6 +4,7 @@
#include <qpdf/QPDFLogger.hh>
#include <qpdf/QPDFUsage.hh>
#include <qpdf/QUtil.hh>
+#include <qpdf/qpdflogger-c_impl.hh>
#include <cstdio>
#include <cstring>
@@ -41,6 +42,18 @@ wrap_qpdfjob(qpdfjob_handle j, std::function<int(qpdfjob_handle j)> fn)
return QPDFJob::EXIT_ERROR;
}
+void
+qpdfjob_set_logger(qpdfjob_handle j, qpdflogger_handle logger)
+{
+ j->j.setLogger(logger->l);
+}
+
+qpdflogger_handle
+qpdfjob_get_logger(qpdfjob_handle j)
+{
+ return new _qpdflogger_handle(j->j.getLogger());
+}
+
int
qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[])
{
diff --git a/libqpdf/qpdflogger-c.cc b/libqpdf/qpdflogger-c.cc
index 290b2667..2a6d1052 100644
--- a/libqpdf/qpdflogger-c.cc
+++ b/libqpdf/qpdflogger-c.cc
@@ -1,5 +1,7 @@
#include <qpdf/qpdflogger-c.h>
+#include <qpdf/qpdflogger-c_impl.hh>
+
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Function.hh>
#include <qpdf/QIntC.hh>
@@ -7,14 +9,6 @@
#include <functional>
#include <memory>
-struct _qpdflogger_handle
-{
- _qpdflogger_handle(std::shared_ptr<QPDFLogger> l);
- ~_qpdflogger_handle() = default;
-
- std::shared_ptr<QPDFLogger> l;
-};
-
_qpdflogger_handle::_qpdflogger_handle(std::shared_ptr<QPDFLogger> l) :
l(l)
{
@@ -26,6 +20,12 @@ qpdflogger_default_logger()
return new _qpdflogger_handle(QPDFLogger::defaultLogger());
}
+qpdflogger_handle
+qpdflogger_create()
+{
+ return new _qpdflogger_handle(QPDFLogger::create());
+}
+
void
qpdflogger_cleanup(qpdflogger_handle* l)
{
@@ -125,3 +125,9 @@ qpdflogger_save_to_standard_output(qpdflogger_handle l, int only_if_not_set)
qpdflogger_set_save(
l, qpdf_log_dest_stdout, nullptr, nullptr, only_if_not_set);
}
+
+int
+qpdflogger_equal(qpdflogger_handle l1, qpdflogger_handle l2)
+{
+ return l1->l.get() == l2->l.get();
+}
diff --git a/qpdf/qpdf-ctest.c b/qpdf/qpdf-ctest.c
index b562ed8b..60986611 100644
--- a/qpdf/qpdf-ctest.c
+++ b/qpdf/qpdf-ctest.c
@@ -140,6 +140,15 @@ write_to_file(char const* data, size_t size, void* udata)
return fwrite(data, 1, size, f) != size;
}
+static int
+custom_log(char const* data, size_t size, void* udata)
+{
+ fprintf(stderr, "|custom|");
+ fwrite(data, 1, size, stderr);
+ fflush(stderr);
+ return 0;
+}
+
static void
test01(
char const* infile,
@@ -583,6 +592,20 @@ test23(
char const* outfile,
char const* xarg)
{
+ /* Test check and also exercise custom logger */
+ qpdflogger_handle l1 = qpdf_get_logger(qpdf);
+ qpdflogger_handle l2 = qpdflogger_default_logger();
+ assert(qpdflogger_equal(l1, l2));
+ qpdflogger_cleanup(&l1);
+ qpdflogger_cleanup(&l2);
+ qpdflogger_handle l = qpdflogger_create();
+ qpdflogger_set_warn(l, qpdf_log_dest_custom, custom_log, NULL);
+ qpdf_set_logger(qpdf, l);
+ qpdflogger_handle l3 = qpdf_get_logger(qpdf);
+ assert(qpdflogger_equal(l, l3));
+ qpdflogger_cleanup(&l);
+ qpdflogger_cleanup(&l3);
+
QPDF_ERROR_CODE status = 0;
qpdf_read(qpdf, infile, password);
status = qpdf_check_pdf(qpdf);
diff --git a/qpdf/qpdfjob-ctest.c b/qpdf/qpdfjob-ctest.c
index f3272aef..708d5fa6 100644
--- a/qpdf/qpdfjob-ctest.c
+++ b/qpdf/qpdfjob-ctest.c
@@ -26,6 +26,15 @@ custom_progress(int progress, void* data)
printf("%s: write progress: %d%%\n", (char const*)data, progress);
}
+static int
+custom_log(char const* data, size_t size, void* udata)
+{
+ fprintf(stderr, "|custom|");
+ fwrite(data, 1, size, stderr);
+ fflush(stderr);
+ return 0;
+}
+
static void
run_tests()
{
@@ -55,6 +64,7 @@ run_tests()
\"objectStreams\": \"generate\"\n\
}") == 0);
printf("json test passed\n");
+ fflush(stdout);
assert(qpdfjob_run_from_json("{\n\
\"inputFile\": \"xref-with-short-size.pdf\",\n\
@@ -64,10 +74,28 @@ run_tests()
\"objectStreams\": \"generate\"\n\
}") == 3);
printf("json warn test passed\n");
+ fflush(stdout);
- assert(qpdfjob_run_from_json("{\n\
+ /* Also exercise custom logger */
+ j = qpdfjob_init();
+ qpdflogger_handle l1 = qpdfjob_get_logger(j);
+ qpdflogger_handle l2 = qpdflogger_default_logger();
+ assert(qpdflogger_equal(l1, l2));
+ qpdflogger_cleanup(&l1);
+ qpdflogger_cleanup(&l2);
+ qpdflogger_handle l = qpdflogger_create();
+ qpdflogger_set_error(l, qpdf_log_dest_custom, custom_log, NULL);
+ qpdfjob_set_logger(j, l);
+ qpdflogger_handle l3 = qpdfjob_get_logger(j);
+ assert(qpdflogger_equal(l, l3));
+ qpdflogger_cleanup(&l);
+ qpdflogger_cleanup(&l3);
+
+ qpdfjob_initialize_from_json(j, "{\n\
\"inputFile\": \"nothing-there.pdf\"\n\
-}") == 2);
+}");
+ assert(qpdfjob_run(j) == 2);
+ qpdfjob_cleanup(&j);
printf("json error test passed\n");
}
diff --git a/qpdf/qtest/qpdf/c-check-warn.out b/qpdf/qtest/qpdf/c-check-warn.out
index 65602762..c733f15d 100644
--- a/qpdf/qtest/qpdf/c-check-warn.out
+++ b/qpdf/qtest/qpdf/c-check-warn.out
@@ -1,6 +1,6 @@
-WARNING: c-check-warn-in.pdf: file is damaged
-WARNING: c-check-warn-in.pdf (offset 1556): xref not found
-WARNING: c-check-warn-in.pdf: Attempting to reconstruct cross-reference table
+|custom|WARNING: |custom|c-check-warn-in.pdf: file is damaged|custom|
+|custom|WARNING: |custom|c-check-warn-in.pdf (offset 1556): xref not found|custom|
+|custom|WARNING: |custom|c-check-warn-in.pdf: Attempting to reconstruct cross-reference table|custom|
status: 1
warning: c-check-warn-in.pdf: file is damaged
code: 5
diff --git a/qpdf/qtest/qpdf/qpdfjob-ctest.out b/qpdf/qtest/qpdf/qpdfjob-ctest.out
index 22d431de..1778e70a 100644
--- a/qpdf/qtest/qpdf/qpdfjob-ctest.out
+++ b/qpdf/qtest/qpdf/qpdfjob-ctest.out
@@ -6,5 +6,6 @@ json test passed
WARNING: xref-with-short-size.pdf (xref stream, offset 16227): Cross-reference stream data has the wrong size; expected = 52; actual = 56
qpdfjob json: operation succeeded with warnings; resulting file may have some problems
json warn test passed
-qpdfjob json: an output file name is required; use - for standard output
+|custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom|
+|custom|qpdfjob json|custom|: |custom|an output file name is required; use - for standard output|custom|
json error test passed