Commit faab52747272e12afaaff12f734ca2b38a9ccdea
Committed by
GitHub
Merge pull request #1619 from m-holger/root
Improve handling of root object `/Type` entries
Showing
10 changed files
with
46 additions
and
15 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -670,11 +670,15 @@ QPDF::getRoot() |
| 670 | 670 | if (!Root) { |
| 671 | 671 | throw m->c.damagedPDF("", -1, "unable to find /Root dictionary"); |
| 672 | 672 | } |
| 673 | - // Check_mode is an interim solution to request #810 pending a more comprehensive review of the | |
| 674 | - // approach to more extensive checks and warning levels. | |
| 675 | - if (m->cf.check_mode() && Name(Root["/Type"]) != "/Catalog") { | |
| 676 | - warn(m->c.damagedPDF("", -1, "catalog /Type entry missing or invalid")); | |
| 677 | - Root.replace("/Type", Name("/Catalog")); | |
| 673 | + if (!m->objects.root_checked()) { | |
| 674 | + m->objects.root_checked(true); | |
| 675 | + if (Name(Root["/Type"]) != "/Catalog") { | |
| 676 | + warn(m->c.damagedPDF( | |
| 677 | + "", -1, "Catalog: setting missing or invalid /Type entry to /Catalog")); | |
| 678 | + if (!global::Options::inspection_mode()) { | |
| 679 | + Root.replace("/Type", Name("/Catalog")); | |
| 680 | + } | |
| 681 | + } | |
| 678 | 682 | } |
| 679 | 683 | return Root.oh(); |
| 680 | 684 | } | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -1022,6 +1022,19 @@ class QPDF::Doc::Objects: Common |
| 1022 | 1022 | { |
| 1023 | 1023 | return uncompressed_after_compressed_; |
| 1024 | 1024 | } |
| 1025 | + | |
| 1026 | + bool | |
| 1027 | + root_checked() const | |
| 1028 | + { | |
| 1029 | + return root_checked_; | |
| 1030 | + } | |
| 1031 | + | |
| 1032 | + void | |
| 1033 | + root_checked(bool val) | |
| 1034 | + { | |
| 1035 | + root_checked_ = val; | |
| 1036 | + } | |
| 1037 | + | |
| 1025 | 1038 | void parse(char const* password); |
| 1026 | 1039 | std::shared_ptr<QPDFObject> const& resolve(QPDFObjGen og); |
| 1027 | 1040 | void inParse(bool); |
| ... | ... | @@ -1106,6 +1119,7 @@ class QPDF::Doc::Objects: Common |
| 1106 | 1119 | // Linearization data |
| 1107 | 1120 | qpdf_offset_t first_xref_item_offset_{0}; // actual value from file |
| 1108 | 1121 | bool uncompressed_after_compressed_{false}; |
| 1122 | + bool root_checked_{false}; | |
| 1109 | 1123 | }; // class QPDF::Doc::Objects |
| 1110 | 1124 | |
| 1111 | 1125 | // This class is used to represent a PDF Pages tree. | ... | ... |
manual/release-notes.rst
| 1 | 1 | .. _ticket: https://issues.qpdf.org |
| 2 | 2 | .. _shared null: https://wiki.qpdf.org/PDF-null-objects-vs-qpdf-null-objects |
| 3 | 3 | |
| 4 | + | |
| 4 | 5 | .. _release-notes: |
| 5 | 6 | |
| 6 | 7 | Release Notes |
| ... | ... | @@ -17,7 +18,7 @@ more detail. |
| 17 | 18 | - Release changes |
| 18 | 19 | |
| 19 | 20 | - Starting with version 12.3.0, we use |
| 20 | - `cosign<https://docs.sigstore.dev/cosign/>__`, rather than GPG, | |
| 21 | + `cosign <https://docs.sigstore.dev/cosign/>`__, rather than GPG, | |
| 21 | 22 | to sign releases. See the top-level README.md for instructions. |
| 22 | 23 | We will continue to use GPG for the 12.x series. Starting with |
| 23 | 24 | qpdf version 13, only cosign will be used. |
| ... | ... | @@ -122,14 +123,8 @@ more detail. |
| 122 | 123 | ``damaged_pdf`` error with message "unable to find /Root dictionary" |
| 123 | 124 | rather than an internal error. |
| 124 | 125 | |
| 125 | -.. _r12-3-0-deprecate: | |
| 126 | - | |
| 127 | - - The following are believed to be not in use and have been deprecated. | |
| 128 | - If you are relying on them please open a ticket_. | |
| 129 | - | |
| 130 | - - QPDF::compute_encryption_key | |
| 131 | - - All QPDF::EncryptionData methods. These methods are not exported in the | |
| 132 | - shared library and are only useable in statically linked programs. | |
| 126 | + - Invalid root object `/Type` entries are now unconditionally repaired [#inspect]_. | |
| 127 | + Previously they were only repaired if the :qpdf:ref:`--check` option was used. | |
| 133 | 128 | |
| 134 | 129 | - Setting :qpdf:ref:`--compress-streams` to ``n`` or |
| 135 | 130 | ``QPDFWriter::setCompressStreams(false)`` no longer automatically |
| ... | ... | @@ -141,6 +136,18 @@ more detail. |
| 141 | 136 | registered by calling ``QPDF::registerStreamFilter``. If you are |
| 142 | 137 | providing your own stream filters please open a ticket_. |
| 143 | 138 | |
| 139 | +.. _r12-3-0-deprecate: | |
| 140 | + | |
| 141 | + - The following are believed to be not in use and have been deprecated. | |
| 142 | + If you are relying on them please open a ticket_. | |
| 143 | + | |
| 144 | + - QPDF::compute_encryption_key | |
| 145 | + | |
| 146 | + - All QPDF::EncryptionData methods. These methods are not exported in the | |
| 147 | + shared library and are only useable in statically linked programs. | |
| 148 | + | |
| 149 | +.. [#inspect] not in :ref:`inspection-mode` | |
| 150 | + | |
| 144 | 151 | 12.2.0: May 4, 2025 |
| 145 | 152 | - Upcoming C++ Version Change |
| 146 | 153 | ... | ... |
qpdf/qtest/qpdf/bad-direct-root.out
| ... | ... | @@ -5,6 +5,7 @@ WARNING: bad-direct-root.pdf: Attempting to reconstruct cross-reference table |
| 5 | 5 | WARNING: bad-direct-root.pdf (trailer, offset 249): unknown token while reading object; treating as null |
| 6 | 6 | WARNING: bad-direct-root.pdf (trailer, offset 261): unknown token while reading object; treating as null |
| 7 | 7 | WARNING: bad-direct-root.pdf (trailer, offset 186): expected dictionary keys but found non-name objects; ignoring |
| 8 | +WARNING: bad-direct-root.pdf: Catalog: setting missing or invalid /Type entry to /Catalog | |
| 8 | 9 | WARNING: bad-direct-root.pdf (object 1 0, offset 65): expected endobj |
| 9 | 10 | WARNING: bad-direct-root.pdf (object 2 0, offset 114): unknown token while reading object; treating as null |
| 10 | 11 | WARNING: bad-direct-root.pdf (object 2 0, offset 122): invalid character (/) in hexstring | ... | ... |
qpdf/qtest/qpdf/catalgg.out
qpdf/qtest/qpdf/fuzz-16214.out
| ... | ... | @@ -6,6 +6,7 @@ WARNING: fuzz-16214.pdf (xref stream, offset 116): Cross-reference stream data h |
| 6 | 6 | WARNING: fuzz-16214.pdf: reported number of objects (6) is not one plus the highest object number (35) |
| 7 | 7 | WARNING: fuzz-16214.pdf (object 14 0, offset 652): expected dictionary key but found non-name object; inserting key /QPDFFake1 |
| 8 | 8 | WARNING: fuzz-16214.pdf (object 14 0, offset 734): expected endobj |
| 9 | +WARNING: fuzz-16214.pdf: Catalog: setting missing or invalid /Type entry to /Catalog | |
| 9 | 10 | WARNING: fuzz-16214.pdf: file is damaged |
| 10 | 11 | WARNING: fuzz-16214.pdf (object 1 0, offset 7189): expected n n obj |
| 11 | 12 | WARNING: fuzz-16214.pdf: Attempting to reconstruct cross-reference table | ... | ... |
qpdf/qtest/qpdf/issue-119.out
qpdf/qtest/qpdf/issue-120.out
qpdf/qtest/qpdf/issue-143.out
| ... | ... | @@ -19,4 +19,5 @@ WARNING: issue-143.pdf object stream 1 (object 0 0, offset 11): object id is inv |
| 19 | 19 | WARNING: issue-143.pdf object stream 1 (object 6 0, offset 21): offset 0 is invalid (must be larger than previous offset 0) |
| 20 | 20 | WARNING: issue-143.pdf object stream 1 (object 0 0, offset 23): object id is invalid |
| 21 | 21 | WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1 |
| 22 | +WARNING: issue-143.pdf: Catalog: setting missing or invalid /Type entry to /Catalog | |
| 22 | 23 | qpdf: issue-143.pdf: unable to find page tree | ... | ... |
qpdf/qtest/qpdf/issue-51.out
| ... | ... | @@ -3,4 +3,5 @@ WARNING: issue-51.pdf: reported number of objects (0) is not one plus the highes |
| 3 | 3 | WARNING: issue-51.pdf (object 7 0, offset 500): treating bad indirect reference (0 0 R) as null |
| 4 | 4 | WARNING: issue-51.pdf (object 7 0, offset 476): dictionary has duplicated key /0000; last occurrence overrides earlier ones |
| 5 | 5 | WARNING: issue-51.pdf (object 7 0, offset 553): expected endobj |
| 6 | +WARNING: issue-51.pdf: Catalog: setting missing or invalid /Type entry to /Catalog | |
| 6 | 7 | issue-51.pdf: unable to find page tree | ... | ... |