Add Pl_Function -- a generic function pipeline

This commit is contained in:
Jay Berkenbilt 2022-06-19 08:56:36 -04:00
parent bb0ea2f8e7
commit eae75dbe44
9 changed files with 169 additions and 5 deletions

View File

@ -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 <qpdf/Pipeline.hh>
#include <functional>
class QPDF_DLL_CLASS Pl_Function: public Pipeline
{
public:
typedef std::function<void(unsigned char const*, size_t)> 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<Members> m;
};
#endif // PL_FUNCTION_HH

View File

@ -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 <qpdf/Pipeline.hh>

View File

@ -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

39
libqpdf/Pl_Function.cc Normal file
View File

@ -0,0 +1,39 @@
#include <qpdf/Pl_Function.hh>
#include <qpdf/QUtil.hh>
#include <errno.h>
#include <stdexcept>
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();
}
}

View File

@ -24,6 +24,7 @@ set(TEST_PROGRAMS
nntree
numrange
pdf_version
pl_function
pointer_holder
predictors
qintc

29
libtests/pl_function.cc Normal file
View File

@ -0,0 +1,29 @@
#include <qpdf/assert_test.h>
#include <qpdf/Pl_Function.hh>
#include <qpdf/Pl_String.hh>
#include <qpdf/Pl_Base64.hh>
#include <iostream>
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<unsigned char const*>("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<unsigned char const*>("salad"), 5);
p2.finish();
assert(s == "c2FsYWQ=");
return 0;
}

View File

@ -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);

View File

@ -0,0 +1,2 @@
p1: 6: potato
p2: 5: salad

View File

@ -16,6 +16,7 @@
#include <qpdf/Pl_DCT.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_Flate.hh>
#include <qpdf/Pl_Function.hh>
#include <qpdf/Pl_OStream.hh>
#include <qpdf/Pl_QPDFTokenizer.hh>
#include <qpdf/Pl_RunLength.hh>
@ -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);