Commit cfcb279e49d1f2049a64652be7bf75d1ae557f1d

Authored by m-holger
Committed by Jay Berkenbilt
1 parent 008364a9

Alternative fix logic for fixDanglingReferences

include/qpdf/QPDF.hh
... ... @@ -1173,6 +1173,7 @@ class QPDF
1173 1173 void inParse(bool);
1174 1174 void setTrailer(QPDFObjectHandle obj);
1175 1175 void read_xref(qpdf_offset_t offset);
  1176 + bool resolveXRefTable();
1176 1177 void reconstruct_xref(QPDFExc& e);
1177 1178 bool
1178 1179 parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes);
... ... @@ -1202,10 +1203,10 @@ class QPDF
1202 1203 bool attempt_recovery,
1203 1204 qpdf_offset_t offset,
1204 1205 std::string const& description,
1205   - QPDFObjGen const& exp_og,
  1206 + QPDFObjGen exp_og,
1206 1207 QPDFObjGen& og,
1207 1208 bool skip_cache_if_in_xref);
1208   - void resolve(QPDFObjGen const& og);
  1209 + void resolve(QPDFObjGen og);
1209 1210 void resolveObjectsInStream(int obj_stream_number);
1210 1211 void stopOnError(std::string const& message);
1211 1212 QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
... ...
libqpdf/QPDF.cc
... ... @@ -1292,48 +1292,36 @@ QPDF::showXRefTable()
1292 1292 }
1293 1293 }
1294 1294  
  1295 +// Resolve all objects in the xref table. If this triggers a xref table
  1296 +// reconstruction abort and return false. Otherwise return true.
  1297 +bool
  1298 +QPDF::resolveXRefTable()
  1299 +{
  1300 + bool may_change = !this->m->reconstructed_xref;
  1301 + for (auto& iter: this->m->xref_table) {
  1302 + if (isUnresolved(iter.first)) {
  1303 + resolve(iter.first);
  1304 + if (may_change && this->m->reconstructed_xref) {
  1305 + return false;
  1306 + }
  1307 + }
  1308 + }
  1309 + return true;
  1310 +}
  1311 +
  1312 +// Ensure all objects in the pdf file, including those in indirect
  1313 +// references, appear in the object cache.
1295 1314 void
1296 1315 QPDF::fixDanglingReferences(bool force)
1297 1316 {
1298   - // Ensure all objects in the pdf file, including those in indirect
1299   - // references, appear in the object cache.
1300   - if (this->m->fixed_dangling_refs && !force) {
  1317 + if (this->m->fixed_dangling_refs) {
1301 1318 return;
1302 1319 }
1303   -
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);
1311   - }
1312   - }
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;
1318   - for (auto const& iter: this->m->obj_cache) {
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.
  1320 + if (!resolveXRefTable()) {
1332 1321 QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction");
1333   - fixDanglingReferences(force);
1334   - } else {
1335   - this->m->fixed_dangling_refs = true;
  1322 + resolveXRefTable();
1336 1323 }
  1324 + this->m->fixed_dangling_refs = true;
1337 1325 }
1338 1326  
1339 1327 size_t
... ... @@ -1356,7 +1344,7 @@ QPDF::getAllObjects()
1356 1344 {
1357 1345 // After fixDanglingReferences is called, all objects are in the
1358 1346 // object cache.
1359   - fixDanglingReferences(true);
  1347 + fixDanglingReferences();
1360 1348 std::vector<QPDFObjectHandle> result;
1361 1349 for (auto const& iter: this->m->obj_cache) {
1362 1350 result.push_back(newIndirect(iter.first, iter.second.object));
... ... @@ -1616,7 +1604,7 @@ QPDF::readObjectAtOffset(
1616 1604 bool try_recovery,
1617 1605 qpdf_offset_t offset,
1618 1606 std::string const& description,
1619   - QPDFObjGen const& exp_og,
  1607 + QPDFObjGen exp_og,
1620 1608 QPDFObjGen& og,
1621 1609 bool skip_cache_if_in_xref)
1622 1610 {
... ... @@ -1799,7 +1787,7 @@ QPDF::readObjectAtOffset(
1799 1787 }
1800 1788  
1801 1789 void
1802   -QPDF::resolve(QPDFObjGen const& og)
  1790 +QPDF::resolve(QPDFObjGen og)
1803 1791 {
1804 1792 if (!isUnresolved(og)) {
1805 1793 return;
... ...
libqpdf/QPDFWriter.cc
... ... @@ -2266,7 +2266,7 @@ QPDFWriter::prepareFileForWrite()
2266 2266 // Make document extension level information direct as required by
2267 2267 // the spec.
2268 2268  
2269   - this->m->pdf.fixDanglingReferences(true);
  2269 + this->m->pdf.fixDanglingReferences();
2270 2270 QPDFObjectHandle root = this->m->pdf.getRoot();
2271 2271 for (auto const& key: root.getKeys()) {
2272 2272 QPDFObjectHandle oh = root.getKey(key);
... ...