Commit bc6e62b947115c9fc0040461362bf3cbeec31d32

Authored by m-holger
1 parent f4598797

Refactor `QPDFWriter`: update `Writer` in `QPDFJob` usage to use `qpdf::Writer` …

…with encapsulated `Config`, replace `qcf` with `d_cfg` for improved consistency, and adjust related logic for maintainability.
include/qpdf/QPDFJob.hh
@@ -490,7 +490,7 @@ class QPDFJob @@ -490,7 +490,7 @@ class QPDFJob
490 490
491 // Output generation 491 // Output generation
492 void doSplitPages(QPDF& pdf); 492 void doSplitPages(QPDF& pdf);
493 - void setWriterOptions(QPDFWriter&); 493 + void setWriterOptions(qpdf::Writer&);
494 void setEncryptionOptions(QPDFWriter&); 494 void setEncryptionOptions(QPDFWriter&);
495 void maybeFixWritePassword(int R, std::string& password); 495 void maybeFixWritePassword(int R, std::string& password);
496 void writeOutfile(QPDF& pdf); 496 void writeOutfile(QPDF& pdf);
include/qpdf/QPDFWriter.hh
@@ -43,6 +43,11 @@ @@ -43,6 +43,11 @@
43 #include <string_view> 43 #include <string_view>
44 #include <vector> 44 #include <vector>
45 45
  46 +namespace qpdf
  47 +{
  48 + class Writer;
  49 +}
  50 +
46 class QPDF; 51 class QPDF;
47 52
48 // This class implements a simple writer for saving QPDF objects to new PDF files. See comments 53 // This class implements a simple writer for saving QPDF objects to new PDF files. See comments
@@ -440,6 +445,8 @@ class QPDFWriter @@ -440,6 +445,8 @@ class QPDFWriter
440 class NewObjTable; 445 class NewObjTable;
441 446
442 private: 447 private:
  448 + friend class qpdf::Writer;
  449 +
443 class Members; 450 class Members;
444 451
445 std::shared_ptr<Members> m; 452 std::shared_ptr<Members> m;
libqpdf/QPDFJob.cc
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 #include <qpdf/QPDFPageObjectHelper.hh> 20 #include <qpdf/QPDFPageObjectHelper.hh>
21 #include <qpdf/QPDFSystemError.hh> 21 #include <qpdf/QPDFSystemError.hh>
22 #include <qpdf/QPDFUsage.hh> 22 #include <qpdf/QPDFUsage.hh>
23 -#include <qpdf/QPDFWriter.hh> 23 +#include <qpdf/QPDFWriter_private.hh>
24 #include <qpdf/QPDF_private.hh> 24 #include <qpdf/QPDF_private.hh>
25 #include <qpdf/QTC.hh> 25 #include <qpdf/QTC.hh>
26 #include <qpdf/QUtil.hh> 26 #include <qpdf/QUtil.hh>
@@ -476,7 +476,7 @@ QPDFJob::writeQPDF(QPDF&amp; pdf) @@ -476,7 +476,7 @@ QPDFJob::writeQPDF(QPDF&amp; pdf)
476 if (!pdf.getWarnings().empty()) { 476 if (!pdf.getWarnings().empty()) {
477 m->warnings = true; 477 m->warnings = true;
478 } 478 }
479 - if (m->warnings && !m->qcf.suppress_warnings()) { 479 + if (m->warnings && !m->d_cfg.suppress_warnings()) {
480 if (createsOutput()) { 480 if (createsOutput()) {
481 *m->log->getWarn() 481 *m->log->getWarn()
482 << m->message_prefix 482 << m->message_prefix
@@ -744,7 +744,8 @@ QPDFJob::doCheck(QPDF&amp; pdf) @@ -744,7 +744,8 @@ QPDFJob::doCheck(QPDF&amp; pdf)
744 744
745 // Write the file to nowhere, uncompressing streams. This causes full file traversal and 745 // Write the file to nowhere, uncompressing streams. This causes full file traversal and
746 // decoding of all streams we can decode. 746 // decoding of all streams we can decode.
747 - QPDFWriter w(pdf); 747 + Writer::Config cfg;
  748 + Writer w(pdf, cfg);
748 Pl_Discard discard; 749 Pl_Discard discard;
749 w.setOutputPipeline(&discard); 750 w.setOutputPipeline(&discard);
750 w.setDecodeLevel(qpdf_dl_all); 751 w.setDecodeLevel(qpdf_dl_all);
@@ -1708,7 +1709,7 @@ QPDFJob::doProcessOnce( @@ -1708,7 +1709,7 @@ QPDFJob::doProcessOnce(
1708 bool main_input) 1709 bool main_input)
1709 { 1710 {
1710 pdf = std::make_unique<QPDF>(); 1711 pdf = std::make_unique<QPDF>();
1711 - pdf->doc().config(m->qcf.log(m->log)); 1712 + pdf->doc().config(m->d_cfg.log(m->log));
1712 if (empty) { 1713 if (empty) {
1713 pdf->emptyPDF(); 1714 pdf->emptyPDF();
1714 } else if (main_input && m->json_input) { 1715 } else if (main_input && m->json_input) {
@@ -1738,7 +1739,7 @@ QPDFJob::doProcess( @@ -1738,7 +1739,7 @@ QPDFJob::doProcess(
1738 // was incorrectly encoded, there's a good chance we'd succeed here. 1739 // was incorrectly encoded, there's a good chance we'd succeed here.
1739 1740
1740 std::string ptemp; 1741 std::string ptemp;
1741 - if (password && !m->qcf.password_is_hex_key()) { 1742 + if (password && !m->d_cfg.password_is_hex_key()) {
1742 if (m->password_mode == QPDFJob::pm_hex_bytes) { 1743 if (m->password_mode == QPDFJob::pm_hex_bytes) {
1743 // Special case: handle --password-mode=hex-bytes for input password as well as output 1744 // Special case: handle --password-mode=hex-bytes for input password as well as output
1744 // password 1745 // password
@@ -1746,7 +1747,7 @@ QPDFJob::doProcess( @@ -1746,7 +1747,7 @@ QPDFJob::doProcess(
1746 password = ptemp.c_str(); 1747 password = ptemp.c_str();
1747 } 1748 }
1748 } 1749 }
1749 - if (!password || empty || m->qcf.password_is_hex_key() || m->suppress_password_recovery) { 1750 + if (!password || empty || m->d_cfg.password_is_hex_key() || m->suppress_password_recovery) {
1750 // There is no password, or we're not doing recovery, so just do the normal processing with 1751 // There is no password, or we're not doing recovery, so just do the normal processing with
1751 // the supplied password. 1752 // the supplied password.
1752 doProcessOnce(pdf, fn, password, empty, used_for_input, main_input); 1753 doProcessOnce(pdf, fn, password, empty, used_for_input, main_input);
@@ -2878,7 +2879,7 @@ parse_version(std::string const&amp; full_version_string, std::string&amp; version, int&amp; @@ -2878,7 +2879,7 @@ parse_version(std::string const&amp; full_version_string, std::string&amp; version, int&amp;
2878 } 2879 }
2879 2880
2880 void 2881 void
2881 -QPDFJob::setWriterOptions(QPDFWriter& w) 2882 +QPDFJob::setWriterOptions(Writer& w)
2882 { 2883 {
2883 if (m->compression_level >= 0) { 2884 if (m->compression_level >= 0) {
2884 Pl_Flate::setCompressionLevel(m->compression_level); 2885 Pl_Flate::setCompressionLevel(m->compression_level);
@@ -3011,7 +3012,7 @@ QPDFJob::doSplitPages(QPDF&amp; pdf) @@ -3011,7 +3012,7 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3011 last = num_pages; 3012 last = num_pages;
3012 } 3013 }
3013 QPDF outpdf; 3014 QPDF outpdf;
3014 - outpdf.doc().config(m->qcf); 3015 + outpdf.doc().config(m->d_cfg);
3015 outpdf.emptyPDF(); 3016 outpdf.emptyPDF();
3016 QPDFAcroFormDocumentHelper* out_afdh = 3017 QPDFAcroFormDocumentHelper* out_afdh =
3017 afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr; 3018 afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr;
@@ -3049,7 +3050,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf) @@ -3049,7 +3050,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3049 if (QUtil::same_file(m->infile_nm(), outfile.data())) { 3050 if (QUtil::same_file(m->infile_nm(), outfile.data())) {
3050 throw std::runtime_error("split pages would overwrite input file with " + outfile); 3051 throw std::runtime_error("split pages would overwrite input file with " + outfile);
3051 } 3052 }
3052 - QPDFWriter w(outpdf, outfile.c_str()); 3053 + Writer w(outpdf, m->w_cfg);
  3054 + w.setOutputFilename(outfile.data());
3053 setWriterOptions(w); 3055 setWriterOptions(w);
3054 w.write(); 3056 w.write();
3055 doIfVerbose([&](Pipeline& v, std::string const& prefix) { 3057 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
@@ -3074,9 +3076,8 @@ QPDFJob::writeOutfile(QPDF&amp; pdf) @@ -3074,9 +3076,8 @@ QPDFJob::writeOutfile(QPDF&amp; pdf)
3074 if (m->json_version) { 3076 if (m->json_version) {
3075 writeJSON(pdf); 3077 writeJSON(pdf);
3076 } else { 3078 } else {
3077 - // QPDFWriter must have block scope so the output file will be closed after write()  
3078 - // finishes.  
3079 - QPDFWriter w(pdf); 3079 + // Writer must have block scope so the output file will be closed after write() finishes.
  3080 + Writer w(pdf, m->w_cfg);
3080 if (!m->outfilename.empty()) { 3081 if (!m->outfilename.empty()) {
3081 w.setOutputFilename(m->outfilename.data()); 3082 w.setOutputFilename(m->outfilename.data());
3082 } else { 3083 } else {
libqpdf/QPDFJob_config.cc
@@ -68,7 +68,7 @@ QPDFJob::Config* @@ -68,7 +68,7 @@ QPDFJob::Config*
68 QPDFJob::Config::check() 68 QPDFJob::Config::check()
69 { 69 {
70 o.m->check = true; 70 o.m->check = true;
71 - o.m->qcf.check_mode(true); 71 + o.m->d_cfg.check_mode(true);
72 o.m->require_outfile = false; 72 o.m->require_outfile = false;
73 return this; 73 return this;
74 } 74 }
@@ -234,7 +234,7 @@ QPDFJob::Config::generateAppearances() @@ -234,7 +234,7 @@ QPDFJob::Config::generateAppearances()
234 QPDFJob::Config* 234 QPDFJob::Config*
235 QPDFJob::Config::ignoreXrefStreams() 235 QPDFJob::Config::ignoreXrefStreams()
236 { 236 {
237 - o.m->qcf.ignore_xref_streams(true); 237 + o.m->d_cfg.ignore_xref_streams(true);
238 return this; 238 return this;
239 } 239 }
240 240
@@ -416,7 +416,7 @@ QPDFJob::Config::noOriginalObjectIds() @@ -416,7 +416,7 @@ QPDFJob::Config::noOriginalObjectIds()
416 QPDFJob::Config* 416 QPDFJob::Config*
417 QPDFJob::Config::noWarn() 417 QPDFJob::Config::noWarn()
418 { 418 {
419 - o.m->qcf.suppress_warnings(true); 419 + o.m->d_cfg.suppress_warnings(true);
420 return this; 420 return this;
421 } 421 }
422 422
@@ -466,7 +466,7 @@ QPDFJob::Config::password(std::string const&amp; parameter) @@ -466,7 +466,7 @@ QPDFJob::Config::password(std::string const&amp; parameter)
466 QPDFJob::Config* 466 QPDFJob::Config*
467 QPDFJob::Config::passwordIsHexKey() 467 QPDFJob::Config::passwordIsHexKey()
468 { 468 {
469 - o.m->qcf.password_is_hex_key(true); 469 + o.m->d_cfg.password_is_hex_key(true);
470 return this; 470 return this;
471 } 471 }
472 472
@@ -663,7 +663,7 @@ QPDFJob::Config::suppressPasswordRecovery() @@ -663,7 +663,7 @@ QPDFJob::Config::suppressPasswordRecovery()
663 QPDFJob::Config* 663 QPDFJob::Config*
664 QPDFJob::Config::suppressRecovery() 664 QPDFJob::Config::suppressRecovery()
665 { 665 {
666 - o.m->qcf.surpress_recovery(true); 666 + o.m->d_cfg.surpress_recovery(true);
667 return this; 667 return this;
668 } 668 }
669 669
libqpdf/QPDFWriter.cc
@@ -292,9 +292,8 @@ namespace qpdf::impl @@ -292,9 +292,8 @@ namespace qpdf::impl
292 Writer(QPDF& qpdf, QPDFWriter& w) : 292 Writer(QPDF& qpdf, QPDFWriter& w) :
293 Common(qpdf.doc()), 293 Common(qpdf.doc()),
294 lin(qpdf.doc().linearization()), 294 lin(qpdf.doc().linearization()),
295 - root_og(  
296 - qpdf.getRoot().getObjGen().isIndirect() ? qpdf.getRoot().getObjGen()  
297 - : QPDFObjGen(-1, 0)), 295 + cfg(true),
  296 + root_og(qpdf.getRoot().indirect() ? qpdf.getRoot().id_gen() : QPDFObjGen(-1, 0)),
298 pipeline_stack(pipeline) 297 pipeline_stack(pipeline)
299 { 298 {
300 } 299 }
@@ -474,6 +473,7 @@ namespace qpdf::impl @@ -474,6 +473,7 @@ namespace qpdf::impl
474 class QPDFWriter::Members: impl::Writer 473 class QPDFWriter::Members: impl::Writer
475 { 474 {
476 friend class QPDFWriter; 475 friend class QPDFWriter;
  476 + friend class qpdf::Writer;
477 477
478 public: 478 public:
479 Members(QPDFWriter& w, QPDF& qpdf) : 479 Members(QPDFWriter& w, QPDF& qpdf) :
@@ -482,6 +482,11 @@ class QPDFWriter::Members: impl::Writer @@ -482,6 +482,11 @@ class QPDFWriter::Members: impl::Writer
482 } 482 }
483 }; 483 };
484 484
  485 +qpdf::Writer::Writer(QPDF& qpdf, Config cfg) :
  486 + QPDFWriter(qpdf)
  487 +{
  488 + m->cfg = cfg;
  489 +}
485 QPDFWriter::QPDFWriter(QPDF& pdf) : 490 QPDFWriter::QPDFWriter(QPDF& pdf) :
486 m(std::make_shared<Members>(*this, pdf)) 491 m(std::make_shared<Members>(*this, pdf))
487 { 492 {
libqpdf/qpdf/QPDFJob_private.hh
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 5
6 #include <qpdf/ClosedFileInputSource.hh> 6 #include <qpdf/ClosedFileInputSource.hh>
7 #include <qpdf/QPDFLogger.hh> 7 #include <qpdf/QPDFLogger.hh>
  8 +#include <qpdf/QPDFWriter_private.hh>
8 #include <qpdf/QPDF_private.hh> 9 #include <qpdf/QPDF_private.hh>
9 10
10 // A selection of pages from a single input PDF to be included in the output. This corresponds to a 11 // A selection of pages from a single input PDF to be included in the output. This corresponds to a
@@ -150,7 +151,7 @@ class QPDFJob::Members @@ -150,7 +151,7 @@ class QPDFJob::Members
150 151
151 public: 152 public:
152 Members(QPDFJob& job) : 153 Members(QPDFJob& job) :
153 - log(qcf.log()), 154 + log(d_cfg.log()),
154 inputs(job) 155 inputs(job)
155 { 156 {
156 } 157 }
@@ -168,7 +169,8 @@ class QPDFJob::Members @@ -168,7 +169,8 @@ class QPDFJob::Members
168 static int constexpr DEFAULT_OI_MIN_AREA = 16384; 169 static int constexpr DEFAULT_OI_MIN_AREA = 16384;
169 static int constexpr DEFAULT_II_MIN_BYTES = 1024; 170 static int constexpr DEFAULT_II_MIN_BYTES = 1024;
170 171
171 - qpdf::Doc::Config qcf; 172 + qpdf::Doc::Config d_cfg;
  173 + qpdf::Writer::Config w_cfg;
172 std::shared_ptr<QPDFLogger> log; 174 std::shared_ptr<QPDFLogger> log;
173 std::string message_prefix{"qpdf"}; 175 std::string message_prefix{"qpdf"};
174 bool warnings{false}; 176 bool warnings{false};
libqpdf/qpdf/QPDFWriter_private.hh
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 #include <qpdf/ObjTable.hh> 6 #include <qpdf/ObjTable.hh>
7 #include <qpdf/Pipeline_private.hh> 7 #include <qpdf/Pipeline_private.hh>
8 #include <qpdf/QPDF.hh> 8 #include <qpdf/QPDF.hh>
  9 +#include <qpdf/QPDFUsage.hh>
9 10
10 // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization 11 // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization
11 // only. 12 // only.
@@ -17,12 +18,24 @@ namespace qpdf @@ -17,12 +18,24 @@ namespace qpdf
17 class Writer; 18 class Writer;
18 } 19 }
19 20
20 - class Writer 21 + class Writer: public QPDFWriter
21 { 22 {
22 public: 23 public:
23 class Config 24 class Config
24 { 25 {
25 public: 26 public:
  27 + Config() = default;
  28 + Config(Config const&) = default;
  29 + Config(Config&&) = delete;
  30 + Config& operator=(Config const&) = default;
  31 + Config& operator=(Config&&) = delete;
  32 + ~Config() = default;
  33 +
  34 + Config(bool permissive) :
  35 + permissive_(permissive)
  36 + {
  37 + }
  38 +
26 bool 39 bool
27 linearize() const 40 linearize() const
28 { 41 {
@@ -258,7 +271,13 @@ namespace qpdf @@ -258,7 +271,13 @@ namespace qpdf
258 Config& pclm(bool val); 271 Config& pclm(bool val);
259 272
260 private: 273 private:
261 - void usage(std::string_view msg) const {}; 274 + void
  275 + usage(std::string const& msg) const
  276 + {
  277 + if (!permissive_) {
  278 + throw QPDFUsage(msg);
  279 + }
  280 + }
262 281
263 std::string forced_pdf_version_; 282 std::string forced_pdf_version_;
264 std::string extra_header_text_; 283 std::string extra_header_text_;
@@ -287,7 +306,19 @@ namespace qpdf @@ -287,7 +306,19 @@ namespace qpdf
287 bool linearize_{false}; 306 bool linearize_{false};
288 bool pclm_{false}; 307 bool pclm_{false};
289 bool encrypt_use_aes_{false}; 308 bool encrypt_use_aes_{false};
  309 +
  310 + bool permissive_{true};
290 }; // class Writer::Config 311 }; // class Writer::Config
  312 +
  313 + Writer() = delete;
  314 + Writer(Writer const&) = delete;
  315 + Writer(Writer&&) = delete;
  316 + Writer& operator=(Writer const&) = delete;
  317 + Writer& operator=(Writer&&) = delete;
  318 + ~Writer() = default;
  319 +
  320 + Writer(QPDF& qpdf, Config cfg);
  321 +
291 }; // class Writer 322 }; // class Writer
292 } // namespace qpdf 323 } // namespace qpdf
293 324