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 730 class Writer;
731 731 class Resolver;
732 732 class StreamCopier;
  733 + class Objects;
733 734 class ParseGuard;
734 735 class Pipe;
735 736 class JobSetter;
... ... @@ -757,6 +758,7 @@ class QPDF
757 758 class ResolveRecorder;
758 759 class JSONReactor;
759 760  
  761 + inline Objects& objects();
760 762 void parse(char const* password);
761 763 void inParse(bool);
762 764 void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
... ...
libqpdf/QPDF.cc
... ... @@ -185,7 +185,8 @@ QPDF::Members::Members(QPDF& qpdf) :
185 185 file_sp(new InvalidInputSource(no_input_name)),
186 186 file(file_sp.get()),
187 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 212 // are reachable from this object to release their association with this QPDF. Direct objects
212 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 216 iter.second.object->disconnect();
216 217 if (iter.second.object->getTypeCode() != ::ot_null) {
217 218 iter.second.object->destroy();
... ... @@ -494,8 +495,8 @@ QPDF::getObjectCount()
494 495 // be in obj_cache.
495 496 fixDanglingReferences();
496 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 501 return toS(og.getObj());
501 502 }
... ... @@ -575,12 +576,12 @@ QPDF::newStream(std::string const& data)
575 576 QPDFObjectHandle
576 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 580 return {it->second.object};
580 581 } else if (m->xref_table.initialized() && !m->xref_table.type(og)) {
581 582 return QPDF_Null::create();
582 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 585 return {result.first->second.object};
585 586 }
586 587 }
... ...
libqpdf/QPDF_objects.cc
... ... @@ -1152,7 +1152,7 @@ QPDF::getAllObjects()
1152 1152 // After fixDanglingReferences is called, all objects are in the object cache.
1153 1153 fixDanglingReferences();
1154 1154 std::vector<QPDFObjectHandle> result;
1155   - for (auto const& iter: m->obj_cache) {
  1155 + for (auto const& iter: m->objects.obj_cache) {
1156 1156 result.push_back(newIndirect(iter.first, iter.second.object));
1157 1157 }
1158 1158 return result;
... ... @@ -1537,7 +1537,7 @@ QPDFObject*
1537 1537 QPDF::resolve(QPDFObjGen og)
1538 1538 {
1539 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 1543 if (m->resolving.count(og)) {
... ... @@ -1546,7 +1546,7 @@ QPDF::resolve(QPDFObjGen og)
1546 1546 QTC::TC("qpdf", "QPDF recursion loop in resolve");
1547 1547 warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
1548 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 1551 ResolveRecorder rr(this, og);
1552 1552  
... ... @@ -1584,7 +1584,7 @@ QPDF::resolve(QPDFObjGen og)
1584 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 1588 result->setDefaultDescription(this, og);
1589 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 1690 {
1691 1691 object->setObjGen(this, og);
1692 1692 if (isCached(og)) {
1693   - auto& cache = m->obj_cache[og];
  1693 + auto& cache = m->objects.obj_cache[og];
1694 1694 cache.object->assign(object);
1695 1695 } else {
1696   - m->obj_cache[og] = ObjCache(object);
  1696 + m->objects.obj_cache[og] = ObjCache(object);
1697 1697 }
1698 1698 }
1699 1699  
1700 1700 bool
1701 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 1706 bool
1707 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 1712 QPDFObjGen
... ... @@ -1723,8 +1723,8 @@ QPDFObjectHandle
1723 1723 QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
1724 1724 {
1725 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 1730 std::shared_ptr<QPDFObject>
... ... @@ -1732,23 +1732,24 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
1732 1732 {
1733 1733 // This method is called by the parser and therefore must not resolve any objects.
1734 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 1736 return iter->second.object;
1737 1737 }
1738 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 1742 if (parse_pdf) {
1742 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 1748 std::shared_ptr<QPDFObject>
1748 1749 QPDF::getObjectForJSON(int id, int gen)
1749 1750 {
1750 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 1753 auto& obj = it->second.object;
1753 1754 if (inserted) {
1754 1755 obj = (m->xref_table.initialized() && !m->xref_table.type(og))
... ... @@ -1771,11 +1772,11 @@ QPDF::replaceObject(QPDFObjGen const&amp; og, QPDFObjectHandle oh)
1771 1772 void
1772 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 1776 // Take care of any object handles that may be floating around.
1776 1777 cached->second.object->assign(QPDF_Null::create());
1777 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 1786 // Force objects to be read from the input source if needed, then swap them in the cache.
1786 1787 resolve(og1);
1787 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 1792 size_t
... ... @@ -1797,7 +1798,7 @@ QPDF::tableSize()
1797 1798 if (max_xref > 0) {
1798 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 1802 auto max_id = std::numeric_limits<int>::max() - 1;
1802 1803 if (max_obj >= max_id || max_xref >= max_id) {
1803 1804 // Temporary fix. Long-term solution is
... ... @@ -1805,7 +1806,7 @@ QPDF::tableSize()
1805 1806 // - xref table and obj cache to protect against insertion of impossibly large obj ids
1806 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 1810 return toS(++max_obj);
1810 1811 }
1811 1812 return toS(++max_xref);
... ... @@ -1844,7 +1845,7 @@ QPDF::getCompressibleObjGens()
1844 1845 queue.push_back(m->xref_table.trailer());
1845 1846 std::vector<T> result;
1846 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 1849 } else if constexpr (std::is_same_v<T, bool>) {
1849 1850 result.resize(max_obj + 1U, false);
1850 1851 } else {
... ... @@ -1868,8 +1869,8 @@ QPDF::getCompressibleObjGens()
1868 1869 // Check whether this is the current object. If not, remove it (which changes it into a
1869 1870 // direct null and therefore stops us from revisiting it) and move on to the next object
1870 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 1874 removeObject(og);
1874 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 3  
4 4 #include <qpdf/QPDF.hh>
5 5  
  6 +#include <qpdf/QPDF_objects.hh>
  7 +
6 8 #include <variant>
7 9  
8 10 // Xref_table encapsulates the pdf's xref table and trailer.
9 11 class QPDF::Xref_table
10 12 {
11 13 public:
12   - Xref_table(QPDF& qpdf, InputSource* const& file) :
  14 + Xref_table(QPDF& qpdf, QPDF::Objects& objects, InputSource* const& file) :
13 15 qpdf(qpdf),
14 16 file(file)
15 17 {
... ... @@ -750,8 +752,8 @@ class QPDF::Members
750 752 bool check_mode{false};
751 753 std::shared_ptr<EncryptionParameters> encp;
752 754 std::string pdf_version;
  755 + Objects objects;
753 756 Xref_table xref_table;
754   - std::map<QPDFObjGen, ObjCache> obj_cache;
755 757 std::set<QPDFObjGen> resolving;
756 758 std::vector<QPDFObjectHandle> all_pages;
757 759 bool invalid_page_found{false};
... ... @@ -800,6 +802,12 @@ class QPDF::Members
800 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 811 // JobSetter class is restricted to QPDFJob.
804 812 class QPDF::JobSetter
805 813 {
... ...