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:
parent
83897e8789
commit
2015f71c7d
@ -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);
|
||||
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
18
libqpdf/qpdf/QPDF_objects.hh
Normal file
18
libqpdf/qpdf/QPDF_objects.hh
Normal 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
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user