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 Writer;
|
||||||
class Resolver;
|
class Resolver;
|
||||||
class StreamCopier;
|
class StreamCopier;
|
||||||
|
class Objects;
|
||||||
class ParseGuard;
|
class ParseGuard;
|
||||||
class Pipe;
|
class Pipe;
|
||||||
class JobSetter;
|
class JobSetter;
|
||||||
@ -757,6 +758,7 @@ class QPDF
|
|||||||
class ResolveRecorder;
|
class ResolveRecorder;
|
||||||
class JSONReactor;
|
class JSONReactor;
|
||||||
|
|
||||||
|
inline Objects& objects();
|
||||||
void parse(char const* password);
|
void parse(char const* password);
|
||||||
void inParse(bool);
|
void inParse(bool);
|
||||||
void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
|
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_sp(new InvalidInputSource(no_input_name)),
|
||||||
file(file_sp.get()),
|
file(file_sp.get()),
|
||||||
encp(new EncryptionParameters),
|
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 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.
|
// 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();
|
iter.second.object->disconnect();
|
||||||
if (iter.second.object->getTypeCode() != ::ot_null) {
|
if (iter.second.object->getTypeCode() != ::ot_null) {
|
||||||
iter.second.object->destroy();
|
iter.second.object->destroy();
|
||||||
@ -494,8 +495,8 @@ QPDF::getObjectCount()
|
|||||||
// be in obj_cache.
|
// be in obj_cache.
|
||||||
fixDanglingReferences();
|
fixDanglingReferences();
|
||||||
QPDFObjGen og;
|
QPDFObjGen og;
|
||||||
if (!m->obj_cache.empty()) {
|
if (!m->objects.obj_cache.empty()) {
|
||||||
og = (*(m->obj_cache.rbegin())).first;
|
og = (*(m->objects.obj_cache.rbegin())).first;
|
||||||
}
|
}
|
||||||
return toS(og.getObj());
|
return toS(og.getObj());
|
||||||
}
|
}
|
||||||
@ -575,12 +576,12 @@ QPDF::newStream(std::string const& data)
|
|||||||
QPDFObjectHandle
|
QPDFObjectHandle
|
||||||
QPDF::getObject(QPDFObjGen const& og)
|
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};
|
return {it->second.object};
|
||||||
} else if (m->xref_table.initialized() && !m->xref_table.type(og)) {
|
} else if (m->xref_table.initialized() && !m->xref_table.type(og)) {
|
||||||
return QPDF_Null::create();
|
return QPDF_Null::create();
|
||||||
} else {
|
} 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};
|
return {result.first->second.object};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1152,7 @@ QPDF::getAllObjects()
|
|||||||
// After fixDanglingReferences is called, all objects are in the object cache.
|
// After fixDanglingReferences is called, all objects are in the object cache.
|
||||||
fixDanglingReferences();
|
fixDanglingReferences();
|
||||||
std::vector<QPDFObjectHandle> result;
|
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));
|
result.push_back(newIndirect(iter.first, iter.second.object));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -1537,7 +1537,7 @@ QPDFObject*
|
|||||||
QPDF::resolve(QPDFObjGen og)
|
QPDF::resolve(QPDFObjGen og)
|
||||||
{
|
{
|
||||||
if (!isUnresolved(og)) {
|
if (!isUnresolved(og)) {
|
||||||
return m->obj_cache[og].object.get();
|
return m->objects.obj_cache[og].object.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->resolving.count(og)) {
|
if (m->resolving.count(og)) {
|
||||||
@ -1546,7 +1546,7 @@ QPDF::resolve(QPDFObjGen og)
|
|||||||
QTC::TC("qpdf", "QPDF recursion loop in resolve");
|
QTC::TC("qpdf", "QPDF recursion loop in resolve");
|
||||||
warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
|
warn(damagedPDF("", "loop detected resolving object " + og.unparse(' ')));
|
||||||
updateCache(og, QPDF_Null::create());
|
updateCache(og, QPDF_Null::create());
|
||||||
return m->obj_cache[og].object.get();
|
return m->objects.obj_cache[og].object.get();
|
||||||
}
|
}
|
||||||
ResolveRecorder rr(this, og);
|
ResolveRecorder rr(this, og);
|
||||||
|
|
||||||
@ -1584,7 +1584,7 @@ QPDF::resolve(QPDFObjGen og)
|
|||||||
updateCache(og, QPDF_Null::create());
|
updateCache(og, QPDF_Null::create());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result(m->obj_cache[og].object);
|
auto result(m->objects.obj_cache[og].object);
|
||||||
result->setDefaultDescription(this, og);
|
result->setDefaultDescription(this, og);
|
||||||
return result.get();
|
return result.get();
|
||||||
}
|
}
|
||||||
@ -1690,23 +1690,23 @@ QPDF::updateCache(QPDFObjGen const& og, std::shared_ptr<QPDFObject> const& objec
|
|||||||
{
|
{
|
||||||
object->setObjGen(this, og);
|
object->setObjGen(this, og);
|
||||||
if (isCached(og)) {
|
if (isCached(og)) {
|
||||||
auto& cache = m->obj_cache[og];
|
auto& cache = m->objects.obj_cache[og];
|
||||||
cache.object->assign(object);
|
cache.object->assign(object);
|
||||||
} else {
|
} else {
|
||||||
m->obj_cache[og] = ObjCache(object);
|
m->objects.obj_cache[og] = ObjCache(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
QPDF::isCached(QPDFObjGen const& og)
|
QPDF::isCached(QPDFObjGen const& og)
|
||||||
{
|
{
|
||||||
return m->obj_cache.count(og) != 0;
|
return m->objects.obj_cache.count(og) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
QPDF::isUnresolved(QPDFObjGen const& og)
|
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
|
QPDFObjGen
|
||||||
@ -1723,8 +1723,8 @@ QPDFObjectHandle
|
|||||||
QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
|
QPDF::makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj)
|
||||||
{
|
{
|
||||||
QPDFObjGen next{nextObjGen()};
|
QPDFObjGen next{nextObjGen()};
|
||||||
m->obj_cache[next] = ObjCache(obj);
|
m->objects.obj_cache[next] = ObjCache(obj);
|
||||||
return newIndirect(next, m->obj_cache[next].object);
|
return newIndirect(next, m->objects.obj_cache[next].object);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<QPDFObject>
|
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.
|
// This method is called by the parser and therefore must not resolve any objects.
|
||||||
auto og = QPDFObjGen(id, gen);
|
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;
|
return iter->second.object;
|
||||||
}
|
}
|
||||||
if (m->xref_table.type(og) || !m->xref_table.initialized()) {
|
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) {
|
if (parse_pdf) {
|
||||||
return QPDF_Null::create();
|
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>
|
std::shared_ptr<QPDFObject>
|
||||||
QPDF::getObjectForJSON(int id, int gen)
|
QPDF::getObjectForJSON(int id, int gen)
|
||||||
{
|
{
|
||||||
auto og = QPDFObjGen(id, 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;
|
auto& obj = it->second.object;
|
||||||
if (inserted) {
|
if (inserted) {
|
||||||
obj = (m->xref_table.initialized() && !m->xref_table.type(og))
|
obj = (m->xref_table.initialized() && !m->xref_table.type(og))
|
||||||
@ -1771,11 +1772,11 @@ QPDF::replaceObject(QPDFObjGen const& og, QPDFObjectHandle oh)
|
|||||||
void
|
void
|
||||||
QPDF::removeObject(QPDFObjGen og)
|
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.
|
// Take care of any object handles that may be floating around.
|
||||||
cached->second.object->assign(QPDF_Null::create());
|
cached->second.object->assign(QPDF_Null::create());
|
||||||
cached->second.object->setObjGen(nullptr, QPDFObjGen());
|
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.
|
// Force objects to be read from the input source if needed, then swap them in the cache.
|
||||||
resolve(og1);
|
resolve(og1);
|
||||||
resolve(og2);
|
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
|
size_t
|
||||||
@ -1797,7 +1798,7 @@ QPDF::tableSize()
|
|||||||
if (max_xref > 0) {
|
if (max_xref > 0) {
|
||||||
--max_xref;
|
--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;
|
auto max_id = std::numeric_limits<int>::max() - 1;
|
||||||
if (max_obj >= max_id || max_xref >= max_id) {
|
if (max_obj >= max_id || max_xref >= max_id) {
|
||||||
// Temporary fix. Long-term solution is
|
// 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
|
// - xref table and obj cache to protect against insertion of impossibly large obj ids
|
||||||
stopOnError("Impossibly large object id encountered.");
|
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_obj);
|
||||||
}
|
}
|
||||||
return toS(++max_xref);
|
return toS(++max_xref);
|
||||||
@ -1844,7 +1845,7 @@ QPDF::getCompressibleObjGens()
|
|||||||
queue.push_back(m->xref_table.trailer());
|
queue.push_back(m->xref_table.trailer());
|
||||||
std::vector<T> result;
|
std::vector<T> result;
|
||||||
if constexpr (std::is_same_v<T, QPDFObjGen>) {
|
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>) {
|
} else if constexpr (std::is_same_v<T, bool>) {
|
||||||
result.resize(max_obj + 1U, false);
|
result.resize(max_obj + 1U, false);
|
||||||
} else {
|
} else {
|
||||||
@ -1868,8 +1869,8 @@ QPDF::getCompressibleObjGens()
|
|||||||
// Check whether this is the current object. If not, remove it (which changes it into a
|
// 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
|
// direct null and therefore stops us from revisiting it) and move on to the next object
|
||||||
// in the queue.
|
// in the queue.
|
||||||
auto upper = m->obj_cache.upper_bound(og);
|
auto upper = m->objects.obj_cache.upper_bound(og);
|
||||||
if (upper != m->obj_cache.end() && upper->first.getObj() == og.getObj()) {
|
if (upper != m->objects.obj_cache.end() && upper->first.getObj() == og.getObj()) {
|
||||||
removeObject(og);
|
removeObject(og);
|
||||||
continue;
|
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.hh>
|
||||||
|
|
||||||
|
#include <qpdf/QPDF_objects.hh>
|
||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
// Xref_table encapsulates the pdf's xref table and trailer.
|
// Xref_table encapsulates the pdf's xref table and trailer.
|
||||||
class QPDF::Xref_table
|
class QPDF::Xref_table
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Xref_table(QPDF& qpdf, InputSource* const& file) :
|
Xref_table(QPDF& qpdf, QPDF::Objects& objects, InputSource* const& file) :
|
||||||
qpdf(qpdf),
|
qpdf(qpdf),
|
||||||
file(file)
|
file(file)
|
||||||
{
|
{
|
||||||
@ -750,8 +752,8 @@ class QPDF::Members
|
|||||||
bool check_mode{false};
|
bool check_mode{false};
|
||||||
std::shared_ptr<EncryptionParameters> encp;
|
std::shared_ptr<EncryptionParameters> encp;
|
||||||
std::string pdf_version;
|
std::string pdf_version;
|
||||||
|
Objects objects;
|
||||||
Xref_table xref_table;
|
Xref_table xref_table;
|
||||||
std::map<QPDFObjGen, ObjCache> obj_cache;
|
|
||||||
std::set<QPDFObjGen> resolving;
|
std::set<QPDFObjGen> resolving;
|
||||||
std::vector<QPDFObjectHandle> all_pages;
|
std::vector<QPDFObjectHandle> all_pages;
|
||||||
bool invalid_page_found{false};
|
bool invalid_page_found{false};
|
||||||
@ -800,6 +802,12 @@ class QPDF::Members
|
|||||||
std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
|
std::map<QPDFObjGen, std::set<ObjUser>> object_to_obj_users;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline QPDF::Objects&
|
||||||
|
QPDF::objects()
|
||||||
|
{
|
||||||
|
return m->objects;
|
||||||
|
}
|
||||||
|
|
||||||
// JobSetter class is restricted to QPDFJob.
|
// JobSetter class is restricted to QPDFJob.
|
||||||
class QPDF::JobSetter
|
class QPDF::JobSetter
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user