Commit faab52747272e12afaaff12f734ca2b38a9ccdea

Authored by m-holger
Committed by GitHub
2 parents 0d42bc0b 7bf08a22

Merge pull request #1619 from m-holger/root

Improve handling of root object `/Type` entries
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
1   -WARNING: catalgg.pdf: catalog /Type entry missing or invalid
  1 +WARNING: catalgg.pdf: Catalog: setting missing or invalid /Type entry to /Catalog
2 2 checking catalgg.pdf
3 3 PDF Version: 1.3
4 4 File is not encrypted
... ...
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
  1 +WARNING: issue-119.pdf: Catalog: setting missing or invalid /Type entry to /Catalog
1 2 qpdf: issue-119.pdf: unable to find page tree
... ...
qpdf/qtest/qpdf/issue-120.out
1 1 WARNING: issue-120.pdf (xref stream, offset 712): self-referential object stream 3
  2 +WARNING: issue-120.pdf: Catalog: setting missing or invalid /Type entry to /Catalog
2 3 qpdf: issue-120.pdf: unable to find page tree
... ...
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
... ...