Commit 2015f71c7d6e316db6ae3cd6a9189b8ed8308c04

Authored by m-holger
1 parent 83897e87

Add new inner class to QPDF::Objects

include/qpdf/QPDF.hh
@@ -730,6 +730,7 @@ class QPDF @@ -730,6 +730,7 @@ class QPDF
730 class Writer; 730 class Writer;
731 class Resolver; 731 class Resolver;
732 class StreamCopier; 732 class StreamCopier;
  733 + class Objects;
733 class ParseGuard; 734 class ParseGuard;
734 class Pipe; 735 class Pipe;
735 class JobSetter; 736 class JobSetter;
@@ -757,6 +758,7 @@ class QPDF @@ -757,6 +758,7 @@ class QPDF
757 class ResolveRecorder; 758 class ResolveRecorder;
758 class JSONReactor; 759 class JSONReactor;
759 760
  761 + inline Objects& objects();
760 void parse(char const* password); 762 void parse(char const* password);
761 void inParse(bool); 763 void inParse(bool);
762 void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); 764 void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
libqpdf/QPDF.cc
@@ -185,7 +185,8 @@ QPDF::Members::Members(QPDF& qpdf) : @@ -185,7 +185,8 @@ QPDF::Members::Members(QPDF& qpdf) :
185 file_sp(new InvalidInputSource(no_input_name)), 185 file_sp(new InvalidInputSource(no_input_name)),
186 file(file_sp.get()), 186 file(file_sp.get()),
187 encp(new EncryptionParameters), 187 encp(new EncryptionParameters),
188 - xref_table(qpdf, file) 188 + objects(qpdf, this),
  189 + xref_table(qpdf, objects, file)
189 { 190 {
190 } 191 }
191 192
@@ -211,7 +212,7 @@ QPDF::~QPDF() @@ -211,7 +212,7 @@ QPDF::~QPDF()
211 // are reachable from this object to release their association with this QPDF. Direct objects 212 // are reachable from this object to release their association with this QPDF. Direct objects
212 // are not destroyed since they can be moved to other QPDF objects safely. 213 // are not destroyed since they can be moved to other QPDF objects safely.
213 214
214 - for (auto const& iter: m->obj_cache) { 215 + for (auto const& iter: m->objects.obj_cache) {
215 iter.second.object->disconnect(); 216 iter.second.object->disconnect();
216 if (iter.second.object->getTypeCode() != ::ot_null) { 217 if (iter.second.object->getTypeCode() != ::ot_null) {
217 iter.second.object->destroy(); 218 iter.second.object->destroy();
@@ -494,8 +495,8 @@ QPDF::getObjectCount() @@ -494,8 +495,8 @@ QPDF::getObjectCount()
494 // be in obj_cache. 495 // be in obj_cache.
495 fixDanglingReferences(); 496 fixDanglingReferences();
496 QPDFObjGen og; 497 QPDFObjGen og;
497 - if (!m->obj_cache.empty()) {  
498 - og = (*(m->obj_cache.rbegin())).first; 498 + if (!m->objects.obj_cache.empty()) {
  499 + og = (*(m->objects.obj_cache.rbegin())).first;
499 } 500 }
500 return toS(og.getObj()); 501 return toS(og.getObj());
501 } 502 }
@@ -575,12 +576,12 @@ QPDF::newStream(std::string const& data) @@ -575,12 +576,12 @@ QPDF::newStream(std::string const& data)
575 QPDFObjectHandle 576 QPDFObjectHandle
576 QPDF::getObject(QPDFObjGen const& og) 577 QPDF::getObject(QPDFObjGen const& og)
577 { 578 {
578 - if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { 579 + if (auto it = m->objects.obj_cache.find(og); it != m->objects.obj_cache.end()) {
579 return {it->second.object}; 580 return {it->second.object};
580 } else if (m->xref_table.initialized() && !m->xref_table.type(og)) { 581 } else if (m->xref_table.initialized() && !m->xref_table.type(og)) {
581 return QPDF_Null::create(); 582 return QPDF_Null::create();
582 } else { 583 } else {
583 - auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og)); 584 + auto result = m->objects.obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og));
584 return {result.first->second.object}; 585 return {result.first->second.object};
585 } 586 }
586 } 587 }
libqpdf/QPDF_objects.cc
@@ -1152,7 +1152,7 @@ QPDF::getAllObjects() @@ -1152,7 +1152,7 @@ QPDF::getAllObjects()
1152 // After fixDanglingReferences is called, all objects are in the object cache. 1152 // After fixDanglingReferences is called, all objects are in the object cache.
1153 fixDanglingReferences(); 1153 fixDanglingReferences();
1154 std::vector<QPDFObjectHandle> result; 1154 std::vector<QPDFObjectHandle> result;
1155 - for (auto const& iter: m->obj_cache) { 1155 + for (auto const& iter: m->objects.obj_cache) {
1156 result.push_back(newIndirect(iter.first, iter.second.object)); 1156 result.push_back(newIndirect(iter.first, iter.second.object));
1157 } 1157 }
1158 return result; 1158 return result;
@@ -1537,7 +1537,7 @@ QPDFObject* @@ -1537,7 +1537,7 @@ QPDFObject*
1537 QPDF::resolve(QPDFObjGen og) 1537 QPDF::resolve(QPDFObjGen og)
1538 { 1538 {
1539 if (!isUnresolved(og)) { 1539 if (!isUnresolved(og)) {
1540 - return m->obj_cache[og].object.get(); 1540 + return m->objects.obj_cache[og].object.get();
1541 } 1541 }
1542 1542
1543 if (m->resolving.count(og)) { 1543 if (m->resolving.count(og)) {
@@ -1546,7 +1546,7 @@ QPDF::resolve(QPDFObjGen og) @@ -1546,7 +1546,7 @@ QPDF::resolve(QPDFObjGen og)
1546 QTC::TC("qpdf", "QPDF recursion loop in resolve"); 1546 QTC::TC("qpdf", "QPDF recursion loop in resolve");
1547 warn(damagedPDF("", "loop detected resolving object " + og.unparse(' '))); 1547 warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
1548 updateCache(og, QPDF_Null::create()); 1548 updateCache(og, QPDF_Null::create());
1549 - return m->obj_cache[og].object.get(); 1549 + return m->objects.obj_cache[og].object.get();
1550 } 1550 }
1551 ResolveRecorder rr(this, og); 1551 ResolveRecorder rr(this, og);
1552 1552
@@ -1584,7 +1584,7 @@ QPDF::resolve(QPDFObjGen og) @@ -1584,7 +1584,7 @@ QPDF::resolve(QPDFObjGen og)
1584 updateCache(og, QPDF_Null::create()); 1584 updateCache(og, QPDF_Null::create());
1585 } 1585 }
1586 1586
1587 - auto result(m->obj_cache[og].object); 1587 + auto result(m->objects.obj_cache[og].object);
1588 result->setDefaultDescription(this, og); 1588 result->setDefaultDescription(this, og);
1589 return result.get(); 1589 return result.get();
1590 } 1590 }
@@ -1690,23 +1690,23 @@ QPDF::updateCache(QPDFObjGen const&amp; og, std::shared_ptr&lt;QPDFObject&gt; const&amp; objec @@ -1690,23 +1690,23 @@ QPDF::updateCache(QPDFObjGen const&amp; og, std::shared_ptr&lt;QPDFObject&gt; const&amp; objec
1690 { 1690 {
1691 object->setObjGen(this, og); 1691 object->setObjGen(this, og);
1692 if (isCached(og)) { 1692 if (isCached(og)) {
1693 - auto& cache = m->obj_cache[og]; 1693 + auto& cache = m->objects.obj_cache[og];
1694 cache.object->assign(object); 1694 cache.object->assign(object);
1695 } else { 1695 } else {
1696 - m->obj_cache[og] = ObjCache(object); 1696 + m->objects.obj_cache[og] = ObjCache(object);
1697 } 1697 }
1698 } 1698 }
1699 1699
1700 bool 1700 bool
1701 QPDF::isCached(QPDFObjGen const& og) 1701 QPDF::isCached(QPDFObjGen const& og)
1702 { 1702 {
1703 - return m->obj_cache.count(og) != 0; 1703 + return m->objects.obj_cache.count(og) != 0;
1704 } 1704 }
1705 1705
1706 bool 1706 bool
1707 QPDF::isUnresolved(QPDFObjGen const& og) 1707 QPDF::isUnresolved(QPDFObjGen const& og)
1708 { 1708 {
1709 - return !isCached(og) || m->obj_cache[og].object->isUnresolved(); 1709 + return !isCached(og) || m->objects.obj_cache[og].object->isUnresolved();
1710 } 1710 }
1711 1711
1712 QPDFObjGen 1712 QPDFObjGen
@@ -1723,8 +1723,8 @@ QPDFObjectHandle @@ -1723,8 +1723,8 @@ QPDFObjectHandle
1723 QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj) 1723 QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
1724 { 1724 {
1725 QPDFObjGen next{nextObjGen()}; 1725 QPDFObjGen next{nextObjGen()};
1726 - m->obj_cache[next] = ObjCache(obj);  
1727 - return newIndirect(next, m->obj_cache[next].object); 1726 + m->objects.obj_cache[next] = ObjCache(obj);
  1727 + return newIndirect(next, m->objects.obj_cache[next].object);
1728 } 1728 }
1729 1729
1730 std::shared_ptr<QPDFObject> 1730 std::shared_ptr<QPDFObject>
@@ -1732,23 +1732,24 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf) @@ -1732,23 +1732,24 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
1732 { 1732 {
1733 // This method is called by the parser and therefore must not resolve any objects. 1733 // This method is called by the parser and therefore must not resolve any objects.
1734 auto og = QPDFObjGen(id, gen); 1734 auto og = QPDFObjGen(id, gen);
1735 - if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) { 1735 + if (auto iter = m->objects.obj_cache.find(og); iter != m->objects.obj_cache.end()) {
1736 return iter->second.object; 1736 return iter->second.object;
1737 } 1737 }
1738 if (m->xref_table.type(og) || !m->xref_table.initialized()) { 1738 if (m->xref_table.type(og) || !m->xref_table.initialized()) {
1739 - return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object; 1739 + return m->objects.obj_cache.insert({og, QPDF_Unresolved::create(this, og)})
  1740 + .first->second.object;
1740 } 1741 }
1741 if (parse_pdf) { 1742 if (parse_pdf) {
1742 return QPDF_Null::create(); 1743 return QPDF_Null::create();
1743 } 1744 }
1744 - return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object; 1745 + return m->objects.obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
1745 } 1746 }
1746 1747
1747 std::shared_ptr<QPDFObject> 1748 std::shared_ptr<QPDFObject>
1748 QPDF::getObjectForJSON(int id, int gen) 1749 QPDF::getObjectForJSON(int id, int gen)
1749 { 1750 {
1750 auto og = QPDFObjGen(id, gen); 1751 auto og = QPDFObjGen(id, gen);
1751 - auto [it, inserted] = m->obj_cache.try_emplace(og); 1752 + auto [it, inserted] = m->objects.obj_cache.try_emplace(og);
1752 auto& obj = it->second.object; 1753 auto& obj = it->second.object;
1753 if (inserted) { 1754 if (inserted) {
1754 obj = (m->xref_table.initialized() && !m->xref_table.type(og)) 1755 obj = (m->xref_table.initialized() && !m->xref_table.type(og))
@@ -1771,11 +1772,11 @@ QPDF::replaceObject(QPDFObjGen const&amp; og, QPDFObjectHandle oh) @@ -1771,11 +1772,11 @@ QPDF::replaceObject(QPDFObjGen const&amp; og, QPDFObjectHandle oh)
1771 void 1772 void
1772 QPDF::removeObject(QPDFObjGen og) 1773 QPDF::removeObject(QPDFObjGen og)
1773 { 1774 {
1774 - if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) { 1775 + if (auto cached = m->objects.obj_cache.find(og); cached != m->objects.obj_cache.end()) {
1775 // Take care of any object handles that may be floating around. 1776 // Take care of any object handles that may be floating around.
1776 cached->second.object->assign(QPDF_Null::create()); 1777 cached->second.object->assign(QPDF_Null::create());
1777 cached->second.object->setObjGen(nullptr, QPDFObjGen()); 1778 cached->second.object->setObjGen(nullptr, QPDFObjGen());
1778 - m->obj_cache.erase(cached); 1779 + m->objects.obj_cache.erase(cached);
1779 } 1780 }
1780 } 1781 }
1781 1782
@@ -1785,7 +1786,7 @@ QPDF::swapObjects(QPDFObjGen const&amp; og1, QPDFObjGen const&amp; og2) @@ -1785,7 +1786,7 @@ QPDF::swapObjects(QPDFObjGen const&amp; og1, QPDFObjGen const&amp; og2)
1785 // Force objects to be read from the input source if needed, then swap them in the cache. 1786 // Force objects to be read from the input source if needed, then swap them in the cache.
1786 resolve(og1); 1787 resolve(og1);
1787 resolve(og2); 1788 resolve(og2);
1788 - m->obj_cache[og1].object->swapWith(m->obj_cache[og2].object); 1789 + m->objects.obj_cache[og1].object->swapWith(m->objects.obj_cache[og2].object);
1789 } 1790 }
1790 1791
1791 size_t 1792 size_t
@@ -1797,7 +1798,7 @@ QPDF::tableSize() @@ -1797,7 +1798,7 @@ QPDF::tableSize()
1797 if (max_xref > 0) { 1798 if (max_xref > 0) {
1798 --max_xref; 1799 --max_xref;
1799 } 1800 }
1800 - auto max_obj = m->obj_cache.size() ? m->obj_cache.crbegin()->first.getObj() : 0; 1801 + auto max_obj = m->objects.obj_cache.size() ? m->objects.obj_cache.crbegin()->first.getObj() : 0;
1801 auto max_id = std::numeric_limits<int>::max() - 1; 1802 auto max_id = std::numeric_limits<int>::max() - 1;
1802 if (max_obj >= max_id || max_xref >= max_id) { 1803 if (max_obj >= max_id || max_xref >= max_id) {
1803 // Temporary fix. Long-term solution is 1804 // Temporary fix. Long-term solution is
@@ -1805,7 +1806,7 @@ QPDF::tableSize() @@ -1805,7 +1806,7 @@ QPDF::tableSize()
1805 // - xref table and obj cache to protect against insertion of impossibly large obj ids 1806 // - xref table and obj cache to protect against insertion of impossibly large obj ids
1806 stopOnError("Impossibly large object id encountered."); 1807 stopOnError("Impossibly large object id encountered.");
1807 } 1808 }
1808 - if (max_obj < 1.1 * std::max(toI(m->obj_cache.size()), max_xref)) { 1809 + if (max_obj < 1.1 * std::max(toI(m->objects.obj_cache.size()), max_xref)) {
1809 return toS(++max_obj); 1810 return toS(++max_obj);
1810 } 1811 }
1811 return toS(++max_xref); 1812 return toS(++max_xref);
@@ -1844,7 +1845,7 @@ QPDF::getCompressibleObjGens() @@ -1844,7 +1845,7 @@ QPDF::getCompressibleObjGens()
1844 queue.push_back(m->xref_table.trailer()); 1845 queue.push_back(m->xref_table.trailer());
1845 std::vector<T> result; 1846 std::vector<T> result;
1846 if constexpr (std::is_same_v<T, QPDFObjGen>) { 1847 if constexpr (std::is_same_v<T, QPDFObjGen>) {
1847 - result.reserve(m->obj_cache.size()); 1848 + result.reserve(m->objects.obj_cache.size());
1848 } else if constexpr (std::is_same_v<T, bool>) { 1849 } else if constexpr (std::is_same_v<T, bool>) {
1849 result.resize(max_obj + 1U, false); 1850 result.resize(max_obj + 1U, false);
1850 } else { 1851 } else {
@@ -1868,8 +1869,8 @@ QPDF::getCompressibleObjGens() @@ -1868,8 +1869,8 @@ QPDF::getCompressibleObjGens()
1868 // Check whether this is the current object. If not, remove it (which changes it into a 1869 // Check whether this is the current object. If not, remove it (which changes it into a
1869 // direct null and therefore stops us from revisiting it) and move on to the next object 1870 // direct null and therefore stops us from revisiting it) and move on to the next object
1870 // in the queue. 1871 // in the queue.
1871 - auto upper = m->obj_cache.upper_bound(og);  
1872 - if (upper != m->obj_cache.end() && upper->first.getObj() == og.getObj()) { 1872 + auto upper = m->objects.obj_cache.upper_bound(og);
  1873 + if (upper != m->objects.obj_cache.end() && upper->first.getObj() == og.getObj()) {
1873 removeObject(og); 1874 removeObject(og);
1874 continue; 1875 continue;
1875 } 1876 }
libqpdf/qpdf/QPDF_objects.hh 0 → 100644
  1 +#ifndef QPDF_OBJECTS_HH
  2 +#define QPDF_OBJECTS_HH
  3 +
  4 +#include <qpdf/QPDF.hh>
  5 +
  6 +// The Objects class is responsible for keeping track of all objects belonging to a QPDF instance,
  7 +// including loading it from an input source when required.
  8 +class QPDF::Objects
  9 +{
  10 + public:
  11 + Objects(QPDF& qpdf, QPDF::Members* m)
  12 + {
  13 + }
  14 +
  15 + std::map<QPDFObjGen, ObjCache> obj_cache;
  16 +}; // Objects
  17 +
  18 +#endif // QPDF_OBJECTS_HH
libqpdf/qpdf/QPDF_private.hh
@@ -3,13 +3,15 @@ @@ -3,13 +3,15 @@
3 3
4 #include <qpdf/QPDF.hh> 4 #include <qpdf/QPDF.hh>
5 5
  6 +#include <qpdf/QPDF_objects.hh>
  7 +
6 #include <variant> 8 #include <variant>
7 9
8 // Xref_table encapsulates the pdf's xref table and trailer. 10 // Xref_table encapsulates the pdf's xref table and trailer.
9 class QPDF::Xref_table 11 class QPDF::Xref_table
10 { 12 {
11 public: 13 public:
12 - Xref_table(QPDF& qpdf, InputSource* const& file) : 14 + Xref_table(QPDF& qpdf, QPDF::Objects& objects, InputSource* const& file) :
13 qpdf(qpdf), 15 qpdf(qpdf),
14 file(file) 16 file(file)
15 { 17 {
@@ -750,8 +752,8 @@ class QPDF::Members @@ -750,8 +752,8 @@ class QPDF::Members
750 bool check_mode{false}; 752 bool check_mode{false};
751 std::shared_ptr<EncryptionParameters> encp; 753 std::shared_ptr<EncryptionParameters> encp;
752 std::string pdf_version; 754 std::string pdf_version;
  755 + Objects objects;
753 Xref_table xref_table; 756 Xref_table xref_table;
754 - std::map<QPDFObjGen, ObjCache> obj_cache;  
755 std::set<QPDFObjGen> resolving; 757 std::set<QPDFObjGen> resolving;
756 std::vector<QPDFObjectHandle> all_pages; 758 std::vector<QPDFObjectHandle> all_pages;
757 bool invalid_page_found{false}; 759 bool invalid_page_found{false};
@@ -800,6 +802,12 @@ class QPDF::Members @@ -800,6 +802,12 @@ class QPDF::Members
800 std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users; 802 std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
801 }; 803 };
802 804
  805 +inline QPDF::Objects&
  806 +QPDF::objects()
  807 +{
  808 + return m->objects;
  809 +}
  810 +
803 // JobSetter class is restricted to QPDFJob. 811 // JobSetter class is restricted to QPDFJob.
804 class QPDF::JobSetter 812 class QPDF::JobSetter
805 { 813 {