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 490  
491 491 // Output generation
492 492 void doSplitPages(QPDF& pdf);
493   - void setWriterOptions(QPDFWriter&);
  493 + void setWriterOptions(qpdf::Writer&);
494 494 void setEncryptionOptions(QPDFWriter&);
495 495 void maybeFixWritePassword(int R, std::string& password);
496 496 void writeOutfile(QPDF& pdf);
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -43,6 +43,11 @@
43 43 #include <string_view>
44 44 #include <vector>
45 45  
  46 +namespace qpdf
  47 +{
  48 + class Writer;
  49 +}
  50 +
46 51 class QPDF;
47 52  
48 53 // This class implements a simple writer for saving QPDF objects to new PDF files. See comments
... ... @@ -440,6 +445,8 @@ class QPDFWriter
440 445 class NewObjTable;
441 446  
442 447 private:
  448 + friend class qpdf::Writer;
  449 +
443 450 class Members;
444 451  
445 452 std::shared_ptr<Members> m;
... ...
libqpdf/QPDFJob.cc
... ... @@ -20,7 +20,7 @@
20 20 #include <qpdf/QPDFPageObjectHelper.hh>
21 21 #include <qpdf/QPDFSystemError.hh>
22 22 #include <qpdf/QPDFUsage.hh>
23   -#include <qpdf/QPDFWriter.hh>
  23 +#include <qpdf/QPDFWriter_private.hh>
24 24 #include <qpdf/QPDF_private.hh>
25 25 #include <qpdf/QTC.hh>
26 26 #include <qpdf/QUtil.hh>
... ... @@ -476,7 +476,7 @@ QPDFJob::writeQPDF(QPDF&amp; pdf)
476 476 if (!pdf.getWarnings().empty()) {
477 477 m->warnings = true;
478 478 }
479   - if (m->warnings && !m->qcf.suppress_warnings()) {
  479 + if (m->warnings && !m->d_cfg.suppress_warnings()) {
480 480 if (createsOutput()) {
481 481 *m->log->getWarn()
482 482 << m->message_prefix
... ... @@ -744,7 +744,8 @@ QPDFJob::doCheck(QPDF&amp; pdf)
744 744  
745 745 // Write the file to nowhere, uncompressing streams. This causes full file traversal and
746 746 // decoding of all streams we can decode.
747   - QPDFWriter w(pdf);
  747 + Writer::Config cfg;
  748 + Writer w(pdf, cfg);
748 749 Pl_Discard discard;
749 750 w.setOutputPipeline(&discard);
750 751 w.setDecodeLevel(qpdf_dl_all);
... ... @@ -1708,7 +1709,7 @@ QPDFJob::doProcessOnce(
1708 1709 bool main_input)
1709 1710 {
1710 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 1713 if (empty) {
1713 1714 pdf->emptyPDF();
1714 1715 } else if (main_input && m->json_input) {
... ... @@ -1738,7 +1739,7 @@ QPDFJob::doProcess(
1738 1739 // was incorrectly encoded, there's a good chance we'd succeed here.
1739 1740  
1740 1741 std::string ptemp;
1741   - if (password && !m->qcf.password_is_hex_key()) {
  1742 + if (password && !m->d_cfg.password_is_hex_key()) {
1742 1743 if (m->password_mode == QPDFJob::pm_hex_bytes) {
1743 1744 // Special case: handle --password-mode=hex-bytes for input password as well as output
1744 1745 // password
... ... @@ -1746,7 +1747,7 @@ QPDFJob::doProcess(
1746 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 1751 // There is no password, or we're not doing recovery, so just do the normal processing with
1751 1752 // the supplied password.
1752 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 2879 }
2879 2880  
2880 2881 void
2881   -QPDFJob::setWriterOptions(QPDFWriter& w)
  2882 +QPDFJob::setWriterOptions(Writer& w)
2882 2883 {
2883 2884 if (m->compression_level >= 0) {
2884 2885 Pl_Flate::setCompressionLevel(m->compression_level);
... ... @@ -3011,7 +3012,7 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3011 3012 last = num_pages;
3012 3013 }
3013 3014 QPDF outpdf;
3014   - outpdf.doc().config(m->qcf);
  3015 + outpdf.doc().config(m->d_cfg);
3015 3016 outpdf.emptyPDF();
3016 3017 QPDFAcroFormDocumentHelper* out_afdh =
3017 3018 afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr;
... ... @@ -3049,7 +3050,8 @@ QPDFJob::doSplitPages(QPDF&amp; pdf)
3049 3050 if (QUtil::same_file(m->infile_nm(), outfile.data())) {
3050 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 3055 setWriterOptions(w);
3054 3056 w.write();
3055 3057 doIfVerbose([&](Pipeline& v, std::string const& prefix) {
... ... @@ -3074,9 +3076,8 @@ QPDFJob::writeOutfile(QPDF&amp; pdf)
3074 3076 if (m->json_version) {
3075 3077 writeJSON(pdf);
3076 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 3081 if (!m->outfilename.empty()) {
3081 3082 w.setOutputFilename(m->outfilename.data());
3082 3083 } else {
... ...
libqpdf/QPDFJob_config.cc
... ... @@ -68,7 +68,7 @@ QPDFJob::Config*
68 68 QPDFJob::Config::check()
69 69 {
70 70 o.m->check = true;
71   - o.m->qcf.check_mode(true);
  71 + o.m->d_cfg.check_mode(true);
72 72 o.m->require_outfile = false;
73 73 return this;
74 74 }
... ... @@ -234,7 +234,7 @@ QPDFJob::Config::generateAppearances()
234 234 QPDFJob::Config*
235 235 QPDFJob::Config::ignoreXrefStreams()
236 236 {
237   - o.m->qcf.ignore_xref_streams(true);
  237 + o.m->d_cfg.ignore_xref_streams(true);
238 238 return this;
239 239 }
240 240  
... ... @@ -416,7 +416,7 @@ QPDFJob::Config::noOriginalObjectIds()
416 416 QPDFJob::Config*
417 417 QPDFJob::Config::noWarn()
418 418 {
419   - o.m->qcf.suppress_warnings(true);
  419 + o.m->d_cfg.suppress_warnings(true);
420 420 return this;
421 421 }
422 422  
... ... @@ -466,7 +466,7 @@ QPDFJob::Config::password(std::string const&amp; parameter)
466 466 QPDFJob::Config*
467 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 470 return this;
471 471 }
472 472  
... ... @@ -663,7 +663,7 @@ QPDFJob::Config::suppressPasswordRecovery()
663 663 QPDFJob::Config*
664 664 QPDFJob::Config::suppressRecovery()
665 665 {
666   - o.m->qcf.surpress_recovery(true);
  666 + o.m->d_cfg.surpress_recovery(true);
667 667 return this;
668 668 }
669 669  
... ...
libqpdf/QPDFWriter.cc
... ... @@ -292,9 +292,8 @@ namespace qpdf::impl
292 292 Writer(QPDF& qpdf, QPDFWriter& w) :
293 293 Common(qpdf.doc()),
294 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 297 pipeline_stack(pipeline)
299 298 {
300 299 }
... ... @@ -474,6 +473,7 @@ namespace qpdf::impl
474 473 class QPDFWriter::Members: impl::Writer
475 474 {
476 475 friend class QPDFWriter;
  476 + friend class qpdf::Writer;
477 477  
478 478 public:
479 479 Members(QPDFWriter& w, QPDF& qpdf) :
... ... @@ -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 490 QPDFWriter::QPDFWriter(QPDF& pdf) :
486 491 m(std::make_shared<Members>(*this, pdf))
487 492 {
... ...
libqpdf/qpdf/QPDFJob_private.hh
... ... @@ -5,6 +5,7 @@
5 5  
6 6 #include <qpdf/ClosedFileInputSource.hh>
7 7 #include <qpdf/QPDFLogger.hh>
  8 +#include <qpdf/QPDFWriter_private.hh>
8 9 #include <qpdf/QPDF_private.hh>
9 10  
10 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 151  
151 152 public:
152 153 Members(QPDFJob& job) :
153   - log(qcf.log()),
  154 + log(d_cfg.log()),
154 155 inputs(job)
155 156 {
156 157 }
... ... @@ -168,7 +169,8 @@ class QPDFJob::Members
168 169 static int constexpr DEFAULT_OI_MIN_AREA = 16384;
169 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 174 std::shared_ptr<QPDFLogger> log;
173 175 std::string message_prefix{"qpdf"};
174 176 bool warnings{false};
... ...
libqpdf/qpdf/QPDFWriter_private.hh
... ... @@ -6,6 +6,7 @@
6 6 #include <qpdf/ObjTable.hh>
7 7 #include <qpdf/Pipeline_private.hh>
8 8 #include <qpdf/QPDF.hh>
  9 +#include <qpdf/QPDFUsage.hh>
9 10  
10 11 // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization
11 12 // only.
... ... @@ -17,12 +18,24 @@ namespace qpdf
17 18 class Writer;
18 19 }
19 20  
20   - class Writer
  21 + class Writer: public QPDFWriter
21 22 {
22 23 public:
23 24 class Config
24 25 {
25 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 39 bool
27 40 linearize() const
28 41 {
... ... @@ -258,7 +271,13 @@ namespace qpdf
258 271 Config& pclm(bool val);
259 272  
260 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 282 std::string forced_pdf_version_;
264 283 std::string extra_header_text_;
... ... @@ -287,7 +306,19 @@ namespace qpdf
287 306 bool linearize_{false};
288 307 bool pclm_{false};
289 308 bool encrypt_use_aes_{false};
  309 +
  310 + bool permissive_{true};
290 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 322 }; // class Writer
292 323 } // namespace qpdf
293 324  
... ...