diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index 45efafe..6039ca6 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -490,7 +490,7 @@ class QPDFJob // Output generation void doSplitPages(QPDF& pdf); - void setWriterOptions(QPDFWriter&); + void setWriterOptions(qpdf::Writer&); void setEncryptionOptions(QPDFWriter&); void maybeFixWritePassword(int R, std::string& password); void writeOutfile(QPDF& pdf); diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index c393f0d..9f884d7 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -43,6 +43,11 @@ #include #include +namespace qpdf +{ + class Writer; +} + class QPDF; // This class implements a simple writer for saving QPDF objects to new PDF files. See comments @@ -440,6 +445,8 @@ class QPDFWriter class NewObjTable; private: + friend class qpdf::Writer; + class Members; std::shared_ptr m; diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index b02708e..4e6ffb6 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -476,7 +476,7 @@ QPDFJob::writeQPDF(QPDF& pdf) if (!pdf.getWarnings().empty()) { m->warnings = true; } - if (m->warnings && !m->qcf.suppress_warnings()) { + if (m->warnings && !m->d_cfg.suppress_warnings()) { if (createsOutput()) { *m->log->getWarn() << m->message_prefix @@ -744,7 +744,8 @@ QPDFJob::doCheck(QPDF& pdf) // Write the file to nowhere, uncompressing streams. This causes full file traversal and // decoding of all streams we can decode. - QPDFWriter w(pdf); + Writer::Config cfg; + Writer w(pdf, cfg); Pl_Discard discard; w.setOutputPipeline(&discard); w.setDecodeLevel(qpdf_dl_all); @@ -1708,7 +1709,7 @@ QPDFJob::doProcessOnce( bool main_input) { pdf = std::make_unique(); - pdf->doc().config(m->qcf.log(m->log)); + pdf->doc().config(m->d_cfg.log(m->log)); if (empty) { pdf->emptyPDF(); } else if (main_input && m->json_input) { @@ -1738,7 +1739,7 @@ QPDFJob::doProcess( // was incorrectly encoded, there's a good chance we'd succeed here. std::string ptemp; - if (password && !m->qcf.password_is_hex_key()) { + if (password && !m->d_cfg.password_is_hex_key()) { if (m->password_mode == QPDFJob::pm_hex_bytes) { // Special case: handle --password-mode=hex-bytes for input password as well as output // password @@ -1746,7 +1747,7 @@ QPDFJob::doProcess( password = ptemp.c_str(); } } - if (!password || empty || m->qcf.password_is_hex_key() || m->suppress_password_recovery) { + if (!password || empty || m->d_cfg.password_is_hex_key() || m->suppress_password_recovery) { // There is no password, or we're not doing recovery, so just do the normal processing with // the supplied password. doProcessOnce(pdf, fn, password, empty, used_for_input, main_input); @@ -2878,7 +2879,7 @@ parse_version(std::string const& full_version_string, std::string& version, int& } void -QPDFJob::setWriterOptions(QPDFWriter& w) +QPDFJob::setWriterOptions(Writer& w) { if (m->compression_level >= 0) { Pl_Flate::setCompressionLevel(m->compression_level); @@ -3011,7 +3012,7 @@ QPDFJob::doSplitPages(QPDF& pdf) last = num_pages; } QPDF outpdf; - outpdf.doc().config(m->qcf); + outpdf.doc().config(m->d_cfg); outpdf.emptyPDF(); QPDFAcroFormDocumentHelper* out_afdh = afdh.hasAcroForm() ? &outpdf.doc().acroform() : nullptr; @@ -3049,7 +3050,8 @@ QPDFJob::doSplitPages(QPDF& pdf) if (QUtil::same_file(m->infile_nm(), outfile.data())) { throw std::runtime_error("split pages would overwrite input file with " + outfile); } - QPDFWriter w(outpdf, outfile.c_str()); + Writer w(outpdf, m->w_cfg); + w.setOutputFilename(outfile.data()); setWriterOptions(w); w.write(); doIfVerbose([&](Pipeline& v, std::string const& prefix) { @@ -3074,9 +3076,8 @@ QPDFJob::writeOutfile(QPDF& pdf) if (m->json_version) { writeJSON(pdf); } else { - // QPDFWriter must have block scope so the output file will be closed after write() - // finishes. - QPDFWriter w(pdf); + // Writer must have block scope so the output file will be closed after write() finishes. + Writer w(pdf, m->w_cfg); if (!m->outfilename.empty()) { w.setOutputFilename(m->outfilename.data()); } else { diff --git a/libqpdf/QPDFJob_config.cc b/libqpdf/QPDFJob_config.cc index de8c0a6..1f2e99a 100644 --- a/libqpdf/QPDFJob_config.cc +++ b/libqpdf/QPDFJob_config.cc @@ -68,7 +68,7 @@ QPDFJob::Config* QPDFJob::Config::check() { o.m->check = true; - o.m->qcf.check_mode(true); + o.m->d_cfg.check_mode(true); o.m->require_outfile = false; return this; } @@ -234,7 +234,7 @@ QPDFJob::Config::generateAppearances() QPDFJob::Config* QPDFJob::Config::ignoreXrefStreams() { - o.m->qcf.ignore_xref_streams(true); + o.m->d_cfg.ignore_xref_streams(true); return this; } @@ -416,7 +416,7 @@ QPDFJob::Config::noOriginalObjectIds() QPDFJob::Config* QPDFJob::Config::noWarn() { - o.m->qcf.suppress_warnings(true); + o.m->d_cfg.suppress_warnings(true); return this; } @@ -466,7 +466,7 @@ QPDFJob::Config::password(std::string const& parameter) QPDFJob::Config* QPDFJob::Config::passwordIsHexKey() { - o.m->qcf.password_is_hex_key(true); + o.m->d_cfg.password_is_hex_key(true); return this; } @@ -663,7 +663,7 @@ QPDFJob::Config::suppressPasswordRecovery() QPDFJob::Config* QPDFJob::Config::suppressRecovery() { - o.m->qcf.surpress_recovery(true); + o.m->d_cfg.surpress_recovery(true); return this; } diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index cd2162a..e399994 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -292,9 +292,8 @@ namespace qpdf::impl Writer(QPDF& qpdf, QPDFWriter& w) : Common(qpdf.doc()), lin(qpdf.doc().linearization()), - root_og( - qpdf.getRoot().getObjGen().isIndirect() ? qpdf.getRoot().getObjGen() - : QPDFObjGen(-1, 0)), + cfg(true), + root_og(qpdf.getRoot().indirect() ? qpdf.getRoot().id_gen() : QPDFObjGen(-1, 0)), pipeline_stack(pipeline) { } @@ -474,6 +473,7 @@ namespace qpdf::impl class QPDFWriter::Members: impl::Writer { friend class QPDFWriter; + friend class qpdf::Writer; public: Members(QPDFWriter& w, QPDF& qpdf) : @@ -482,6 +482,11 @@ class QPDFWriter::Members: impl::Writer } }; +qpdf::Writer::Writer(QPDF& qpdf, Config cfg) : + QPDFWriter(qpdf) +{ + m->cfg = cfg; +} QPDFWriter::QPDFWriter(QPDF& pdf) : m(std::make_shared(*this, pdf)) { diff --git a/libqpdf/qpdf/QPDFJob_private.hh b/libqpdf/qpdf/QPDFJob_private.hh index 8fe9be0..3f8ec59 100644 --- a/libqpdf/qpdf/QPDFJob_private.hh +++ b/libqpdf/qpdf/QPDFJob_private.hh @@ -5,6 +5,7 @@ #include #include +#include #include // 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 public: Members(QPDFJob& job) : - log(qcf.log()), + log(d_cfg.log()), inputs(job) { } @@ -168,7 +169,8 @@ class QPDFJob::Members static int constexpr DEFAULT_OI_MIN_AREA = 16384; static int constexpr DEFAULT_II_MIN_BYTES = 1024; - qpdf::Doc::Config qcf; + qpdf::Doc::Config d_cfg; + qpdf::Writer::Config w_cfg; std::shared_ptr log; std::string message_prefix{"qpdf"}; bool warnings{false}; diff --git a/libqpdf/qpdf/QPDFWriter_private.hh b/libqpdf/qpdf/QPDFWriter_private.hh index 447c227..cd5e1ee 100644 --- a/libqpdf/qpdf/QPDFWriter_private.hh +++ b/libqpdf/qpdf/QPDFWriter_private.hh @@ -6,6 +6,7 @@ #include #include #include +#include // This file is intended for inclusion by QPDFWriter, QPDF, QPDF_optimization and QPDF_linearization // only. @@ -17,12 +18,24 @@ namespace qpdf class Writer; } - class Writer + class Writer: public QPDFWriter { public: class Config { public: + Config() = default; + Config(Config const&) = default; + Config(Config&&) = delete; + Config& operator=(Config const&) = default; + Config& operator=(Config&&) = delete; + ~Config() = default; + + Config(bool permissive) : + permissive_(permissive) + { + } + bool linearize() const { @@ -258,7 +271,13 @@ namespace qpdf Config& pclm(bool val); private: - void usage(std::string_view msg) const {}; + void + usage(std::string const& msg) const + { + if (!permissive_) { + throw QPDFUsage(msg); + } + } std::string forced_pdf_version_; std::string extra_header_text_; @@ -287,7 +306,19 @@ namespace qpdf bool linearize_{false}; bool pclm_{false}; bool encrypt_use_aes_{false}; + + bool permissive_{true}; }; // class Writer::Config + + Writer() = delete; + Writer(Writer const&) = delete; + Writer(Writer&&) = delete; + Writer& operator=(Writer const&) = delete; + Writer& operator=(Writer&&) = delete; + ~Writer() = default; + + Writer(QPDF& qpdf, Config cfg); + }; // class Writer } // namespace qpdf