From 041397fdabde66574824db7582a26ef1e3fbfc65 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 23 Sep 2012 17:42:26 -0400 Subject: Allow reading from InputSource and writing to Pipeline Allowing users to subclass InputSource and Pipeline to read and write from/to arbitrary sources provides the maximum flexibility for users who want to read and write from other than files or memory. --- ChangeLog | 7 +++++++ include/qpdf/QPDF.hh | 7 +++++++ include/qpdf/QPDFWriter.hh | 9 +++++++++ libqpdf/QPDF.cc | 18 ++++++++++++------ libqpdf/QPDFWriter.cc | 7 +++++++ qpdf/qtest/qpdf.test | 9 ++++++++- qpdf/qtest/qpdf/custom-pipeline.pdf | Bin 0 -> 799 bytes qpdf/test_driver.cc | 14 ++++++++++++++ 8 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 qpdf/qtest/qpdf/custom-pipeline.pdf diff --git a/ChangeLog b/ChangeLog index fd15bda1..f023b09b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2012-09-23 Jay Berkenbilt + + * Add public methods QPDF::processInputSource and + QPDFWriter::setOutputPipeline to allow users to read from custom + input sources and to write to custom pipelines. This allows the + maximum flexibility in sources for reading and writing PDF files. + 2012-09-06 Jay Berkenbilt * 3.0.2: release diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index e594a44a..64858625 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -72,6 +72,13 @@ class QPDF char const* buf, size_t length, char const* password = 0); + // Parse a PDF file loaded from a custom InputSource. If you have + // your own method of retrieving a PDF file, you can subclass + // InputSource and use this method. + QPDF_DLL + void processInputSource(PointerHolder, + char const* password = 0); + // Create a QPDF object for an empty PDF. This PDF has no pages // or objects other than a minimal trailer, a document catalog, // and a /Pages tree containing zero pages. Pages and other diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 2c1c32f6..725b2be8 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -95,6 +95,15 @@ class QPDFWriter QPDF_DLL Buffer* getBuffer(); + // Supply your own pipeline object. Output will be written to + // this pipeline, and QPDFWriter will call finish() on the + // pipeline. It is the caller's responsibility to manage the + // memory for the pipeline. The pipeline is never deleted by + // QPDFWriter, which makes it possible for you to call additional + // methods on the pipeline after the writing is finished. + QPDF_DLL + void setOutputPipeline(Pipeline*); + // Setting Parameters // Set the value of object stream mode. In disable mode, we never diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 472e0c13..678f773e 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -138,9 +138,8 @@ void QPDF::processFile(char const* filename, char const* password) { FileInputSource* fi = new FileInputSource(); - this->file = fi; fi->setFilename(filename); - parse(password); + processInputSource(fi, password); } void @@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep, bool close_file, char const* password) { FileInputSource* fi = new FileInputSource(); - this->file = fi; fi->setFile(description, filep, close_file); - parse(password); + processInputSource(fi, password); } void @@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description, char const* buf, size_t length, char const* password) { - this->file = + processInputSource( new BufferInputSource(description, new Buffer((unsigned char*)buf, length), - true); + true), + password); +} + +void +QPDF::processInputSource(PointerHolder source, + char const* password) +{ + this->file = source; parse(password); } diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index eb08488a..c1e4e1dd 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -134,6 +134,13 @@ QPDFWriter::getBuffer() return result; } +void +QPDFWriter::setOutputPipeline(Pipeline* p) +{ + this->filename = "custom pipeline"; + initializePipelineStack(p); +} + void QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) { diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index d12f0644..e510eded 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -149,7 +149,7 @@ $td->runtest("remove page we don't have", $td->NORMALIZE_NEWLINES); # ---------- $td->notify("--- Miscellaneous Tests ---"); -$n_tests += 53; +$n_tests += 55; $td->runtest("qpdf version", {$td->COMMAND => "qpdf --version"}, @@ -403,6 +403,13 @@ $td->runtest("check output", $td->runtest("check output", {$td->FILE => "d.pdf"}, {$td->FILE => "extra-header-lin-newline.pdf"}); +$td->runtest("output to custom pipeline", + {$td->COMMAND => "test_driver 33 minimal.pdf"}, + {$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "custom-pipeline.pdf"}); show_ntests(); # ---------- diff --git a/qpdf/qtest/qpdf/custom-pipeline.pdf b/qpdf/qtest/qpdf/custom-pipeline.pdf new file mode 100644 index 00000000..b8c692ed Binary files /dev/null and b/qpdf/qtest/qpdf/custom-pipeline.pdf differ diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 311097f6..2c729987 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -1112,6 +1112,20 @@ void runtest(int n, char const* filename1, char const* filename2) w.write(); } } + else if (n == 33) + { + // Test writing to a custom pipeline + Pl_Buffer p("buffer"); + QPDFWriter w(pdf); + w.setStaticID(true); + w.setOutputPipeline(&p); + w.write(); + PointerHolder b = p.getBuffer(); + FILE* f = QUtil::fopen_wrapper("open a.pdf", + fopen("a.pdf", "wb")); + fwrite(b->getBuffer(), b->getSize(), 1, f); + fclose(f); + } else { throw std::runtime_error(std::string("invalid test ") + -- cgit v1.2.3-54-g00ecf