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 | 31 | // |
| 32 | 32 | // It is okay to not call finish() on this pipeline if it has no |
| 33 | 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 | 38 | #include <qpdf/Pipeline.hh> |
| 36 | 39 | |
| ... | ... | @@ -41,8 +44,26 @@ class QPDF_DLL_CLASS Pl_Function: public Pipeline |
| 41 | 44 | public: |
| 42 | 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 | 48 | QPDF_DLL |
| 45 | 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 | 67 | QPDF_DLL |
| 47 | 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 | 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 | 48 | Pl_Function::~Pl_Function() |
| 19 | 49 | { |
| 20 | 50 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in | ... | ... |
libtests/pl_function.cc
| ... | ... | @@ -5,6 +5,38 @@ |
| 5 | 5 | #include <qpdf/Pl_String.hh> |
| 6 | 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 | 40 | int |
| 9 | 41 | main(int argc, char* argv[]) |
| 10 | 42 | { |
| ... | ... | @@ -23,5 +55,32 @@ main(int argc, char* argv[]) |
| 23 | 55 | p2.finish(); |
| 24 | 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 | 85 | return 0; |
| 27 | 86 | } | ... | ... |
libtests/qtest/pl_function/exp