Commit 2015f71c7d6e316db6ae3cd6a9189b8ed8308c04
1 parent
83897e87
Add new inner class to QPDF::Objects
Showing
5 changed files
with
60 additions
and
30 deletions
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& og, std::shared_ptr<QPDFObject> const& 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& 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& og1, QPDFObjGen const& 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 | { | ... | ... |