Commit cfcb279e49d1f2049a64652be7bf75d1ae557f1d
Committed by
Jay Berkenbilt
1 parent
008364a9
Alternative fix logic for fixDanglingReferences
Showing
3 changed files
with
30 additions
and
41 deletions
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); | ... | ... |