Commit ff42ea4e6cb8b03badf31993fcb4d9f57bb2ad1e

Authored by Jay Berkenbilt
Committed by Jay Berkenbilt
1 parent 1d9209ee

Fix logic for fixDanglingReferences

libqpdf/QPDF.cc
... ... @@ -1292,48 +1292,48 @@ QPDF::showXRefTable()
1292 1292 }
1293 1293 }
1294 1294  
1295   -// Ensure all objects in the pdf file, including those in indirect references,
1296   -// appear in the object cache.
1297 1295 void
1298 1296 QPDF::fixDanglingReferences(bool force)
1299 1297 {
  1298 + // Ensure all objects in the pdf file, including those in indirect
  1299 + // references, appear in the object cache.
1300 1300 if (this->m->fixed_dangling_refs && !force) {
1301 1301 return;
1302 1302 }
1303 1303  
1304   - if (!this->m->fixed_dangling_refs) {
1305   - // First pass is only run if the the xref table has not been
1306   - // reconstructed. It will be terminated as soon as reconstruction is
1307   - // triggered.
1308   - if (!this->m->reconstructed_xref) {
1309   - for (auto const& iter: this->m->xref_table) {
1310   - auto og = iter.first;
1311   - if (!isCached(og)) {
1312   - m->obj_cache[og] =
1313   - ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
1314   - if (this->m->reconstructed_xref) {
1315   - break;
1316   - }
1317   - }
1318   - }
1319   - }
1320   - // Second pass is skipped if the first pass did not trigger
1321   - // reconstruction of the xref table.
1322   - if (this->m->reconstructed_xref) {
1323   - for (auto const& iter: this->m->xref_table) {
1324   - auto og = iter.first;
1325   - if (!isCached(og)) {
1326   - m->obj_cache[og] =
1327   - ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
1328   - }
1329   - }
  1304 + // Make sure everything in the xref table appears in the object
  1305 + // cache.
  1306 + for (auto const& iter: this->m->xref_table) {
  1307 + auto og = iter.first;
  1308 + if (!isCached(og)) {
  1309 + m->obj_cache[og] =
  1310 + ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
1330 1311 }
1331 1312 }
1332   - // Final pass adds all indirect references to the object cache.
  1313 +
  1314 + // Resolve all known objects. The parser inserts any indirect
  1315 + // reference into the object cache, including dangling references.
  1316 + bool orig_reconstructed_xref = this->m->reconstructed_xref;
  1317 + bool triggered_xref_reconstruction = false;
1333 1318 for (auto const& iter: this->m->obj_cache) {
1334 1319 resolve(iter.first);
  1320 + if (!orig_reconstructed_xref && this->m->reconstructed_xref) {
  1321 + triggered_xref_reconstruction = true;
  1322 + // We triggered xref reconstruction. We'll have to start
  1323 + // over.
  1324 + break;
  1325 + }
  1326 + }
  1327 + if (triggered_xref_reconstruction) {
  1328 + // Resolving objects triggered xref reconstruction. This may
  1329 + // cause new objects to appear in the xref. Start over again.
  1330 + // This recursive call can never go more than two deep since
  1331 + // we never clear this->m->reconstructed_xref.
  1332 + QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction");
  1333 + fixDanglingReferences(force);
  1334 + } else {
  1335 + this->m->fixed_dangling_refs = true;
1335 1336 }
1336   - this->m->fixed_dangling_refs = true;
1337 1337 }
1338 1338  
1339 1339 size_t
... ...
qpdf/qpdf.testcov
... ... @@ -678,3 +678,4 @@ QPDF_json bad pushedinheritedpageresources 0
678 678 QPDFPageObjectHelper copied fallback 0
679 679 QPDFPageObjectHelper used fallback without copying 0
680 680 QPDF skipping cache for known unchecked object 0
  681 +QPDF fix dangling triggered xref reconstruction 0
... ...
qpdf/qtest/dangling-refs.test
... ... @@ -19,21 +19,13 @@ my $n_tests = 2 * scalar(@dangling);
19 19  
20 20 foreach my $f (@dangling)
21 21 {
22   - # TEMPORARY
23   - my $xflags = 0;
24   - if ($f eq 'dangling-bad-xref')
25   - {
26   - $xflags = $td->EXPECT_FAILURE;
27   - }
28   - # END TEMPORARY
29 22 $td->runtest("dangling refs: $f",
30 23 {$td->COMMAND => "test_driver 53 $f.pdf"},
31 24 {$td->FILE => "$f-dangling.out", $td->EXIT_STATUS => 0},
32   - $td->NORMALIZE_NEWLINES | $xflags);
  25 + $td->NORMALIZE_NEWLINES);
33 26 $td->runtest("check output",
34 27 {$td->FILE => "a.pdf"},
35   - {$td->FILE => "$f-dangling-out.pdf"},
36   - $xflags);
  28 + {$td->FILE => "$f-dangling-out.pdf"});
37 29 }
38 30 cleanup();
39 31 $td->report($n_tests);
... ...