diff --git a/include/qpdf/Pl_Function.hh b/include/qpdf/Pl_Function.hh new file mode 100644 index 00000000..dd700e80 --- /dev/null +++ b/include/qpdf/Pl_Function.hh @@ -0,0 +1,73 @@ +// Copyright (c) 2005-2022 Jay Berkenbilt +// +// This file is part of qpdf. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. + +#ifndef PL_FUNCTION_HH +#define PL_FUNCTION_HH + +// This pipeline calls an arbitrary function with whatever data is +// passed to it. This pipeline can be reused. +// +// For this pipeline, "next" may be null. If a next pointer is +// provided, this pipeline will also pass the data through to it and +// will forward finish() to it. +// +// It is okay to not call finish() on this pipeline if it has no +// "next". + +#include + +#include + +class QPDF_DLL_CLASS Pl_Function: public Pipeline +{ + public: + typedef std::function writer_t; + + QPDF_DLL + Pl_Function(char const* identifier, Pipeline* next, writer_t fn); + QPDF_DLL + virtual ~Pl_Function(); + + QPDF_DLL + virtual void write(unsigned char const* buf, size_t len); + QPDF_DLL + virtual void finish(); + + private: + class QPDF_DLL_PRIVATE Members + { + friend class Pl_Function; + + public: + QPDF_DLL + ~Members() = default; + + private: + Members(writer_t); + Members(Members const&) = delete; + + writer_t fn; + }; + + std::shared_ptr m; +}; + +#endif // PL_FUNCTION_HH diff --git a/include/qpdf/Pl_String.hh b/include/qpdf/Pl_String.hh index 327598da..906a2660 100644 --- a/include/qpdf/Pl_String.hh +++ b/include/qpdf/Pl_String.hh @@ -30,11 +30,11 @@ // provided, this pipeline will also pass the data through to it and // will forward finish() to it. // -// It is okay to not call finish() on this pipeline. This makes it -// easy to stick this in front of another pipeline to capture data -// that is written to the other pipeline without interfering with when -// finish is called on the other pipeline and without having to put a -// Pl_Concatenate after it. +// It is okay to not call finish() on this pipeline if it has no +// "next". This makes it easy to stick this in front of another +// pipeline to capture data that is written to the other pipeline +// without interfering with when finish is called on the other +// pipeline and without having to put a Pl_Concatenate after it. #include diff --git a/libqpdf/CMakeLists.txt b/libqpdf/CMakeLists.txt index 3c14115b..a6e30163 100644 --- a/libqpdf/CMakeLists.txt +++ b/libqpdf/CMakeLists.txt @@ -42,6 +42,7 @@ set(libqpdf_SOURCES Pl_DCT.cc Pl_Discard.cc Pl_Flate.cc + Pl_Function.cc Pl_LZWDecoder.cc Pl_MD5.cc Pl_OStream.cc diff --git a/libqpdf/Pl_Function.cc b/libqpdf/Pl_Function.cc new file mode 100644 index 00000000..32fcccf1 --- /dev/null +++ b/libqpdf/Pl_Function.cc @@ -0,0 +1,39 @@ +#include + +#include +#include +#include + +Pl_Function::Members::Members(writer_t fn) : + fn(fn) +{ +} + +Pl_Function::Pl_Function(char const* identifier, Pipeline* next, writer_t fn) : + Pipeline(identifier, next), + m(new Members(fn)) +{ +} + +Pl_Function::~Pl_Function() +{ + // Must be explicit and not inline -- see QPDF_DLL_CLASS in + // README-maintainer +} + +void +Pl_Function::write(unsigned char const* buf, size_t len) +{ + this->m->fn(buf, len); + if (getNext(true)) { + getNext()->write(buf, len); + } +} + +void +Pl_Function::finish() +{ + if (getNext(true)) { + getNext()->finish(); + } +} diff --git a/libtests/CMakeLists.txt b/libtests/CMakeLists.txt index 62ba390e..ea4dc7cd 100644 --- a/libtests/CMakeLists.txt +++ b/libtests/CMakeLists.txt @@ -24,6 +24,7 @@ set(TEST_PROGRAMS nntree numrange pdf_version + pl_function pointer_holder predictors qintc diff --git a/libtests/pl_function.cc b/libtests/pl_function.cc new file mode 100644 index 00000000..960ad5cb --- /dev/null +++ b/libtests/pl_function.cc @@ -0,0 +1,29 @@ +#include + +#include +#include +#include +#include + +int +main(int argc, char* argv[]) +{ + Pl_Function p1( + "p1", nullptr, [](unsigned char const* data, size_t len) { + std::cout << "p1: " << len << ": " << data << std::endl; + }); + p1.write(reinterpret_cast("potato"), 6); + + std::string s; + Pl_String ps("string", nullptr, s); + Pl_Base64 b("base64", &ps, Pl_Base64::a_encode); + Pl_Function p2( + "p2", &b, [](unsigned char const* data, size_t len) { + std::cout << "p2: " << len << ": " << data << std::endl; + }); + p2.write(reinterpret_cast("salad"), 5); + p2.finish(); + assert(s == "c2FsYWQ="); + + return 0; +} diff --git a/libtests/qtest/pl_function.test b/libtests/qtest/pl_function.test new file mode 100644 index 00000000..847aa472 --- /dev/null +++ b/libtests/qtest/pl_function.test @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +require 5.008; +use warnings; +use strict; + +chdir("pl_function") or die "chdir testdir failed: $!\n"; + +require TestDriver; + +my $td = new TestDriver('pl_function'); + +$td->runtest("pl_function", + {$td->COMMAND => "pl_function"}, + {$td->FILE => "exp", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + +$td->report(1); diff --git a/libtests/qtest/pl_function/exp b/libtests/qtest/pl_function/exp new file mode 100644 index 00000000..fd2ea1bc --- /dev/null +++ b/libtests/qtest/pl_function/exp @@ -0,0 +1,2 @@ +p1: 6: potato +p2: 5: salad diff --git a/qpdf/sizes.cc b/qpdf/sizes.cc index 6d4635fd..12843ab2 100644 --- a/qpdf/sizes.cc +++ b/qpdf/sizes.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ main() print_size(Pl_DCT); print_size(Pl_Discard); print_size(Pl_Flate); + print_size(Pl_Function); print_size(Pl_OStream); print_size(Pl_QPDFTokenizer); print_size(Pl_RunLength);