Commit b0f054e600bd07f540ac0a081dd8b5a8cc561617
1 parent
5911a348
Add ability to initialize Pl_Function with a C-style function
Showing
4 changed files
with
119 additions
and
0 deletions
include/qpdf/Pl_Function.hh
| @@ -31,6 +31,9 @@ | @@ -31,6 +31,9 @@ | ||
| 31 | // | 31 | // |
| 32 | // It is okay to not call finish() on this pipeline if it has no | 32 | // It is okay to not call finish() on this pipeline if it has no |
| 33 | // "next". | 33 | // "next". |
| 34 | +// | ||
| 35 | +// It is okay to keep calling write() after a previous write throws an | ||
| 36 | +// exception as long as the delegated function allows it. | ||
| 34 | 37 | ||
| 35 | #include <qpdf/Pipeline.hh> | 38 | #include <qpdf/Pipeline.hh> |
| 36 | 39 | ||
| @@ -41,8 +44,26 @@ class QPDF_DLL_CLASS Pl_Function: public Pipeline | @@ -41,8 +44,26 @@ class QPDF_DLL_CLASS Pl_Function: public Pipeline | ||
| 41 | public: | 44 | public: |
| 42 | typedef std::function<void(unsigned char const*, size_t)> writer_t; | 45 | typedef std::function<void(unsigned char const*, size_t)> writer_t; |
| 43 | 46 | ||
| 47 | + // The supplied function is called every time write is called. | ||
| 44 | QPDF_DLL | 48 | QPDF_DLL |
| 45 | Pl_Function(char const* identifier, Pipeline* next, writer_t fn); | 49 | Pl_Function(char const* identifier, Pipeline* next, writer_t fn); |
| 50 | + | ||
| 51 | + // The supplied C-style function is called every time write is | ||
| 52 | + // called. The udata option is passed into the function with each | ||
| 53 | + // call. If the function returns a non-zero value, a runtime error | ||
| 54 | + // is thrown. | ||
| 55 | + typedef int (*writer_c_t)(unsigned char const*, size_t, void*); | ||
| 56 | + QPDF_DLL | ||
| 57 | + Pl_Function( | ||
| 58 | + char const* identifier, Pipeline* next, writer_c_t fn, void* udata); | ||
| 59 | + typedef int (*writer_c_char_t)(char const*, size_t, void*); | ||
| 60 | + QPDF_DLL | ||
| 61 | + Pl_Function( | ||
| 62 | + char const* identifier, | ||
| 63 | + Pipeline* next, | ||
| 64 | + writer_c_char_t fn, | ||
| 65 | + void* udata); | ||
| 66 | + | ||
| 46 | QPDF_DLL | 67 | QPDF_DLL |
| 47 | virtual ~Pl_Function(); | 68 | virtual ~Pl_Function(); |
| 48 | 69 |
libqpdf/Pl_Function.cc
| @@ -15,6 +15,36 @@ Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_t fn) : | @@ -15,6 +15,36 @@ Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_t fn) : | ||
| 15 | { | 15 | { |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | +Pl_Function::Pl_Function( | ||
| 19 | + char const* identifier, Pipeline* next, writer_c_t fn, void* udata) : | ||
| 20 | + Pipeline(identifier, next), | ||
| 21 | + m(new Members(nullptr)) | ||
| 22 | +{ | ||
| 23 | + m->fn = [identifier, fn, udata](unsigned char const* data, size_t len) { | ||
| 24 | + int code = fn(data, len, udata); | ||
| 25 | + if (code != 0) { | ||
| 26 | + throw std::runtime_error( | ||
| 27 | + std::string(identifier) + " function returned code " + | ||
| 28 | + QUtil::int_to_string(code)); | ||
| 29 | + } | ||
| 30 | + }; | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +Pl_Function::Pl_Function( | ||
| 34 | + char const* identifier, Pipeline* next, writer_c_char_t fn, void* udata) : | ||
| 35 | + Pipeline(identifier, next), | ||
| 36 | + m(new Members(nullptr)) | ||
| 37 | +{ | ||
| 38 | + m->fn = [identifier, fn, udata](unsigned char const* data, size_t len) { | ||
| 39 | + int code = fn(reinterpret_cast<char const*>(data), len, udata); | ||
| 40 | + if (code != 0) { | ||
| 41 | + throw std::runtime_error( | ||
| 42 | + std::string(identifier) + " function returned code " + | ||
| 43 | + QUtil::int_to_string(code)); | ||
| 44 | + } | ||
| 45 | + }; | ||
| 46 | +} | ||
| 47 | + | ||
| 18 | Pl_Function::~Pl_Function() | 48 | Pl_Function::~Pl_Function() |
| 19 | { | 49 | { |
| 20 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in | 50 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in |
libtests/pl_function.cc
| @@ -5,6 +5,38 @@ | @@ -5,6 +5,38 @@ | ||
| 5 | #include <qpdf/Pl_String.hh> | 5 | #include <qpdf/Pl_String.hh> |
| 6 | #include <iostream> | 6 | #include <iostream> |
| 7 | 7 | ||
| 8 | +namespace | ||
| 9 | +{ | ||
| 10 | + struct Count | ||
| 11 | + { | ||
| 12 | + int count{0}; | ||
| 13 | + }; | ||
| 14 | +} // namespace | ||
| 15 | + | ||
| 16 | +int | ||
| 17 | +f(unsigned char const* data, size_t len, void* udata) | ||
| 18 | +{ | ||
| 19 | + auto c = reinterpret_cast<Count*>(udata); | ||
| 20 | + ++c->count; | ||
| 21 | + std::cout << "got " << data << "(" << len << ")" << std::endl; | ||
| 22 | + if (c->count == 3) { | ||
| 23 | + return 1; | ||
| 24 | + } | ||
| 25 | + return 0; | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +int | ||
| 29 | +g(char const* data, size_t len, void* udata) | ||
| 30 | +{ | ||
| 31 | + auto c = reinterpret_cast<Count*>(udata); | ||
| 32 | + ++c->count; | ||
| 33 | + std::cout << "signed got " << data << "(" << len << ")" << std::endl; | ||
| 34 | + if (c->count == 2) { | ||
| 35 | + return 2; | ||
| 36 | + } | ||
| 37 | + return 0; | ||
| 38 | +} | ||
| 39 | + | ||
| 8 | int | 40 | int |
| 9 | main(int argc, char* argv[]) | 41 | main(int argc, char* argv[]) |
| 10 | { | 42 | { |
| @@ -23,5 +55,32 @@ main(int argc, char* argv[]) | @@ -23,5 +55,32 @@ main(int argc, char* argv[]) | ||
| 23 | p2.finish(); | 55 | p2.finish(); |
| 24 | assert(s == "c2FsYWQ="); | 56 | assert(s == "c2FsYWQ="); |
| 25 | 57 | ||
| 58 | + Count c; | ||
| 59 | + Pl_Function p3("c-function", nullptr, f, &c); | ||
| 60 | + p3 << "one"; | ||
| 61 | + p3 << "two"; | ||
| 62 | + try { | ||
| 63 | + p3 << "three"; | ||
| 64 | + assert(false); | ||
| 65 | + } catch (std::runtime_error& e) { | ||
| 66 | + std::cout << "three threw " << e.what() << std::endl; | ||
| 67 | + } | ||
| 68 | + p3 << "four"; | ||
| 69 | + p3.finish(); | ||
| 70 | + assert(c.count == 4); | ||
| 71 | + | ||
| 72 | + c.count = 0; | ||
| 73 | + Pl_Function p4("c-function", nullptr, g, &c); | ||
| 74 | + p4 << "potato"; | ||
| 75 | + try { | ||
| 76 | + p4 << "salad"; | ||
| 77 | + assert(false); | ||
| 78 | + } catch (std::runtime_error& e) { | ||
| 79 | + std::cout << "salad threw " << e.what() << std::endl; | ||
| 80 | + } | ||
| 81 | + p4 << "quack"; | ||
| 82 | + p4.finish(); | ||
| 83 | + assert(c.count == 3); | ||
| 84 | + | ||
| 26 | return 0; | 85 | return 0; |
| 27 | } | 86 | } |
libtests/qtest/pl_function/exp