2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 02:49:00 +00:00

Add new inner class to QPDF::Objects

This commit is contained in:
m-holger 2024-10-07 10:22:10 +01:00
parent 83897e8789
commit 2015f71c7d
5 changed files with 60 additions and 30 deletions

View File

@ -730,6 +730,7 @@ class QPDF
class Writer;
class Resolver;
class StreamCopier;
class Objects;
class ParseGuard;
class Pipe;
class JobSetter;
@ -757,6 +758,7 @@ class QPDF
class ResolveRecorder;
class JSONReactor;
inline Objects& objects();
void parse(char const* password);
void inParse(bool);
void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);

View File

@ -185,7 +185,8 @@ QPDF::Members::Members(QPDF& qpdf) :
file_sp(new InvalidInputSource(no_input_name)),
file(file_sp.get()),
encp(new EncryptionParameters),
xref_table(qpdf, file)
objects(qpdf, this),
xref_table(qpdf, objects, file)
{
}
@ -211,7 +212,7 @@ QPDF::~QPDF()
// are reachable from this object to release their association with this QPDF. Direct objects
// are not destroyed since they can be moved to other QPDF objects safely.
for (auto const& iter: m->obj_cache) {
for (auto const& iter: m->objects.obj_cache) {
iter.second.object->disconnect();
if (iter.second.object->getTypeCode() != ::ot_null) {
iter.second.object->destroy();
@ -494,8 +495,8 @@ QPDF::getObjectCount()
// be in obj_cache.
fixDanglingReferences();
QPDFObjGen og;
if (!m->obj_cache.empty()) {
og = (*(m->obj_cache.rbegin())).first;
if (!m->objects.obj_cache.empty()) {
og = (*(m->objects.obj_cache.rbegin())).first;
}
return toS(og.getObj());
}
@ -575,12 +576,12 @@ QPDF::newStream(std::string const& data)
QPDFObjectHandle
QPDF::getObject(QPDFObjGen const& og)
{
if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
if (auto it = m->objects.obj_cache.find(og); it != m->objects.obj_cache.end()) {
return {it->second.object};
} else if (m->xref_table.initialized() && !m->xref_table.type(og)) {
return QPDF_Null::create();
} else {
auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og));
auto result = m->objects.obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og));
return {result.first->second.object};
}
}

View File

@ -1152,7 +1152,7 @@ QPDF::getAllObjects()
// After fixDanglingReferences is called, all objects are in the object cache.
fixDanglingReferences();
std::vector<QPDFObjectHandle> result;
for (auto const& iter: m->obj_cache) {
for (auto const& iter: m->objects.obj_cache) {
result.push_back(newIndirect(iter.first, iter.second.object));
}
return result;
@ -1537,7 +1537,7 @@ QPDFObject*
QPDF::resolve(QPDFObjGen og)
{
if (!isUnresolved(og)) {
return m->obj_cache[og].object.get();
return m->objects.obj_cache[og].object.get();
}
if (m->resolving.count(og)) {
@ -1546,7 +1546,7 @@ QPDF::resolve(QPDFObjGen og)
QTC::TC("qpdf", "QPDF recursion loop in resolve");
warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
updateCache(og, QPDF_Null::create());
return m->obj_cache[og].object.get();
return m->objects.obj_cache[og].object.get();
}
ResolveRecorder rr(this, og);
@ -1584,7 +1584,7 @@ QPDF::resolve(QPDFObjGen og)
updateCache(og, QPDF_Null::create());
}
auto result(m->obj_cache[og].object);
auto result(m->objects.obj_cache[og].object);
result->setDefaultDescription(this, og);
return result.get();
}
@ -1690,23 +1690,23 @@ QPDF::updateCache(QPDFObjGen const& og, std::shared_ptr<QPDFObject> const& objec
{
object->setObjGen(this, og);
if (isCached(og)) {
auto& cache = m->obj_cache[og];
auto& cache = m->objects.obj_cache[og];
cache.object->assign(object);
} else {
m->obj_cache[og] = ObjCache(object);
m->objects.obj_cache[og] = ObjCache(object);
}
}
bool
QPDF::isCached(QPDFObjGen const& og)
{
return m->obj_cache.count(og) != 0;
return m->objects.obj_cache.count(og) != 0;
}
bool
QPDF::isUnresolved(QPDFObjGen const& og)
{
return !isCached(og) || m->obj_cache[og].object->isUnresolved();
return !isCached(og) || m->objects.obj_cache[og].object->isUnresolved();
}
QPDFObjGen
@ -1723,8 +1723,8 @@ QPDFObjectHandle
QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
{
QPDFObjGen next{nextObjGen()};
m->obj_cache[next] = ObjCache(obj);
return newIndirect(next, m->obj_cache[next].object);
m->objects.obj_cache[next] = ObjCache(obj);
return newIndirect(next, m->objects.obj_cache[next].object);
}
std::shared_ptr<QPDFObject>
@ -1732,23 +1732,24 @@ QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
{
// This method is called by the parser and therefore must not resolve any objects.
auto og = QPDFObjGen(id, gen);
if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) {
if (auto iter = m->objects.obj_cache.find(og); iter != m->objects.obj_cache.end()) {
return iter->second.object;
}
if (m->xref_table.type(og) || !m->xref_table.initialized()) {
return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
return m->objects.obj_cache.insert({og, QPDF_Unresolved::create(this, og)})
.first->second.object;
}
if (parse_pdf) {
return QPDF_Null::create();
}
return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
return m->objects.obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
}
std::shared_ptr<QPDFObject>
QPDF::getObjectForJSON(int id, int gen)
{
auto og = QPDFObjGen(id, gen);
auto [it, inserted] = m->obj_cache.try_emplace(og);
auto [it, inserted] = m->objects.obj_cache.try_emplace(og);
auto& obj = it->second.object;
if (inserted) {
obj = (m->xref_table.initialized() && !m->xref_table.type(og))
@ -1771,11 +1772,11 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
void
QPDF::removeObject(QPDFObjGen og)
{
if (auto cached = m->obj_cache.find(og); cached != m->obj_cache.end()) {
if (auto cached = m->objects.obj_cache.find(og); cached != m->objects.obj_cache.end()) {
// Take care of any object handles that may be floating around.
cached->second.object->assign(QPDF_Null::create());
cached->second.object->setObjGen(nullptr, QPDFObjGen());
m->obj_cache.erase(cached);
m->objects.obj_cache.erase(cached);
}
}
@ -1785,7 +1786,7 @@ QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2)
// Force objects to be read from the input source if needed, then swap them in the cache.
resolve(og1);
resolve(og2);
m->obj_cache[og1].object->swapWith(m->obj_cache[og2].object);
m->objects.obj_cache[og1].object->swapWith(m->objects.obj_cache[og2].object);
}
size_t
@ -1797,7 +1798,7 @@ QPDF::tableSize()
if (max_xref > 0) {
--max_xref;
}
auto max_obj = m->obj_cache.size() ? m->obj_cache.crbegin()->first.getObj() : 0;
auto max_obj = m->objects.obj_cache.size() ? m->objects.obj_cache.crbegin()->first.getObj() : 0;
auto max_id = std::numeric_limits<int>::max() - 1;
if (max_obj >= max_id || max_xref >= max_id) {
// Temporary fix. Long-term solution is
@ -1805,7 +1806,7 @@ QPDF::tableSize()
// - xref table and obj cache to protect against insertion of impossibly large obj ids
stopOnError("Impossibly large object id encountered.");
}
if (max_obj < 1.1 * std::max(toI(m->obj_cache.size()), max_xref)) {
if (max_obj < 1.1 * std::max(toI(m->objects.obj_cache.size()), max_xref)) {
return toS(++max_obj);
}
return toS(++max_xref);
@ -1844,7 +1845,7 @@ QPDF::getCompressibleObjGens()
queue.push_back(m->xref_table.trailer());
std::vector<T> result;
if constexpr (std::is_same_v<T, QPDFObjGen>) {
result.reserve(m->obj_cache.size());
result.reserve(m->objects.obj_cache.size());
} else if constexpr (std::is_same_v<T, bool>) {
result.resize(max_obj + 1U, false);
} else {
@ -1868,8 +1869,8 @@ QPDF::getCompressibleObjGens()
// Check whether this is the current object. If not, remove it (which changes it into a
// direct null and therefore stops us from revisiting it) and move on to the next object
// in the queue.
auto upper = m->obj_cache.upper_bound(og);
if (upper != m->obj_cache.end() && upper->first.getObj() == og.getObj()) {
auto upper = m->objects.obj_cache.upper_bound(og);
if (upper != m->objects.obj_cache.end() && upper->first.getObj() == og.getObj()) {
removeObject(og);
continue;
}

View File

@ -0,0 +1,18 @@
#ifndef QPDF_OBJECTS_HH
#define QPDF_OBJECTS_HH
#include <qpdf/QPDF.hh>
// The Objects class is responsible for keeping track of all objects belonging to a QPDF instance,
// including loading it from an input source when required.
class QPDF::Objects
{
public:
Objects(QPDF& qpdf, QPDF::Members* m)
{
}
std::map<QPDFObjGen, ObjCache> obj_cache;
}; // Objects
#endif // QPDF_OBJECTS_HH

View File

@ -3,13 +3,15 @@
#include <qpdf/QPDF.hh>
#include <qpdf/QPDF_objects.hh>
#include <variant>
// Xref_table encapsulates the pdf's xref table and trailer.
class QPDF::Xref_table
{
public:
Xref_table(QPDF& qpdf, InputSource* const& file) :
Xref_table(QPDF& qpdf, QPDF::Objects& objects, InputSource* const& file) :
qpdf(qpdf),
file(file)
{
@ -750,8 +752,8 @@ class QPDF::Members
bool check_mode{false};
std::shared_ptr<EncryptionParameters> encp;
std::string pdf_version;
Objects objects;
Xref_table xref_table;
std::map<QPDFObjGen, ObjCache> obj_cache;
std::set<QPDFObjGen> resolving;
std::vector<QPDFObjectHandle> all_pages;
bool invalid_page_found{false};
@ -800,6 +802,12 @@ class QPDF::Members
std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
};
inline QPDF::Objects&
QPDF::objects()
{
return m->objects;
}
// JobSetter class is restricted to QPDFJob.
class QPDF::JobSetter
{