Commit 041397fdabde66574824db7582a26ef1e3fbfc65

Authored by Jay Berkenbilt
1 parent 8c99e4a6

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
  1 +2012-09-23 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add public methods QPDF::processInputSource and
  4 + QPDFWriter::setOutputPipeline to allow users to read from custom
  5 + input sources and to write to custom pipelines. This allows the
  6 + maximum flexibility in sources for reading and writing PDF files.
  7 +
1 8 2012-09-06 Jay Berkenbilt <ejb@ql.org>
2 9  
3 10 * 3.0.2: release
... ...
include/qpdf/QPDF.hh
... ... @@ -72,6 +72,13 @@ class QPDF
72 72 char const* buf, size_t length,
73 73 char const* password = 0);
74 74  
  75 + // Parse a PDF file loaded from a custom InputSource. If you have
  76 + // your own method of retrieving a PDF file, you can subclass
  77 + // InputSource and use this method.
  78 + QPDF_DLL
  79 + void processInputSource(PointerHolder<InputSource>,
  80 + char const* password = 0);
  81 +
75 82 // Create a QPDF object for an empty PDF. This PDF has no pages
76 83 // or objects other than a minimal trailer, a document catalog,
77 84 // and a /Pages tree containing zero pages. Pages and other
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -95,6 +95,15 @@ class QPDFWriter
95 95 QPDF_DLL
96 96 Buffer* getBuffer();
97 97  
  98 + // Supply your own pipeline object. Output will be written to
  99 + // this pipeline, and QPDFWriter will call finish() on the
  100 + // pipeline. It is the caller's responsibility to manage the
  101 + // memory for the pipeline. The pipeline is never deleted by
  102 + // QPDFWriter, which makes it possible for you to call additional
  103 + // methods on the pipeline after the writing is finished.
  104 + QPDF_DLL
  105 + void setOutputPipeline(Pipeline*);
  106 +
98 107 // Setting Parameters
99 108  
100 109 // Set the value of object stream mode. In disable mode, we never
... ...
libqpdf/QPDF.cc
... ... @@ -138,9 +138,8 @@ void
138 138 QPDF::processFile(char const* filename, char const* password)
139 139 {
140 140 FileInputSource* fi = new FileInputSource();
141   - this->file = fi;
142 141 fi->setFilename(filename);
143   - parse(password);
  142 + processInputSource(fi, password);
144 143 }
145 144  
146 145 void
... ... @@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep,
148 147 bool close_file, char const* password)
149 148 {
150 149 FileInputSource* fi = new FileInputSource();
151   - this->file = fi;
152 150 fi->setFile(description, filep, close_file);
153   - parse(password);
  151 + processInputSource(fi, password);
154 152 }
155 153  
156 154 void
... ... @@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description,
158 156 char const* buf, size_t length,
159 157 char const* password)
160 158 {
161   - this->file =
  159 + processInputSource(
162 160 new BufferInputSource(description,
163 161 new Buffer((unsigned char*)buf, length),
164   - true);
  162 + true),
  163 + password);
  164 +}
  165 +
  166 +void
  167 +QPDF::processInputSource(PointerHolder<InputSource> source,
  168 + char const* password)
  169 +{
  170 + this->file = source;
165 171 parse(password);
166 172 }
167 173  
... ...
libqpdf/QPDFWriter.cc
... ... @@ -135,6 +135,13 @@ QPDFWriter::getBuffer()
135 135 }
136 136  
137 137 void
  138 +QPDFWriter::setOutputPipeline(Pipeline* p)
  139 +{
  140 + this->filename = "custom pipeline";
  141 + initializePipelineStack(p);
  142 +}
  143 +
  144 +void
138 145 QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode)
139 146 {
140 147 this->object_stream_mode = mode;
... ...
qpdf/qtest/qpdf.test
... ... @@ -149,7 +149,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;,
149 149 $td->NORMALIZE_NEWLINES);
150 150 # ----------
151 151 $td->notify("--- Miscellaneous Tests ---");
152   -$n_tests += 53;
  152 +$n_tests += 55;
153 153  
154 154 $td->runtest("qpdf version",
155 155 {$td->COMMAND => "qpdf --version"},
... ... @@ -403,6 +403,13 @@ $td-&gt;runtest(&quot;check output&quot;,
403 403 $td->runtest("check output",
404 404 {$td->FILE => "d.pdf"},
405 405 {$td->FILE => "extra-header-lin-newline.pdf"});
  406 +$td->runtest("output to custom pipeline",
  407 + {$td->COMMAND => "test_driver 33 minimal.pdf"},
  408 + {$td->STRING => "test 33 done\n", $td->EXIT_STATUS => 0},
  409 + $td->NORMALIZE_NEWLINES);
  410 +$td->runtest("check output",
  411 + {$td->FILE => "a.pdf"},
  412 + {$td->FILE => "custom-pipeline.pdf"});
406 413  
407 414 show_ntests();
408 415 # ----------
... ...
qpdf/qtest/qpdf/custom-pipeline.pdf 0 → 100644
No preview for this file type
qpdf/test_driver.cc
... ... @@ -1112,6 +1112,20 @@ void runtest(int n, char const* filename1, char const* filename2)
1112 1112 w.write();
1113 1113 }
1114 1114 }
  1115 + else if (n == 33)
  1116 + {
  1117 + // Test writing to a custom pipeline
  1118 + Pl_Buffer p("buffer");
  1119 + QPDFWriter w(pdf);
  1120 + w.setStaticID(true);
  1121 + w.setOutputPipeline(&p);
  1122 + w.write();
  1123 + PointerHolder<Buffer> b = p.getBuffer();
  1124 + FILE* f = QUtil::fopen_wrapper("open a.pdf",
  1125 + fopen("a.pdf", "wb"));
  1126 + fwrite(b->getBuffer(), b->getSize(), 1, f);
  1127 + fclose(f);
  1128 + }
1115 1129 else
1116 1130 {
1117 1131 throw std::runtime_error(std::string("invalid test ") +
... ...