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,6 +1173,7 @@ class QPDF
1173 void inParse(bool); 1173 void inParse(bool);
1174 void setTrailer(QPDFObjectHandle obj); 1174 void setTrailer(QPDFObjectHandle obj);
1175 void read_xref(qpdf_offset_t offset); 1175 void read_xref(qpdf_offset_t offset);
  1176 + bool resolveXRefTable();
1176 void reconstruct_xref(QPDFExc& e); 1177 void reconstruct_xref(QPDFExc& e);
1177 bool 1178 bool
1178 parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes); 1179 parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes);
@@ -1202,10 +1203,10 @@ class QPDF @@ -1202,10 +1203,10 @@ class QPDF
1202 bool attempt_recovery, 1203 bool attempt_recovery,
1203 qpdf_offset_t offset, 1204 qpdf_offset_t offset,
1204 std::string const& description, 1205 std::string const& description,
1205 - QPDFObjGen const& exp_og, 1206 + QPDFObjGen exp_og,
1206 QPDFObjGen& og, 1207 QPDFObjGen& og,
1207 bool skip_cache_if_in_xref); 1208 bool skip_cache_if_in_xref);
1208 - void resolve(QPDFObjGen const& og); 1209 + void resolve(QPDFObjGen og);
1209 void resolveObjectsInStream(int obj_stream_number); 1210 void resolveObjectsInStream(int obj_stream_number);
1210 void stopOnError(std::string const& message); 1211 void stopOnError(std::string const& message);
1211 QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); 1212 QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
libqpdf/QPDF.cc
@@ -1292,48 +1292,36 @@ QPDF::showXRefTable() @@ -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 void 1314 void
1296 QPDF::fixDanglingReferences(bool force) 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 return; 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 QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction"); 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 size_t 1327 size_t
@@ -1356,7 +1344,7 @@ QPDF::getAllObjects() @@ -1356,7 +1344,7 @@ QPDF::getAllObjects()
1356 { 1344 {
1357 // After fixDanglingReferences is called, all objects are in the 1345 // After fixDanglingReferences is called, all objects are in the
1358 // object cache. 1346 // object cache.
1359 - fixDanglingReferences(true); 1347 + fixDanglingReferences();
1360 std::vector<QPDFObjectHandle> result; 1348 std::vector<QPDFObjectHandle> result;
1361 for (auto const& iter: this->m->obj_cache) { 1349 for (auto const& iter: this->m->obj_cache) {
1362 result.push_back(newIndirect(iter.first, iter.second.object)); 1350 result.push_back(newIndirect(iter.first, iter.second.object));
@@ -1616,7 +1604,7 @@ QPDF::readObjectAtOffset( @@ -1616,7 +1604,7 @@ QPDF::readObjectAtOffset(
1616 bool try_recovery, 1604 bool try_recovery,
1617 qpdf_offset_t offset, 1605 qpdf_offset_t offset,
1618 std::string const& description, 1606 std::string const& description,
1619 - QPDFObjGen const& exp_og, 1607 + QPDFObjGen exp_og,
1620 QPDFObjGen& og, 1608 QPDFObjGen& og,
1621 bool skip_cache_if_in_xref) 1609 bool skip_cache_if_in_xref)
1622 { 1610 {
@@ -1799,7 +1787,7 @@ QPDF::readObjectAtOffset( @@ -1799,7 +1787,7 @@ QPDF::readObjectAtOffset(
1799 } 1787 }
1800 1788
1801 void 1789 void
1802 -QPDF::resolve(QPDFObjGen const& og) 1790 +QPDF::resolve(QPDFObjGen og)
1803 { 1791 {
1804 if (!isUnresolved(og)) { 1792 if (!isUnresolved(og)) {
1805 return; 1793 return;
libqpdf/QPDFWriter.cc
@@ -2266,7 +2266,7 @@ QPDFWriter::prepareFileForWrite() @@ -2266,7 +2266,7 @@ QPDFWriter::prepareFileForWrite()
2266 // Make document extension level information direct as required by 2266 // Make document extension level information direct as required by
2267 // the spec. 2267 // the spec.
2268 2268
2269 - this->m->pdf.fixDanglingReferences(true); 2269 + this->m->pdf.fixDanglingReferences();
2270 QPDFObjectHandle root = this->m->pdf.getRoot(); 2270 QPDFObjectHandle root = this->m->pdf.getRoot();
2271 for (auto const& key: root.getKeys()) { 2271 for (auto const& key: root.getKeys()) {
2272 QPDFObjectHandle oh = root.getKey(key); 2272 QPDFObjectHandle oh = root.getKey(key);