diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index f0d3882..dc87647 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -27,9 +27,9 @@ using namespace qpdf; using namespace std::literals; -using Doc = QPDF::Doc; -using Common = Doc::Common; -using Objects = Doc::Objects; +using QDoc = QPDF::Doc; +using Common = QDoc::Common; +using Objects = QDoc::Objects; using Foreign = Objects::Foreign; using Streams = Objects::Streams; @@ -133,7 +133,6 @@ QPDF::Members::Members(QPDF& qpdf) : lin(*this), objects(*this), pages(*this), - log(QPDFLogger::defaultLogger()), file(std::make_shared()), encp(std::make_shared()) { @@ -232,7 +231,7 @@ QPDF::closeInputSource() void QPDF::setPasswordIsHexKey(bool val) { - m->provided_password_is_hex_key = val; + m->cf.provided_password_is_hex_key_ = val; } void @@ -251,56 +250,56 @@ QPDF::registerStreamFilter( void QPDF::setIgnoreXRefStreams(bool val) { - m->ignore_xref_streams = val; + m->cf.ignore_xref_streams_ = val; } std::shared_ptr QPDF::getLogger() { - return m->log; + return m->cf.log_; } void QPDF::setLogger(std::shared_ptr l) { - m->log = l; + m->cf.log_ = l; } void QPDF::setOutputStreams(std::ostream* out, std::ostream* err) { setLogger(QPDFLogger::create()); - m->log->setOutputStreams(out, err); + m->cf.log_->setOutputStreams(out, err); } void QPDF::setSuppressWarnings(bool val) { - m->suppress_warnings = val; + m->cf.suppress_warnings_ = val; } void QPDF::setMaxWarnings(size_t val) { - m->max_warnings = val; + m->cf.max_warnings_ = val; } void QPDF::setAttemptRecovery(bool val) { - m->attempt_recovery = val; + m->cf.attempt_recovery_ = val; } void QPDF::setImmediateCopyFrom(bool val) { - m->immediate_copy_from = val; + m->cf.immediate_copy_from_ = val; } std::vector QPDF::getWarnings() { - std::vector result = m->warnings; + std::vector result = std::move(m->warnings); m->warnings.clear(); return result; } @@ -372,12 +371,12 @@ QPDF::warn(QPDFExc const& e) void Common::warn(QPDFExc const& e) { - if (m->max_warnings > 0 && m->warnings.size() >= m->max_warnings) { + if (m->cf.max_warnings_ > 0 && m->warnings.size() >= m->cf.max_warnings_) { stopOnError("Too many warnings - file is too badly damaged"); } - m->warnings.push_back(e); - if (!m->suppress_warnings) { - *m->log->getWarn() << "WARNING: " << m->warnings.back().what() << "\n"; + m->warnings.emplace_back(e); + if (!m->cf.suppress_warnings_) { + *m->cf.log_->getWarn() << "WARNING: " << m->warnings.back().what() << "\n"; } } @@ -715,7 +714,7 @@ QPDF::getRoot() } else if ( // Check_mode is an interim solution to request #810 pending a more comprehensive review of // the approach to more extensive checks and warning levels. - m->check_mode && !root.getKey("/Type").isNameAndEquals("/Catalog")) { + m->cf.check_mode_ && !root.getKey("/Type").isNameAndEquals("/Catalog")) { warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid")); root.replaceKey("/Type", "/Catalog"_qpdf); } diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index 287bfee..8ce7965 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -30,18 +30,18 @@ using namespace qpdf; -using Doc = QPDF::Doc; -using Pages = Doc::Pages; +using QDoc = QPDF::Doc; +using Pages = QDoc::Pages; // JobSetter class is restricted to QPDFJob. -class Doc::JobSetter +class QDoc::JobSetter { public: // Enable enhanced warnings for pdf file checking. static void setCheckMode(QPDF& qpdf, bool val) { - qpdf.m->check_mode = val; + qpdf.m->cf.check_mode_ = val; } }; @@ -749,7 +749,7 @@ QPDFJob::doCheck(QPDF& pdf) bool okay = true; auto& cout = *m->log->getInfo(); cout << "checking " << m->infile_name() << "\n"; - Doc::JobSetter::setCheckMode(pdf, true); + QDoc::JobSetter::setCheckMode(pdf, true); try { int extension_level = pdf.getExtensionLevel(); cout << "PDF Version: " << pdf.getPDFVersion(); diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 3977bb4..8aa53ac 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -27,8 +27,8 @@ using namespace std::literals; using namespace qpdf; -using Doc = QPDF::Doc; -using Encryption = Doc::Encryption; +using QDoc = QPDF::Doc; +using Encryption = QDoc::Encryption; QPDFWriter::ProgressReporter::~ProgressReporter() // NOLINT (modernize-use-equals-default) { @@ -263,7 +263,7 @@ Pl_stack::Popper::pop() } // Writer class is restricted to QPDFWriter so that only it can call certain methods. -class Doc::Writer: Doc::Common +class QPDF::Doc::Writer: QPDF::Doc::Common { friend class QPDFWriter; Writer(QPDF& qpdf) : diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 153852d..b54acc4 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -30,7 +30,7 @@ using Streams = QPDF::Doc::Objects::Streams; bool Streams::immediate_copy_from() const { - return qpdf.m->immediate_copy_from; + return qpdf.m->cf.immediate_copy_from_; } class Streams::Copier final: public QPDFObjectHandle::StreamDataProvider diff --git a/libqpdf/QPDF_encryption.cc b/libqpdf/QPDF_encryption.cc index 91b3819..abcb5b7 100644 --- a/libqpdf/QPDF_encryption.cc +++ b/libqpdf/QPDF_encryption.cc @@ -904,7 +904,7 @@ QPDF::EncryptionParameters::initialize(QPDF& qpdf) } Encryption data(V, R, Length / 8, p, O, U, OE, UE, Perms, id1, encrypt_metadata); - if (qm.provided_password_is_hex_key) { + if (qm.cf.provided_password_is_hex_key_) { // ignore passwords in file encryption_key = QUtil::hex_decode(provided_password); return; diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index 9313d43..a405205 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -1095,25 +1095,27 @@ QPDF::showLinearizationData() void Lin::dumpLinearizationDataInternal() { - *m->log->getInfo() << m->file->getName() << ": linearization data:\n\n"; - - *m->log->getInfo() << "file_size: " << m->linp.file_size << "\n" - << "first_page_object: " << m->linp.first_page_object << "\n" - << "first_page_end: " << m->linp.first_page_end << "\n" - << "npages: " << m->linp.npages << "\n" - << "xref_zero_offset: " << m->linp.xref_zero_offset << "\n" - << "first_page: " << m->linp.first_page << "\n" - << "H_offset: " << m->linp.H_offset << "\n" - << "H_length: " << m->linp.H_length << "\n" - << "\n"; - - *m->log->getInfo() << "Page Offsets Hint Table\n\n"; + auto& info = *m->cf.log_->getInfo(); + + info << m->file->getName() << ": linearization data:\n\n"; + + info << "file_size: " << m->linp.file_size << "\n" + << "first_page_object: " << m->linp.first_page_object << "\n" + << "first_page_end: " << m->linp.first_page_end << "\n" + << "npages: " << m->linp.npages << "\n" + << "xref_zero_offset: " << m->linp.xref_zero_offset << "\n" + << "first_page: " << m->linp.first_page << "\n" + << "H_offset: " << m->linp.H_offset << "\n" + << "H_length: " << m->linp.H_length << "\n" + << "\n"; + + info << "Page Offsets Hint Table\n\n"; dumpHPageOffset(); - *m->log->getInfo() << "\nShared Objects Hint Table\n\n"; + info << "\nShared Objects Hint Table\n\n"; dumpHSharedObject(); if (m->outline_hints.nobjects > 0) { - *m->log->getInfo() << "\nOutlines Hint Table\n\n"; + info << "\nOutlines Hint Table\n\n"; dumpHGeneric(m->outline_hints); } } @@ -1132,38 +1134,35 @@ Lin::adjusted_offset(qpdf_offset_t offset) void Lin::dumpHPageOffset() { + auto& info = *m->cf.log_->getInfo(); HPageOffset& t = m->page_offset_hints; - *m->log->getInfo() << "min_nobjects: " << t.min_nobjects << "\n" - << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n" - << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n" - << "min_page_length: " << t.min_page_length << "\n" - << "nbits_delta_page_length: " << t.nbits_delta_page_length << "\n" - << "min_content_offset: " << t.min_content_offset << "\n" - << "nbits_delta_content_offset: " << t.nbits_delta_content_offset << "\n" - << "min_content_length: " << t.min_content_length << "\n" - << "nbits_delta_content_length: " << t.nbits_delta_content_length << "\n" - << "nbits_nshared_objects: " << t.nbits_nshared_objects << "\n" - << "nbits_shared_identifier: " << t.nbits_shared_identifier << "\n" - << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n" - << "shared_denominator: " << t.shared_denominator << "\n"; + info << "min_nobjects: " << t.min_nobjects << "\n" + << "first_page_offset: " << adjusted_offset(t.first_page_offset) << "\n" + << "nbits_delta_nobjects: " << t.nbits_delta_nobjects << "\n" + << "min_page_length: " << t.min_page_length << "\n" + << "nbits_delta_page_length: " << t.nbits_delta_page_length << "\n" + << "min_content_offset: " << t.min_content_offset << "\n" + << "nbits_delta_content_offset: " << t.nbits_delta_content_offset << "\n" + << "min_content_length: " << t.min_content_length << "\n" + << "nbits_delta_content_length: " << t.nbits_delta_content_length << "\n" + << "nbits_nshared_objects: " << t.nbits_nshared_objects << "\n" + << "nbits_shared_identifier: " << t.nbits_shared_identifier << "\n" + << "nbits_shared_numerator: " << t.nbits_shared_numerator << "\n" + << "shared_denominator: " << t.shared_denominator << "\n"; for (size_t i1 = 0; i1 < m->linp.npages; ++i1) { HPageOffsetEntry& pe = t.entries.at(i1); - *m->log->getInfo() << "Page " << i1 << ":\n" - << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n" - << " length: " << pe.delta_page_length + t.min_page_length - << "\n" - // content offset is relative to page, not file - << " content_offset: " << pe.delta_content_offset + t.min_content_offset - << "\n" - << " content_length: " << pe.delta_content_length + t.min_content_length - << "\n" - << " nshared_objects: " << pe.nshared_objects << "\n"; + info << "Page " << i1 << ":\n" + << " nobjects: " << pe.delta_nobjects + t.min_nobjects << "\n" + << " length: " << pe.delta_page_length + t.min_page_length + << "\n" + // content offset is relative to page, not file + << " content_offset: " << pe.delta_content_offset + t.min_content_offset << "\n" + << " content_length: " << pe.delta_content_length + t.min_content_length << "\n" + << " nshared_objects: " << pe.nshared_objects << "\n"; for (size_t i2 = 0; i2 < toS(pe.nshared_objects); ++i2) { - *m->log->getInfo() << " identifier " << i2 << ": " << pe.shared_identifiers.at(i2) - << "\n"; - *m->log->getInfo() << " numerator " << i2 << ": " << pe.shared_numerators.at(i2) - << "\n"; + info << " identifier " << i2 << ": " << pe.shared_identifiers.at(i2) << "\n"; + info << " numerator " << i2 << ": " << pe.shared_numerators.at(i2) << "\n"; } } } @@ -1171,27 +1170,27 @@ Lin::dumpHPageOffset() void Lin::dumpHSharedObject() { + auto& info = *m->cf.log_->getInfo(); HSharedObject& t = m->shared_object_hints; - *m->log->getInfo() << "first_shared_obj: " << t.first_shared_obj << "\n" - << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n" - << "nshared_first_page: " << t.nshared_first_page << "\n" - << "nshared_total: " << t.nshared_total << "\n" - << "nbits_nobjects: " << t.nbits_nobjects << "\n" - << "min_group_length: " << t.min_group_length << "\n" - << "nbits_delta_group_length: " << t.nbits_delta_group_length << "\n"; + info << "first_shared_obj: " << t.first_shared_obj << "\n" + << "first_shared_offset: " << adjusted_offset(t.first_shared_offset) << "\n" + << "nshared_first_page: " << t.nshared_first_page << "\n" + << "nshared_total: " << t.nshared_total << "\n" + << "nbits_nobjects: " << t.nbits_nobjects << "\n" + << "min_group_length: " << t.min_group_length << "\n" + << "nbits_delta_group_length: " << t.nbits_delta_group_length << "\n"; for (size_t i = 0; i < toS(t.nshared_total); ++i) { HSharedObjectEntry& se = t.entries.at(i); - *m->log->getInfo() << "Shared Object " << i << ":\n" - << " group length: " << se.delta_group_length + t.min_group_length - << "\n"; + info << "Shared Object " << i << ":\n" + << " group length: " << se.delta_group_length + t.min_group_length << "\n"; // PDF spec says signature present nobjects_minus_one are always 0, so print them only if // they have a non-zero value. if (se.signature_present) { - *m->log->getInfo() << " signature present\n"; + info << " signature present\n"; } if (se.nobjects_minus_one != 0) { - *m->log->getInfo() << " nobjects: " << se.nobjects_minus_one + 1 << "\n"; + info << " nobjects: " << se.nobjects_minus_one + 1 << "\n"; } } } @@ -1199,10 +1198,11 @@ Lin::dumpHSharedObject() void Lin::dumpHGeneric(HGeneric& t) { - *m->log->getInfo() << "first_object: " << t.first_object << "\n" - << "first_object_offset: " << adjusted_offset(t.first_object_offset) << "\n" - << "nobjects: " << t.nobjects << "\n" - << "group_length: " << t.group_length << "\n"; + *m->cf.log_->getInfo() << "first_object: " << t.first_object << "\n" + << "first_object_offset: " << adjusted_offset(t.first_object_offset) + << "\n" + << "nobjects: " << t.nobjects << "\n" + << "group_length: " << t.group_length << "\n"; } template diff --git a/libqpdf/QPDF_objects.cc b/libqpdf/QPDF_objects.cc index ea3144b..4e9ed6b 100644 --- a/libqpdf/QPDF_objects.cc +++ b/libqpdf/QPDF_objects.cc @@ -157,7 +157,7 @@ Objects::parse(char const* password) throw damagedPDF("", -1, std::string("error reading xref: ") + e.what()); } } catch (QPDFExc& e) { - if (m->attempt_recovery) { + if (m->cf.attempt_recovery_) { reconstruct_xref(e, xref_offset > 0); } else { throw; @@ -736,7 +736,7 @@ Objects::read_xrefTable(qpdf_offset_t xref_offset) } if (cur_trailer.hasKey("/XRefStm")) { - if (m->ignore_xref_streams) { + if (m->cf.ignore_xref_streams_) { QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer"); } else { if (cur_trailer.getKey("/XRefStm").isInteger()) { @@ -763,7 +763,7 @@ Objects::read_xrefTable(qpdf_offset_t xref_offset) qpdf_offset_t Objects::read_xrefStream(qpdf_offset_t xref_offset, bool in_stream_recovery) { - if (!m->ignore_xref_streams) { + if (!m->cf.ignore_xref_streams_) { QPDFObjectHandle xref_obj; try { m->in_read_xref_stream = true; @@ -1073,7 +1073,7 @@ Objects::insertFreeXrefEntry(QPDFObjGen og) void QPDF::showXRefTable() { - auto& cout = *m->log->getInfo(); + auto& cout = *m->cf.log_->getInfo(); for (auto const& iter: m->xref_table) { QPDFObjGen const& og = iter.first; QPDFXRefEntry const& entry = iter.second; @@ -1084,15 +1084,15 @@ QPDF::showXRefTable() break; case 2: - *m->log->getInfo() << "compressed; stream = " << entry.getObjStreamNumber() - << ", index = " << entry.getObjStreamIndex(); + *m->cf.log_->getInfo() << "compressed; stream = " << entry.getObjStreamNumber() + << ", index = " << entry.getObjStreamIndex(); break; default: throw std::logic_error("unknown cross-reference table type while showing xref_table"); break; } - m->log->info("\n"); + m->cf.log_->info("\n"); } } @@ -1248,7 +1248,7 @@ Objects::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offse throw damagedPDF("expected endstream"); } } catch (QPDFExc& e) { - if (m->attempt_recovery) { + if (m->cf.attempt_recovery_) { warn(e); length = recoverStreamLength(m->file, og, stream_offset); } else { @@ -1431,7 +1431,7 @@ Objects::readObjectAtOffset( QPDFObjGen og; setLastObjectDescription(description, exp_og); - if (!m->attempt_recovery) { + if (!m->cf.attempt_recovery_) { try_recovery = false; } diff --git a/libqpdf/qpdf/QPDF_private.hh b/libqpdf/qpdf/QPDF_private.hh index ed426aa..4794e98 100644 --- a/libqpdf/qpdf/QPDF_private.hh +++ b/libqpdf/qpdf/QPDF_private.hh @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,31 @@ namespace qpdf { class OffsetBuffer; } // namespace is + + class Doc: public QPDF + { + public: + class Config + { + friend class QPDF; + + Config() : + log_(QPDFLogger::defaultLogger()) + { + } + + std::shared_ptr log_; + + size_t max_warnings_{0}; + + bool provided_password_is_hex_key_{false}; + bool ignore_xref_streams_{false}; + bool suppress_warnings_{false}; + bool attempt_recovery_{true}; + bool check_mode_{false}; + bool immediate_copy_from_{false}; + }; // Class Config + }; // class Doc } // namespace qpdf class BitStream; @@ -421,10 +447,13 @@ class QPDF::Doc return *page_labels_; } - private: + protected: QPDF& qpdf; QPDF::Members* m; + qpdf::Doc::Config cf; + + private: // Document Helpers; std::unique_ptr acroform_; std::unique_ptr embedded_files_; @@ -969,18 +998,11 @@ class QPDF::Members: Doc Doc::Linearization lin; Doc::Objects objects; Doc::Pages pages; - std::shared_ptr log; unsigned long long unique_id{0}; qpdf::Tokenizer tokenizer; std::shared_ptr file; std::string last_object_description; std::shared_ptr last_ostream_description; - bool provided_password_is_hex_key{false}; - bool ignore_xref_streams{false}; - bool suppress_warnings{false}; - size_t max_warnings{0}; - bool attempt_recovery{true}; - bool check_mode{false}; std::shared_ptr encp; std::string pdf_version; std::map xref_table; @@ -995,7 +1017,6 @@ class QPDF::Members: Doc bool reconstructed_xref{false}; bool in_read_xref_stream{false}; bool fixed_dangling_refs{false}; - bool immediate_copy_from{false}; bool in_parse{false}; bool parsed{false}; std::set resolved_object_streams;