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

Move QPDF::insertXrefEntry etc to QPDF::Xref_table

This commit is contained in:
m-holger 2024-08-09 14:14:56 +01:00
parent 0ac37bc956
commit 1e072e223a
3 changed files with 37 additions and 25 deletions

View File

@ -777,9 +777,6 @@ class QPDF
QPDFObjectHandle& dict, QPDFObjectHandle& dict,
int max_num_entries, int max_num_entries,
std::function<QPDFExc(std::string_view)> damaged); std::function<QPDFExc(std::string_view)> damaged);
void insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2);
void insertFreeXrefEntry(QPDFObjGen);
void insertReconstructedXrefEntry(int obj, qpdf_offset_t f1, int f2);
void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); void setLastObjectDescription(std::string const& description, QPDFObjGen const& og);
QPDFObjectHandle readTrailer(); QPDFObjectHandle readTrailer();
QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og); QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og);

View File

@ -196,15 +196,16 @@ QPDF::EncryptionParameters::EncryptionParameters() :
{ {
} }
QPDF::Members::Members() : QPDF::Members::Members(QPDF& qpdf) :
log(QPDFLogger::defaultLogger()), log(QPDFLogger::defaultLogger()),
file(new InvalidInputSource()), file(new InvalidInputSource()),
encp(new EncryptionParameters) encp(new EncryptionParameters),
xref_table(qpdf)
{ {
} }
QPDF::QPDF() : QPDF::QPDF() :
m(new Members()) m(new Members(*this))
{ {
m->tokenizer.allowEOF(); m->tokenizer.allowEOF();
// Generate a unique ID. It just has to be unique among all QPDF objects allocated throughout // Generate a unique ID. It just has to be unique among all QPDF objects allocated throughout
@ -585,7 +586,7 @@ QPDF::reconstruct_xref(QPDFExc& e)
int obj = QUtil::string_to_int(t1.getValue().c_str()); int obj = QUtil::string_to_int(t1.getValue().c_str());
int gen = QUtil::string_to_int(t2.getValue().c_str()); int gen = QUtil::string_to_int(t2.getValue().c_str());
if (obj <= m->xref_table.max_id) { if (obj <= m->xref_table.max_id) {
insertReconstructedXrefEntry(obj, token_start, gen); m->xref_table.insert_reconstructed(obj, token_start, gen);
} else { } else {
warn(damagedPDF( warn(damagedPDF(
"", 0, "ignoring object with impossibly large id " + std::to_string(obj))); "", 0, "ignoring object with impossibly large id " + std::to_string(obj)));
@ -981,9 +982,9 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
"xref table", "invalid xref entry (obj=" + std::to_string(i) + ")"); "xref table", "invalid xref entry (obj=" + std::to_string(i) + ")");
} }
if (type == 'f') { if (type == 'f') {
insertFreeXrefEntry(QPDFObjGen(toI(i), f2)); m->xref_table.insert_free(QPDFObjGen(toI(i), f2));
} else { } else {
insertXrefEntry(toI(i), 1, f1, f2); m->xref_table.insert(toI(i), 1, f1, f2);
} }
} }
qpdf_offset_t pos = m->file->tell(); qpdf_offset_t pos = m->file->tell();
@ -1251,9 +1252,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
// Ignore fields[2], which we don't care about in this case. This works around the // Ignore fields[2], which we don't care about in this case. This works around the
// issue of some PDF files that put invalid values, like -1, here for deleted // issue of some PDF files that put invalid values, like -1, here for deleted
// objects. // objects.
insertFreeXrefEntry(QPDFObjGen(obj, 0)); m->xref_table.insert_free(QPDFObjGen(obj, 0));
} else { } else {
insertXrefEntry(obj, toI(fields[0]), fields[1], toI(fields[2])); m->xref_table.insert(obj, toI(fields[0]), fields[1], toI(fields[2]));
} }
++obj; ++obj;
} }
@ -1276,7 +1277,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
} }
void void
QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2) QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
{ {
// Populate the xref table in such a way that the first reference to an object that we see, // Populate the xref table in such a way that the first reference to an object that we see,
// which is the one in the latest xref table in which it appears, is the one that gets stored. // which is the one in the latest xref table in which it appears, is the one that gets stored.
@ -1285,22 +1286,23 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2)
// If there is already an entry for this object and generation in the table, it means that a // If there is already an entry for this object and generation in the table, it means that a
// later xref table has registered this object. Disregard this one. // later xref table has registered this object. Disregard this one.
if (obj > m->xref_table.max_id) { if (obj > max_id) {
// ignore impossibly large object ids or object ids > Size. // ignore impossibly large object ids or object ids > Size.
return; return;
} }
if (m->xref_table.deleted_objects.count(obj)) { if (deleted_objects.count(obj)) {
QTC::TC("qpdf", "QPDF xref deleted object"); QTC::TC("qpdf", "QPDF xref deleted object");
return; return;
} }
if (f0 == 2 && static_cast<int>(f1) == obj) { if (f0 == 2 && static_cast<int>(f1) == obj) {
warn(damagedPDF("xref stream", "self-referential object stream " + std::to_string(obj))); qpdf.warn(qpdf.damagedPDF(
"xref stream", "self-referential object stream " + std::to_string(obj)));
return; return;
} }
auto [iter, created] = m->xref_table.try_emplace(QPDFObjGen(obj, (f0 == 2 ? 0 : f2))); auto [iter, created] = try_emplace(QPDFObjGen(obj, (f0 == 2 ? 0 : f2)));
if (!created) { if (!created) {
QTC::TC("qpdf", "QPDF xref reused object"); QTC::TC("qpdf", "QPDF xref reused object");
return; return;
@ -1318,35 +1320,36 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2)
break; break;
default: default:
throw damagedPDF("xref stream", "unknown xref stream entry type " + std::to_string(f0)); throw qpdf.damagedPDF(
"xref stream", "unknown xref stream entry type " + std::to_string(f0));
break; break;
} }
} }
void void
QPDF::insertFreeXrefEntry(QPDFObjGen og) QPDF::Xref_table::insert_free(QPDFObjGen og)
{ {
if (!m->xref_table.count(og)) { if (!count(og)) {
m->xref_table.deleted_objects.insert(og.getObj()); deleted_objects.insert(og.getObj());
} }
} }
// Replace uncompressed object. This is used in xref recovery mode, which reads the file from // Replace uncompressed object. This is used in xref recovery mode, which reads the file from
// beginning to end. // beginning to end.
void void
QPDF::insertReconstructedXrefEntry(int obj, qpdf_offset_t f1, int f2) QPDF::Xref_table::insert_reconstructed(int obj, qpdf_offset_t f1, int f2)
{ {
if (!(obj > 0 && obj <= m->xref_table.max_id && 0 <= f2 && f2 < 65535)) { if (!(obj > 0 && obj <= max_id && 0 <= f2 && f2 < 65535)) {
QTC::TC("qpdf", "QPDF xref overwrite invalid objgen"); QTC::TC("qpdf", "QPDF xref overwrite invalid objgen");
return; return;
} }
QPDFObjGen og(obj, f2); QPDFObjGen og(obj, f2);
if (!m->xref_table.deleted_objects.count(obj)) { if (!deleted_objects.count(obj)) {
// deleted_objects stores the uncompressed objects removed from the xref table at the start // deleted_objects stores the uncompressed objects removed from the xref table at the start
// of recovery. // of recovery.
QTC::TC("qpdf", "QPDF xref overwrite object"); QTC::TC("qpdf", "QPDF xref overwrite object");
m->xref_table[QPDFObjGen(obj, f2)] = QPDFXRefEntry(f1); insert_or_assign(QPDFObjGen(obj, f2), QPDFXRefEntry(f1));
} }
} }

View File

@ -7,6 +7,15 @@
class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry>
{ {
public: public:
Xref_table(QPDF& qpdf) :
qpdf(qpdf)
{
}
void insert_reconstructed(int obj, qpdf_offset_t f1, int f2);
void insert(int obj, int f0, qpdf_offset_t f1, int f2);
void insert_free(QPDFObjGen);
QPDFObjectHandle trailer; QPDFObjectHandle trailer;
bool reconstructed{false}; bool reconstructed{false};
// Various tables are indexed by object id, with potential size id + 1 // Various tables are indexed by object id, with potential size id + 1
@ -20,6 +29,9 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry>
// Linearization data // Linearization data
bool uncompressed_after_compressed{false}; bool uncompressed_after_compressed{false};
qpdf_offset_t first_item_offset{0}; // actual value from file qpdf_offset_t first_item_offset{0}; // actual value from file
private:
QPDF& qpdf;
}; };
// Writer class is restricted to QPDFWriter so that only it can call certain methods. // Writer class is restricted to QPDFWriter so that only it can call certain methods.
@ -469,7 +481,7 @@ class QPDF::Members
~Members() = default; ~Members() = default;
private: private:
Members(); Members(QPDF& qpdf);
Members(Members const&) = delete; Members(Members const&) = delete;
std::shared_ptr<QPDFLogger> log; std::shared_ptr<QPDFLogger> log;