Commit f37d399d825fc70155a3634c26463a24a2e17035

Authored by Jay Berkenbilt
1 parent 6a7d53ad

Add newline-before-endstream option (fixes #103)

ChangeLog
1 2017-07-29 Jay Berkenbilt <ejb@ql.org> 1 2017-07-29 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add --newline-before-endstream command-line option and
  4 + setNewlineBeforeEndstream method to QPDFWriter. This forces qpdf
  5 + to always add a newline before the endstream keyword. It is a
  6 + necessary but not sufficient condition for PDF/A compliance. Fixes
  7 + #103.
  8 +
3 * Handle zlib data errors when decoding streams. Fixes #106. 9 * Handle zlib data errors when decoding streams. Fixes #106.
4 10
5 * Improve handling of files where the "stream" keyword is not 11 * Improve handling of files where the "stream" keyword is not
include/qpdf/QPDFWriter.hh
@@ -161,6 +161,11 @@ class QPDFWriter @@ -161,6 +161,11 @@ class QPDFWriter
161 QPDF_DLL 161 QPDF_DLL
162 void setPreserveUnreferencedObjects(bool); 162 void setPreserveUnreferencedObjects(bool);
163 163
  164 + // Always write a newline before the endstream keyword. This helps
  165 + // with PDF/A compliance, though it is not sufficient for it.
  166 + QPDF_DLL
  167 + void setNewlineBeforeEndstream(bool);
  168 +
164 // Set the minimum PDF version. If the PDF version of the input 169 // Set the minimum PDF version. If the PDF version of the input
165 // file (or previously set minimum version) is less than the 170 // file (or previously set minimum version) is less than the
166 // version passed to this method, the PDF version of the output 171 // version passed to this method, the PDF version of the output
@@ -434,6 +439,7 @@ class QPDFWriter @@ -434,6 +439,7 @@ class QPDFWriter
434 bool qdf_mode; 439 bool qdf_mode;
435 bool precheck_streams; 440 bool precheck_streams;
436 bool preserve_unreferenced_objects; 441 bool preserve_unreferenced_objects;
  442 + bool newline_before_endstream;
437 bool static_id; 443 bool static_id;
438 bool suppress_original_object_ids; 444 bool suppress_original_object_ids;
439 bool direct_stream_lengths; 445 bool direct_stream_lengths;
libqpdf/QPDFWriter.cc
@@ -59,6 +59,7 @@ QPDFWriter::init() @@ -59,6 +59,7 @@ QPDFWriter::init()
59 qdf_mode = false; 59 qdf_mode = false;
60 precheck_streams = false; 60 precheck_streams = false;
61 preserve_unreferenced_objects = false; 61 preserve_unreferenced_objects = false;
  62 + newline_before_endstream = false;
62 static_id = false; 63 static_id = false;
63 suppress_original_object_ids = false; 64 suppress_original_object_ids = false;
64 direct_stream_lengths = true; 65 direct_stream_lengths = true;
@@ -191,6 +192,12 @@ QPDFWriter::setPreserveUnreferencedObjects(bool val) @@ -191,6 +192,12 @@ QPDFWriter::setPreserveUnreferencedObjects(bool val)
191 } 192 }
192 193
193 void 194 void
  195 +QPDFWriter::setNewlineBeforeEndstream(bool val)
  196 +{
  197 + this->newline_before_endstream = val;
  198 +}
  199 +
  200 +void
194 QPDFWriter::setMinimumPDFVersion(std::string const& version) 201 QPDFWriter::setMinimumPDFVersion(std::string const& version)
195 { 202 {
196 setMinimumPDFVersion(version, 0); 203 setMinimumPDFVersion(version, 0);
@@ -1580,7 +1587,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level, @@ -1580,7 +1587,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
1580 char last_char = this->pipeline->getLastChar(); 1587 char last_char = this->pipeline->getLastChar();
1581 popPipelineStack(); 1588 popPipelineStack();
1582 1589
1583 - if (this->qdf_mode) 1590 + if (this->qdf_mode || this->newline_before_endstream)
1584 { 1591 {
1585 if (last_char != '\n') 1592 if (last_char != '\n')
1586 { 1593 {
qpdf/qpdf.cc
@@ -204,6 +204,7 @@ familiar with the PDF file format or who are PDF developers.\n\ @@ -204,6 +204,7 @@ familiar with the PDF file format or who are PDF developers.\n\
204 --ignore-xref-streams tells qpdf to ignore any cross-reference streams\n\ 204 --ignore-xref-streams tells qpdf to ignore any cross-reference streams\n\
205 --precheck-streams precheck ability to decode streams\n\ 205 --precheck-streams precheck ability to decode streams\n\
206 --preserve-unreferenced preserve unreferenced objects\n\ 206 --preserve-unreferenced preserve unreferenced objects\n\
  207 +--newline-before-endstream always put a newline before endstream\n\
207 --qdf turns on \"QDF mode\" (below)\n\ 208 --qdf turns on \"QDF mode\" (below)\n\
208 --min-version=version sets the minimum PDF version of the output file\n\ 209 --min-version=version sets the minimum PDF version of the output file\n\
209 --force-version=version forces this to be the PDF version of the output file\n\ 210 --force-version=version forces this to be the PDF version of the output file\n\
@@ -1032,6 +1033,7 @@ int main(int argc, char* argv[]) @@ -1032,6 +1033,7 @@ int main(int argc, char* argv[])
1032 bool qdf_mode = false; 1033 bool qdf_mode = false;
1033 bool precheck_streams = false; 1034 bool precheck_streams = false;
1034 bool preserve_unreferenced_objects = false; 1035 bool preserve_unreferenced_objects = false;
  1036 + bool newline_before_endstream = false;
1035 std::string min_version; 1037 std::string min_version;
1036 std::string force_version; 1038 std::string force_version;
1037 1039
@@ -1225,6 +1227,10 @@ int main(int argc, char* argv[]) @@ -1225,6 +1227,10 @@ int main(int argc, char* argv[])
1225 { 1227 {
1226 preserve_unreferenced_objects = true; 1228 preserve_unreferenced_objects = true;
1227 } 1229 }
  1230 + else if (strcmp(arg, "newline-before-endstream") == 0)
  1231 + {
  1232 + newline_before_endstream = true;
  1233 + }
1228 else if (strcmp(arg, "min-version") == 0) 1234 else if (strcmp(arg, "min-version") == 0)
1229 { 1235 {
1230 if (parameter == 0) 1236 if (parameter == 0)
@@ -1724,6 +1730,10 @@ int main(int argc, char* argv[]) @@ -1724,6 +1730,10 @@ int main(int argc, char* argv[])
1724 { 1730 {
1725 w.setPreserveUnreferencedObjects(true); 1731 w.setPreserveUnreferencedObjects(true);
1726 } 1732 }
  1733 + if (newline_before_endstream)
  1734 + {
  1735 + w.setNewlineBeforeEndstream(true);
  1736 + }
1727 if (normalize_set) 1737 if (normalize_set)
1728 { 1738 {
1729 w.setContentNormalization(normalize); 1739 w.setContentNormalization(normalize);
qpdf/qtest/qpdf.test
@@ -206,7 +206,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;, @@ -206,7 +206,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;,
206 show_ntests(); 206 show_ntests();
207 # ---------- 207 # ----------
208 $td->notify("--- Miscellaneous Tests ---"); 208 $td->notify("--- Miscellaneous Tests ---");
209 -$n_tests += 89; 209 +$n_tests += 91;
210 210
211 $td->runtest("qpdf version", 211 $td->runtest("qpdf version",
212 {$td->COMMAND => "qpdf --version"}, 212 {$td->COMMAND => "qpdf --version"},
@@ -618,6 +618,16 @@ $td-&gt;runtest(&quot;split content stream errors&quot;, @@ -618,6 +618,16 @@ $td-&gt;runtest(&quot;split content stream errors&quot;,
618 $td->EXIT_STATUS => 3}, 618 $td->EXIT_STATUS => 3},
619 $td->NORMALIZE_NEWLINES); 619 $td->NORMALIZE_NEWLINES);
620 620
  621 +$td->runtest("newline before endstream",
  622 + {$td->COMMAND =>
  623 + "qpdf --static-id --newline-before-endstream" .
  624 + " minimal.pdf a.pdf"},
  625 + {$td->STRING => "", $td->EXIT_STATUS => 0},
  626 + $td->NORMALIZE_NEWLINES);
  627 +$td->runtest("check output",
  628 + {$td->FILE => "a.pdf"},
  629 + {$td->FILE => "newline-before-endstream.pdf"});
  630 +
621 631
622 show_ntests(); 632 show_ntests();
623 # ---------- 633 # ----------
qpdf/qtest/qpdf/newline-before-endstream.pdf 0 → 100644
No preview for this file type