Commit 3dd27a1dd6c1f05b0931ec47fc430ab60e0a87e7
1 parent
206c2fc1
Detect and warn about outline loops during structure traversal in `--check`. Upd…
…ate tests and adjust exit status accordingly.
Showing
5 changed files
with
18 additions
and
6 deletions
libqpdf/QPDFOutlineDocumentHelper.cc
| @@ -53,7 +53,11 @@ QPDFOutlineDocumentHelper::validate(bool repair) | @@ -53,7 +53,11 @@ QPDFOutlineDocumentHelper::validate(bool repair) | ||
| 53 | } | 53 | } |
| 54 | QPDFObjectHandle cur = outlines.getKey("/First"); | 54 | QPDFObjectHandle cur = outlines.getKey("/First"); |
| 55 | QPDFObjGen::set seen; | 55 | QPDFObjGen::set seen; |
| 56 | - while (!cur.null() && seen.add(cur)) { | 56 | + while (!cur.null()) { |
| 57 | + if (!seen.add(cur)) { | ||
| 58 | + cur.warn("Loop detected loop in /Outlines tree"); | ||
| 59 | + return; | ||
| 60 | + } | ||
| 57 | m->outlines.emplace_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1)); | 61 | m->outlines.emplace_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1)); |
| 58 | cur = cur.getKey("/Next"); | 62 | cur = cur.getKey("/Next"); |
| 59 | } | 63 | } |
libqpdf/QPDFOutlineObjectHelper.cc
| @@ -20,15 +20,20 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( | @@ -20,15 +20,20 @@ QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( | ||
| 20 | return; | 20 | return; |
| 21 | } | 21 | } |
| 22 | if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) { | 22 | if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) { |
| 23 | + a_oh.warn("Loop detected loop in /Outlines tree"); | ||
| 23 | return; | 24 | return; |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | QPDFObjGen::set children; | 27 | QPDFObjGen::set children; |
| 27 | QPDFObjectHandle cur = a_oh.getKey("/First"); | 28 | QPDFObjectHandle cur = a_oh.getKey("/First"); |
| 28 | - while (!cur.null() && cur.isIndirect() && children.add(cur)) { | 29 | + while (!cur.null() && cur.isIndirect()) { |
| 30 | + if (!children.add(cur)) { | ||
| 31 | + cur.warn("Loop detected loop in /Outlines tree"); | ||
| 32 | + break; | ||
| 33 | + } | ||
| 29 | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); | 34 | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); |
| 30 | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); | 35 | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); |
| 31 | - m->kids.push_back(new_ooh); | 36 | + m->kids.emplace_back(new_ooh); |
| 32 | cur = cur.getKey("/Next"); | 37 | cur = cur.getKey("/Next"); |
| 33 | } | 38 | } |
| 34 | } | 39 | } |
qpdf/qtest/outlines.test
| @@ -32,7 +32,7 @@ foreach my $f (@outline_files) | @@ -32,7 +32,7 @@ foreach my $f (@outline_files) | ||
| 32 | 32 | ||
| 33 | $td->runtest("outlines: outlines-with-loop --check", | 33 | $td->runtest("outlines: outlines-with-loop --check", |
| 34 | {$td->COMMAND => "qpdf --check outlines-with-loop.pdf"}, | 34 | {$td->COMMAND => "qpdf --check outlines-with-loop.pdf"}, |
| 35 | - {$td->FILE => "outlines-with-loop-check.out", $td->EXIT_STATUS => 0}, | 35 | + {$td->FILE => "outlines-with-loop-check.out", $td->EXIT_STATUS => 3}, |
| 36 | $td->NORMALIZE_NEWLINES); | 36 | $td->NORMALIZE_NEWLINES); |
| 37 | 37 | ||
| 38 | cleanup(); | 38 | cleanup(); |
qpdf/qtest/qpdf/outlines-with-loop-check.out
| @@ -2,5 +2,6 @@ checking outlines-with-loop.pdf | @@ -2,5 +2,6 @@ checking outlines-with-loop.pdf | ||
| 2 | PDF Version: 1.3 | 2 | PDF Version: 1.3 |
| 3 | File is not encrypted | 3 | File is not encrypted |
| 4 | File is not linearized | 4 | File is not linearized |
| 5 | -No syntax or stream encoding errors found; the file may still contain | ||
| 6 | -errors that qpdf cannot detect | 5 | +WARNING: outlines-with-loop.pdf, object 4 0 at offset 637: Loop detected loop in /Outlines tree |
| 6 | +WARNING: outlines-with-loop.pdf, object 5 0 at offset 855: Loop detected loop in /Outlines tree | ||
| 7 | +qpdf: operation succeeded with warnings |
qpdf/qtest/qpdf/outlines-with-loop.out
| 1 | +WARNING: outlines-with-loop.pdf, object 4 0 at offset 637: Loop detected loop in /Outlines tree | ||
| 2 | +WARNING: outlines-with-loop.pdf, object 5 0 at offset 855: Loop detected loop in /Outlines tree | ||
| 1 | page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ] | 3 | page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ] |
| 2 | page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ] | 4 | page 5: Potato 1 -> 5: /XYZ null null null -> [ 11 0 R /XYZ null null null ] |
| 3 | page 11: Mern 1.1 -> 11: /Fit -> [ 17 0 R /Fit ] | 5 | page 11: Mern 1.1 -> 11: /Fit -> [ 17 0 R /Fit ] |