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 2012-09-06 Jay Berkenbilt <ejb@ql.org> 8 2012-09-06 Jay Berkenbilt <ejb@ql.org>
2 9
3 * 3.0.2: release 10 * 3.0.2: release
include/qpdf/QPDF.hh
@@ -72,6 +72,13 @@ class QPDF @@ -72,6 +72,13 @@ class QPDF
72 char const* buf, size_t length, 72 char const* buf, size_t length,
73 char const* password = 0); 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 // Create a QPDF object for an empty PDF. This PDF has no pages 82 // Create a QPDF object for an empty PDF. This PDF has no pages
76 // or objects other than a minimal trailer, a document catalog, 83 // or objects other than a minimal trailer, a document catalog,
77 // and a /Pages tree containing zero pages. Pages and other 84 // and a /Pages tree containing zero pages. Pages and other
include/qpdf/QPDFWriter.hh
@@ -95,6 +95,15 @@ class QPDFWriter @@ -95,6 +95,15 @@ class QPDFWriter
95 QPDF_DLL 95 QPDF_DLL
96 Buffer* getBuffer(); 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 // Setting Parameters 107 // Setting Parameters
99 108
100 // Set the value of object stream mode. In disable mode, we never 109 // Set the value of object stream mode. In disable mode, we never
libqpdf/QPDF.cc
@@ -138,9 +138,8 @@ void @@ -138,9 +138,8 @@ void
138 QPDF::processFile(char const* filename, char const* password) 138 QPDF::processFile(char const* filename, char const* password)
139 { 139 {
140 FileInputSource* fi = new FileInputSource(); 140 FileInputSource* fi = new FileInputSource();
141 - this->file = fi;  
142 fi->setFilename(filename); 141 fi->setFilename(filename);
143 - parse(password); 142 + processInputSource(fi, password);
144 } 143 }
145 144
146 void 145 void
@@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep, @@ -148,9 +147,8 @@ QPDF::processFile(char const* description, FILE* filep,
148 bool close_file, char const* password) 147 bool close_file, char const* password)
149 { 148 {
150 FileInputSource* fi = new FileInputSource(); 149 FileInputSource* fi = new FileInputSource();
151 - this->file = fi;  
152 fi->setFile(description, filep, close_file); 150 fi->setFile(description, filep, close_file);
153 - parse(password); 151 + processInputSource(fi, password);
154 } 152 }
155 153
156 void 154 void
@@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description, @@ -158,10 +156,18 @@ QPDF::processMemoryFile(char const* description,
158 char const* buf, size_t length, 156 char const* buf, size_t length,
159 char const* password) 157 char const* password)
160 { 158 {
161 - this->file = 159 + processInputSource(
162 new BufferInputSource(description, 160 new BufferInputSource(description,
163 new Buffer((unsigned char*)buf, length), 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 parse(password); 171 parse(password);
166 } 172 }
167 173
libqpdf/QPDFWriter.cc
@@ -135,6 +135,13 @@ QPDFWriter::getBuffer() @@ -135,6 +135,13 @@ QPDFWriter::getBuffer()
135 } 135 }
136 136
137 void 137 void
  138 +QPDFWriter::setOutputPipeline(Pipeline* p)
  139 +{
  140 + this->filename = "custom pipeline";
  141 + initializePipelineStack(p);
  142 +}
  143 +
  144 +void
138 QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode) 145 QPDFWriter::setObjectStreamMode(qpdf_object_stream_e mode)
139 { 146 {
140 this->object_stream_mode = mode; 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,7 +149,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;,
149 $td->NORMALIZE_NEWLINES); 149 $td->NORMALIZE_NEWLINES);
150 # ---------- 150 # ----------
151 $td->notify("--- Miscellaneous Tests ---"); 151 $td->notify("--- Miscellaneous Tests ---");
152 -$n_tests += 53; 152 +$n_tests += 55;
153 153
154 $td->runtest("qpdf version", 154 $td->runtest("qpdf version",
155 {$td->COMMAND => "qpdf --version"}, 155 {$td->COMMAND => "qpdf --version"},
@@ -403,6 +403,13 @@ $td-&gt;runtest(&quot;check output&quot;, @@ -403,6 +403,13 @@ $td-&gt;runtest(&quot;check output&quot;,
403 $td->runtest("check output", 403 $td->runtest("check output",
404 {$td->FILE => "d.pdf"}, 404 {$td->FILE => "d.pdf"},
405 {$td->FILE => "extra-header-lin-newline.pdf"}); 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 show_ntests(); 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,6 +1112,20 @@ void runtest(int n, char const* filename1, char const* filename2)
1112 w.write(); 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 else 1129 else
1116 { 1130 {
1117 throw std::runtime_error(std::string("invalid test ") + 1131 throw std::runtime_error(std::string("invalid test ") +