Add more flexible funtions to qpdfjob C API

This commit is contained in:
Jay Berkenbilt 2022-06-19 08:20:43 -04:00
parent 28cc3692e3
commit daef4e8fb8
7 changed files with 158 additions and 26 deletions

View File

@ -1,5 +1,7 @@
2022-06-18 Jay Berkenbilt <ejb@ql.org>
* Add additional qpdfjob C API functions take a handle.
* Add qpdf_exit_code_e to Constants.h so that exit codes from
QPDFJob are accessible to the C API.

View File

@ -108,6 +108,8 @@ class QPDFJob
// and error streams on the caller's behalf. Defaults to "qpdf".
QPDF_DLL
void setMessagePrefix(std::string const&);
QPDF_DLL
std::string getMessagePrefix() const;
// To capture or redirect output, configure the logger returned by
// getLogger(). By default, all QPDF and QPDFJob objects share the

View File

@ -45,6 +45,11 @@
#ifdef __cplusplus
extern "C" {
#endif
/* SHORT INTERFACE -- These functions are single calls that take
* care of the whole life cycle of QPDFJob. They can be used for
* one-shot ooperations where no additional configuration is
* needed. See FULL INTERFACE below. */
/* This function does the equivalent of running the qpdf
* command-line with the given arguments and returns the exit code
* that qpdf would use. argv must be a null-terminated array of
@ -74,6 +79,52 @@ extern "C" {
QPDF_DLL
int qpdfjob_run_from_json(char const* json);
/* FULL INTERFACE -- new in qpdf11. Similar to the qpdf-c.h API,
* you must call qpdfjob_init to get a qpdfjob_handle and, when
* done, call qpdfjob_cleanup to free resources. Remaining methods
* take qpdfjob_handle as an argument. This interface requires
* more calls but also offers greater flexibility.
*/
typedef struct _qpdfjob_handle* qpdfjob_handle;
QPDF_DLL
qpdfjob_handle qpdfjob_init();
QPDF_DLL
void qpdfjob_cleanup(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.
*/
QPDF_DLL
int
qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[]);
#ifndef QPDF_NO_WCHAR_T
/* This function is the same as qpdfjob_initialize_from_argv
* except argv is encoded with wide characters. This would be
* suitable for calling from a Windows wmain function.
*/
QPDF_DLL
int qpdfjob_initialize_from_wide_argv(
qpdfjob_handle j, wchar_t const* const argv[]);
#endif /* QPDF_NO_WCHAR_T */
/* This function wraps QPDFJob::initializeFromJson. 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.
*/
QPDF_DLL
int qpdfjob_initialize_from_json(qpdfjob_handle j, char const* json);
/* This function wraps QPDFJob::run. It returns the error code
* that qpdf would return with the equivalent command-line
* invocation. Exit code values are defined in Constants.h in the
* qpdf_exit_code_e type.
*/
QPDF_DLL
int qpdfjob_run(qpdfjob_handle j);
#ifdef __cplusplus
}
#endif

View File

@ -438,6 +438,12 @@ QPDFJob::setMessagePrefix(std::string const& message_prefix)
this->m->message_prefix = message_prefix;
}
std::string
QPDFJob::getMessagePrefix() const
{
return this->m->message_prefix;
}
std::shared_ptr<QPDFLogger>
QPDFJob::getLogger()
{

View File

@ -8,51 +8,115 @@
#include <cstdio>
#include <cstring>
int
qpdfjob_run_from_argv(char const* const argv[])
struct _qpdfjob_handle
{
auto whoami_p = QUtil::make_unique_cstr(argv[0]);
auto whoami = QUtil::getWhoami(whoami_p.get());
QUtil::setLineBuf(stdout);
_qpdfjob_handle() = default;
~_qpdfjob_handle() = default;
QPDFJob j;
};
qpdfjob_handle
qpdfjob_init()
{
return new _qpdfjob_handle;
}
void
qpdfjob_cleanup(qpdfjob_handle* j)
{
delete *j;
*j = nullptr;
}
static int
wrap_qpdfjob(qpdfjob_handle j, std::function<int(qpdfjob_handle j)> fn)
{
try {
j.initializeFromArgv(argv);
j.run();
return fn(j);
} catch (std::exception& e) {
*QPDFLogger::defaultLogger()->getError()
<< whoami << ": " << e.what() << "\n";
return QPDFJob::EXIT_ERROR;
*j->j.getLogger()->getError()
<< j->j.getMessagePrefix() << ": " << e.what() << "\n";
}
return j.getExitCode();
return QPDFJob::EXIT_ERROR;
}
int
qpdfjob_initialize_from_argv(qpdfjob_handle j, char const* const argv[])
{
return wrap_qpdfjob(j, [argv](qpdfjob_handle jh) {
jh->j.initializeFromArgv(argv);
return 0;
});
}
#ifndef QPDF_NO_WCHAR_T
int
qpdfjob_run_from_wide_argv(wchar_t const* const argv[])
qpdfjob_initialize_from_wide_argv(qpdfjob_handle j, wchar_t const* const argv[])
{
int argc = 0;
for (auto k = argv; *k; ++k) {
++argc;
}
return QUtil::call_main_from_wmain(
argc, argv, [](int, char const* const new_argv[]) {
return qpdfjob_run_from_argv(new_argv);
argc, argv, [j](int, char const* const new_argv[]) {
return qpdfjob_initialize_from_argv(j, new_argv);
});
}
#endif // QPDF_NO_WCHAR_T
int
qpdfjob_run_from_json(char const* json)
qpdfjob_initialize_from_json(qpdfjob_handle j, char const* json)
{
QPDFJob j;
try {
j.initializeFromJson(json);
j.run();
} catch (std::exception& e) {
*QPDFLogger::defaultLogger()->getError()
<< "qpdfjob json: " << e.what() << "\n";
return QPDFJob::EXIT_ERROR;
}
return j.getExitCode();
return wrap_qpdfjob(j, [json](qpdfjob_handle jh) {
jh->j.setMessagePrefix("qpdfjob json");
jh->j.initializeFromJson(json);
return 0;
});
}
int
qpdfjob_run(qpdfjob_handle j)
{
QUtil::setLineBuf(stdout);
return wrap_qpdfjob(j, [](qpdfjob_handle jh) {
jh->j.run();
return jh->j.getExitCode();
});
}
static int run_with_handle(std::function<int(qpdfjob_handle)> fn)
{
auto j = qpdfjob_init();
int status = fn(j);
if (status == 0) {
status = qpdfjob_run(j);
}
qpdfjob_cleanup(&j);
return status;
}
int qpdfjob_run_from_argv(char const* const argv[])
{
return run_with_handle([argv](qpdfjob_handle j) {
return qpdfjob_initialize_from_argv(j, argv);
});
}
#ifndef QPDF_NO_WCHAR_T
int
qpdfjob_run_from_wide_argv(wchar_t const* const argv[])
{
return run_with_handle([argv](qpdfjob_handle j) {
return qpdfjob_initialize_from_wide_argv(j, argv);
});
}
#endif /* QPDF_NO_WCHAR_T */
int qpdfjob_run_from_json(char const* json)
{
return run_with_handle([json](qpdfjob_handle j) {
return qpdfjob_initialize_from_json(j, json);
});
}

View File

@ -188,6 +188,13 @@ For a detailed list of changes, please see the file
writing large amounts of data without having to keep everything
in memory.
- Add new functions to the C API for qpdfjob that use a
``qpdfjob_handle``. Like with the regular C API for qpdf, you
have to call ``qpdfjob_init`` first, pass the handle to the
functions, and call ``qpdfjob_cleanup`` at the end. This
interface offers more flexibility than the old interface, which
remains available.
- Other changes
- In JSON v1 mode, the ``"objects"`` key now reflects the repaired

View File

@ -1,7 +1,7 @@
argv test passed
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
qpdf: operation succeeded with warnings; resulting file may have some problems
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
json error test passed