From 8e361d98f0bb23d58cbc773367ba76dffced7bdb Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 18 Jun 2022 14:16:56 -0400 Subject: Add examples for output capture (fixes #691) --- examples/CMakeLists.txt | 6 +- examples/qpdfjob-c-save-attachment.c | 100 +++++++++++++++++++++++++++ examples/qpdfjob-c.c | 4 ++ examples/qpdfjob-save-attachment.cc | 51 ++++++++++++++ examples/qtest/qpdfjob-attachment/attach.pdf | Bin 0 -> 1290 bytes examples/qtest/save-attachment.test | 42 +++++++++++ 6 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 examples/qpdfjob-c-save-attachment.c create mode 100644 examples/qpdfjob-save-attachment.cc create mode 100644 examples/qtest/qpdfjob-attachment/attach.pdf create mode 100644 examples/qtest/save-attachment.test (limited to 'examples') diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 40ecd603..947068dd 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -14,11 +14,13 @@ set(EXAMPLE_CXX_PROGRAMS pdf-parse-content pdf-set-form-values pdf-split-pages - qpdf-job) + qpdf-job + qpdfjob-save-attachment) set(EXAMPLE_C_PROGRAMS pdf-c-objects pdf-linearize - qpdfjob-c) + qpdfjob-c + qpdfjob-c-save-attachment) foreach(PROG ${EXAMPLE_CXX_PROGRAMS}) add_executable(${PROG} ${PROG}.cc) diff --git a/examples/qpdfjob-c-save-attachment.c b/examples/qpdfjob-c-save-attachment.c new file mode 100644 index 00000000..950e297b --- /dev/null +++ b/examples/qpdfjob-c-save-attachment.c @@ -0,0 +1,100 @@ +#include +#include +#include + +#include +#include +#include +#include + +// This example demonstrates how we can redirect where saved output +// goes by calling the default logger's setSave method before running +// something with QPDFJob. See qpdfjob-c-save-attachment.c for an +// implementation that uses the C API. + +static void +save_to_file(char const* data, size_t len, void* udata) +{ + FILE* f = (FILE*)udata; + fwrite(data, 1, len, f); +} + +static FILE* +do_fopen(char const* filename) +{ + FILE* f = NULL; +#ifdef _MSC_VER + if (fopen_s(&f, filename, "wb") != 0) { + f = NULL; + } +#else + f = fopen(filename, "wb"); +#endif + if (f == NULL) { + fprintf(stderr, "unable to open %s\n", filename); + exit(2); + } + return f; +} + +int +main(int argc, char* argv[]) +{ + char const* whoami = "qpdfjob-c-save-attachment"; + char const* filename = NULL; + char const* key = NULL; + char const* outfilename = NULL; + char* attachment_arg = NULL; + char const* attachment_flag = "--show-attachment="; + size_t flag_len = 0; + FILE* outfile = NULL; + int status = 0; + qpdfjob_handle j = NULL; + qpdflogger_handle l = qpdflogger_default_logger(); + + if (argc != 4) { + fprintf(stderr, "Usage: %s file attachment-key outfile\n", whoami); + exit(2); + } + + filename = argv[1]; + key = argv[2]; + outfilename = argv[3]; + + flag_len = strlen(attachment_flag) + strlen(key) + 1; + attachment_arg = malloc(flag_len); +#ifdef _MSC_VER + strncpy_s(attachment_arg, flag_len, attachment_flag, flag_len); + strncat_s(attachment_arg, flag_len, key, flag_len - strlen(attachment_arg)); +#else + strncpy(attachment_arg, attachment_flag, flag_len); + strncat(attachment_arg, key, flag_len - strlen(attachment_arg)); +#endif + + char const* j_argv[5] = { + whoami, + filename, + attachment_arg, + "--", + NULL, + }; + outfile = do_fopen(outfilename); + + /* Use qpdflogger_set_save with a callback function to redirect + * saved data. You can use other qpdf logger functions to capture + * informational output, warnings, and errors. + */ + qpdflogger_set_save( + l, qpdf_log_dest_custom, save_to_file, (void*)outfile, 0); + qpdflogger_cleanup(&l); + j = qpdfjob_init(); + status = (qpdfjob_initialize_from_argv(j, j_argv) || + qpdfjob_run(j)); + qpdfjob_cleanup(&j); + free(attachment_arg); + fclose(outfile); + if (status == qpdf_exit_success) { + printf("%s: wrote attachment to %s\n", whoami, outfilename); + } + return 0; +} diff --git a/examples/qpdfjob-c.c b/examples/qpdfjob-c.c index ee2ef4ab..452e689b 100644 --- a/examples/qpdfjob-c.c +++ b/examples/qpdfjob-c.c @@ -52,6 +52,10 @@ main(int argc, char* argv[]) * To use that from C just like the argv one, call * qpdfjob_run_from_json instead and pass the json string as a * single char const* argument. + * + * See qpdfjob-c-save-attachment.c for an example of using the + * full form of the qpdfjob interface with init and cleanup + * functions. */ r = qpdfjob_run_from_argv(new_argv); return r; diff --git a/examples/qpdfjob-save-attachment.cc b/examples/qpdfjob-save-attachment.cc new file mode 100644 index 00000000..2c08620a --- /dev/null +++ b/examples/qpdfjob-save-attachment.cc @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +// This example demonstrates how we can redirect where saved output +// goes by calling the default logger's setSave method before running +// something with QPDFJob. See qpdfjob-c-save-attachment.c for an +// implementation that uses the C API. + +int +main(int argc, char* argv[]) +{ + auto whoami = QUtil::getWhoami(argv[0]); + + if (argc != 4) { + std::cerr << "Usage: " << whoami << " file attachment-key outfile" + << std::endl; + exit(2); + } + + char const* filename = argv[1]; + char const* key = argv[2]; + char const* outfilename = argv[3]; + std::string attachment_arg = "--show-attachment="; + attachment_arg += key; + + char const* j_argv[] = { + whoami, + filename, + attachment_arg.c_str(), + "--", + nullptr, + }; + + QUtil::FileCloser fc(QUtil::safe_fopen(outfilename, "wb")); + auto save = std::make_shared("capture", fc.f); + QPDFLogger::defaultLogger()->setSave(save, false); + + try { + QPDFJob j; + j.initializeFromArgv(j_argv); + j.run(); + } catch (std::exception& e) { + std::cerr << whoami << ": " << e.what() << std::endl; + exit(2); + } + + std::cout << whoami << ": wrote attachment to " << outfilename << std::endl; + return 0; +} diff --git a/examples/qtest/qpdfjob-attachment/attach.pdf b/examples/qtest/qpdfjob-attachment/attach.pdf new file mode 100644 index 00000000..bbc09588 Binary files /dev/null and b/examples/qtest/qpdfjob-attachment/attach.pdf differ diff --git a/examples/qtest/save-attachment.test b/examples/qtest/save-attachment.test new file mode 100644 index 00000000..2486a29c --- /dev/null +++ b/examples/qtest/save-attachment.test @@ -0,0 +1,42 @@ +#!/usr/bin/env perl +require 5.008; +use warnings; +use strict; + +chdir("qpdfjob-attachment") or die "chdir testdir failed: $!\n"; + +require TestDriver; + +cleanup(); + +my $td = new TestDriver('qpdfjob-attachment'); + +$td->runtest("save attachment (C)", + {$td->COMMAND => "qpdfjob-c-save-attachment attach.pdf a a"}, + {$td->STRING => + "qpdfjob-c-save-attachment: wrote attachment to a\n", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a"}, + {$td->STRING => "quack\n"}, + $td->NORMALIZE_NEWLINES); +$td->runtest("save attachment (C++)", + {$td->COMMAND => "qpdfjob-save-attachment attach.pdf a b"}, + {$td->STRING => + "qpdfjob-save-attachment: wrote attachment to b\n", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "b"}, + {$td->STRING => "quack\n"}, + $td->NORMALIZE_NEWLINES); + +cleanup(); + +$td->report(4); + +sub cleanup +{ + unlink "a", "b"; +} -- cgit v1.2.3-54-g00ecf