aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-09-08 22:38:36 +0200
committerJay Berkenbilt <ejb@ql.org>2022-09-08 23:35:27 +0200
commitb0f054e600bd07f540ac0a081dd8b5a8cc561617 (patch)
tree5e539e77e5b2fc3f54e1380eb2b9877662bc43ef
parent5911a348a5ae9065610be5fe5f251cab399a52b8 (diff)
downloadqpdf-b0f054e600bd07f540ac0a081dd8b5a8cc561617.tar.zst
Add ability to initialize Pl_Function with a C-style function
-rw-r--r--include/qpdf/Pl_Function.hh21
-rw-r--r--libqpdf/Pl_Function.cc30
-rw-r--r--libtests/pl_function.cc59
-rw-r--r--libtests/qtest/pl_function/exp9
4 files changed, 119 insertions, 0 deletions
diff --git a/include/qpdf/Pl_Function.hh b/include/qpdf/Pl_Function.hh
index dd700e80..41c56a98 100644
--- a/include/qpdf/Pl_Function.hh
+++ b/include/qpdf/Pl_Function.hh
@@ -31,6 +31,9 @@
//
// It is okay to not call finish() on this pipeline if it has no
// "next".
+//
+// It is okay to keep calling write() after a previous write throws an
+// exception as long as the delegated function allows it.
#include <qpdf/Pipeline.hh>
@@ -41,8 +44,26 @@ class QPDF_DLL_CLASS Pl_Function: public Pipeline
public:
typedef std::function<void(unsigned char const*, size_t)> writer_t;
+ // The supplied function is called every time write is called.
QPDF_DLL
Pl_Function(char const* identifier, Pipeline* next, writer_t fn);
+
+ // The supplied C-style function is called every time write is
+ // called. The udata option is passed into the function with each
+ // call. If the function returns a non-zero value, a runtime error
+ // is thrown.
+ typedef int (*writer_c_t)(unsigned char const*, size_t, void*);
+ QPDF_DLL
+ Pl_Function(
+ char const* identifier, Pipeline* next, writer_c_t fn, void* udata);
+ typedef int (*writer_c_char_t)(char const*, size_t, void*);
+ QPDF_DLL
+ Pl_Function(
+ char const* identifier,
+ Pipeline* next,
+ writer_c_char_t fn,
+ void* udata);
+
QPDF_DLL
virtual ~Pl_Function();
diff --git a/libqpdf/Pl_Function.cc b/libqpdf/Pl_Function.cc
index 32fcccf1..5f2dc042 100644
--- a/libqpdf/Pl_Function.cc
+++ b/libqpdf/Pl_Function.cc
@@ -15,6 +15,36 @@ Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_t fn) :
{
}
+Pl_Function::Pl_Function(
+ char const* identifier, Pipeline* next, writer_c_t fn, void* udata) :
+ Pipeline(identifier, next),
+ m(new Members(nullptr))
+{
+ m->fn = [identifier, fn, udata](unsigned char const* data, size_t len) {
+ int code = fn(data, len, udata);
+ if (code != 0) {
+ throw std::runtime_error(
+ std::string(identifier) + " function returned code " +
+ QUtil::int_to_string(code));
+ }
+ };
+}
+
+Pl_Function::Pl_Function(
+ char const* identifier, Pipeline* next, writer_c_char_t fn, void* udata) :
+ Pipeline(identifier, next),
+ m(new Members(nullptr))
+{
+ m->fn = [identifier, fn, udata](unsigned char const* data, size_t len) {
+ int code = fn(reinterpret_cast<char const*>(data), len, udata);
+ if (code != 0) {
+ throw std::runtime_error(
+ std::string(identifier) + " function returned code " +
+ QUtil::int_to_string(code));
+ }
+ };
+}
+
Pl_Function::~Pl_Function()
{
// Must be explicit and not inline -- see QPDF_DLL_CLASS in
diff --git a/libtests/pl_function.cc b/libtests/pl_function.cc
index 101ec02e..2829671b 100644
--- a/libtests/pl_function.cc
+++ b/libtests/pl_function.cc
@@ -5,6 +5,38 @@
#include <qpdf/Pl_String.hh>
#include <iostream>
+namespace
+{
+ struct Count
+ {
+ int count{0};
+ };
+} // namespace
+
+int
+f(unsigned char const* data, size_t len, void* udata)
+{
+ auto c = reinterpret_cast<Count*>(udata);
+ ++c->count;
+ std::cout << "got " << data << "(" << len << ")" << std::endl;
+ if (c->count == 3) {
+ return 1;
+ }
+ return 0;
+}
+
+int
+g(char const* data, size_t len, void* udata)
+{
+ auto c = reinterpret_cast<Count*>(udata);
+ ++c->count;
+ std::cout << "signed got " << data << "(" << len << ")" << std::endl;
+ if (c->count == 2) {
+ return 2;
+ }
+ return 0;
+}
+
int
main(int argc, char* argv[])
{
@@ -23,5 +55,32 @@ main(int argc, char* argv[])
p2.finish();
assert(s == "c2FsYWQ=");
+ Count c;
+ Pl_Function p3("c-function", nullptr, f, &c);
+ p3 << "one";
+ p3 << "two";
+ try {
+ p3 << "three";
+ assert(false);
+ } catch (std::runtime_error& e) {
+ std::cout << "three threw " << e.what() << std::endl;
+ }
+ p3 << "four";
+ p3.finish();
+ assert(c.count == 4);
+
+ c.count = 0;
+ Pl_Function p4("c-function", nullptr, g, &c);
+ p4 << "potato";
+ try {
+ p4 << "salad";
+ assert(false);
+ } catch (std::runtime_error& e) {
+ std::cout << "salad threw " << e.what() << std::endl;
+ }
+ p4 << "quack";
+ p4.finish();
+ assert(c.count == 3);
+
return 0;
}
diff --git a/libtests/qtest/pl_function/exp b/libtests/qtest/pl_function/exp
index fd2ea1bc..930240d9 100644
--- a/libtests/qtest/pl_function/exp
+++ b/libtests/qtest/pl_function/exp
@@ -1,2 +1,11 @@
p1: 6: potato
p2: 5: salad
+got one(3)
+got two(3)
+got three(5)
+three threw c-function function returned code 1
+got four(4)
+signed got potato(6)
+signed got salad(5)
+salad threw c-function function returned code 2
+signed got quack(5)