mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 02:49:00 +00:00
Refactor Xref_table::Entry
Replace QPDFXRefEntry with a std::variant of structs.
This commit is contained in:
parent
6b9eb14c76
commit
a1b646fcca
@ -574,7 +574,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
|
||||
|
||||
// Delete all references to type 1 (uncompressed) objects
|
||||
for (auto& iter: table) {
|
||||
if (iter.entry.getType() == 1) {
|
||||
if (iter.type() == 1) {
|
||||
iter = {};
|
||||
}
|
||||
}
|
||||
@ -638,12 +638,12 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
|
||||
qpdf_offset_t max_offset{0};
|
||||
// If there are any xref streams, take the last one to appear.
|
||||
int i = -1;
|
||||
for (auto const& [gen, entry]: table) {
|
||||
for (auto const& item: table) {
|
||||
++i;
|
||||
if (entry.getType() != 1) {
|
||||
if (item.type() != 1) {
|
||||
continue;
|
||||
}
|
||||
auto oh = qpdf.getObject(i, gen);
|
||||
auto oh = qpdf.getObject(i, item.gen());
|
||||
try {
|
||||
if (!oh.isStreamOfType("/XRef")) {
|
||||
continue;
|
||||
@ -651,7 +651,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
|
||||
} catch (std::exception&) {
|
||||
continue;
|
||||
}
|
||||
auto offset = entry.getOffset();
|
||||
auto offset = item.offset();
|
||||
if (offset > max_offset) {
|
||||
max_offset = offset;
|
||||
trailer_ = oh.getDict();
|
||||
@ -1334,9 +1334,9 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
|
||||
}
|
||||
|
||||
auto& entry = table[static_cast<size_t>(obj)];
|
||||
auto old_type = entry.entry.getType();
|
||||
auto old_type = entry.type();
|
||||
|
||||
if (!old_type && entry.gen > 0) {
|
||||
if (!old_type && entry.gen() > 0) {
|
||||
// At the moment we are processing the updates last to first and therefore the gen doesn't
|
||||
// matter as long as it > 0 to distinguish it from an uninitialized entry. This will need
|
||||
// to be revisited when we want to support incremental updates or more comprhensive
|
||||
@ -1351,7 +1351,7 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
|
||||
return;
|
||||
}
|
||||
|
||||
if (old_type && entry.gen >= new_gen) {
|
||||
if (old_type && entry.gen() >= new_gen) {
|
||||
QTC::TC("qpdf", "QPDF xref reused object");
|
||||
return;
|
||||
}
|
||||
@ -1360,11 +1360,11 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
|
||||
case 1:
|
||||
// f2 is generation
|
||||
QTC::TC("qpdf", "QPDF xref gen > 0", (f2 > 0) ? 1 : 0);
|
||||
entry = {f2, QPDFXRefEntry(f1)};
|
||||
entry = {f2, Uncompressed(f1)};
|
||||
break;
|
||||
|
||||
case 2:
|
||||
entry = {0, QPDFXRefEntry(toI(f1), f2)};
|
||||
entry = {0, Compressed(toI(f1), f2)};
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1400,19 +1400,18 @@ QPDF::Xref_table::show()
|
||||
{
|
||||
auto& cout = *qpdf.m->log->getInfo();
|
||||
int i = -1;
|
||||
for (auto const& [gen, entry]: table) {
|
||||
for (auto const& item: table) {
|
||||
++i;
|
||||
auto type = entry.getType();
|
||||
if (type) {
|
||||
cout << std::to_string(i) << "/" << std::to_string(gen) << ": ";
|
||||
switch (type) {
|
||||
if (item.type()) {
|
||||
cout << std::to_string(i) << "/" << std::to_string(item.gen()) << ": ";
|
||||
switch (item.type()) {
|
||||
case 1:
|
||||
cout << "uncompressed; offset = " << entry.getOffset() << "\n";
|
||||
cout << "uncompressed; offset = " << item.offset() << "\n";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
cout << "compressed; stream = " << entry.getObjStreamNumber()
|
||||
<< ", index = " << entry.getObjStreamIndex() << "\n";
|
||||
cout << "compressed; stream = " << item.stream_number()
|
||||
<< ", index = " << item.stream_index() << "\n";
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1430,11 +1429,11 @@ QPDF::Xref_table::resolve()
|
||||
{
|
||||
bool may_change = !reconstructed_;
|
||||
int i = -1;
|
||||
for (auto& iter: table) {
|
||||
for (auto& item: table) {
|
||||
++i;
|
||||
if (iter.entry.getType()) {
|
||||
if (qpdf.isUnresolved(QPDFObjGen(i, iter.gen))) {
|
||||
qpdf.resolve(QPDFObjGen(i, iter.gen));
|
||||
if (item.type()) {
|
||||
if (qpdf.isUnresolved(QPDFObjGen(i, item.gen()))) {
|
||||
qpdf.resolve(QPDFObjGen(i, item.gen()));
|
||||
if (may_change && reconstructed_) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <qpdf/QPDF.hh>
|
||||
|
||||
#include <variant>
|
||||
|
||||
// Xref_table encapsulates the pdf's xref table and trailer.
|
||||
class QPDF::Xref_table
|
||||
{
|
||||
@ -34,54 +36,55 @@ class QPDF::Xref_table
|
||||
}
|
||||
|
||||
// Returns 0 if og is not in table.
|
||||
int
|
||||
size_t
|
||||
type(QPDFObjGen og) const
|
||||
{
|
||||
if (og.getObj() >= toI(table.size())) {
|
||||
int id = og.getObj();
|
||||
if (id < 1 || static_cast<size_t>(id) >= table.size()) {
|
||||
return 0;
|
||||
}
|
||||
auto& e = table.at(toS(og.getObj()));
|
||||
return e.gen == og.getGen() ? e.entry.getType() : 0;
|
||||
auto& e = table[static_cast<size_t>(id)];
|
||||
return e.gen() == og.getGen() ? e.type() : 0;
|
||||
}
|
||||
|
||||
// Returns 0 if og is not in table.
|
||||
int
|
||||
type(size_t id) const
|
||||
size_t
|
||||
type(size_t id) const noexcept
|
||||
{
|
||||
if (id >= table.size()) {
|
||||
return 0;
|
||||
}
|
||||
return table[id].entry.getType();
|
||||
return table[id].type();
|
||||
}
|
||||
|
||||
// Returns 0 if og is not in table.
|
||||
qpdf_offset_t
|
||||
offset(QPDFObjGen og) const
|
||||
offset(QPDFObjGen og) const noexcept
|
||||
{
|
||||
if (og.getObj() >= toI(table.size())) {
|
||||
int id = og.getObj();
|
||||
if (id < 1 || static_cast<size_t>(id) >= table.size()) {
|
||||
return 0;
|
||||
}
|
||||
auto& e = table.at(toS(og.getObj()));
|
||||
return e.gen == og.getGen() ? e.entry.getOffset() : 0;
|
||||
return table[static_cast<size_t>(id)].offset();
|
||||
}
|
||||
|
||||
// Returns 0 if og is not in table.
|
||||
// Returns 0 if id is not in table.
|
||||
int
|
||||
stream_number(int id) const
|
||||
stream_number(int id) const noexcept
|
||||
{
|
||||
if (id < 1 || static_cast<size_t>(id) >= table.size()) {
|
||||
return 0;
|
||||
}
|
||||
return table[static_cast<size_t>(id)].entry.getObjStreamNumber();
|
||||
return table[static_cast<size_t>(id)].stream_number();
|
||||
}
|
||||
|
||||
int
|
||||
stream_index(int id) const
|
||||
stream_index(int id) const noexcept
|
||||
{
|
||||
if (id < 1 || static_cast<size_t>(id) >= table.size()) {
|
||||
return 0;
|
||||
}
|
||||
return table[static_cast<size_t>(id)].entry.getObjStreamIndex();
|
||||
return table[static_cast<size_t>(id)].stream_index();
|
||||
}
|
||||
|
||||
// Temporary access to underlying map
|
||||
@ -90,9 +93,19 @@ class QPDF::Xref_table
|
||||
{
|
||||
std::map<QPDFObjGen, QPDFXRefEntry> result;
|
||||
int i{0};
|
||||
for (auto const& [gen, entry]: table) {
|
||||
if (entry.getType()) {
|
||||
result.emplace(QPDFObjGen(i, gen), entry);
|
||||
for (auto const& item: table) {
|
||||
switch (item.type()) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
result.emplace(QPDFObjGen(i, item.gen()), item.offset());
|
||||
break;
|
||||
case 2:
|
||||
result.emplace(
|
||||
QPDFObjGen(i, 0), QPDFXRefEntry(item.stream_number(), item.stream_index()));
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("Xref_table: invalid entry type");
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@ -149,10 +162,62 @@ class QPDF::Xref_table
|
||||
// Object, count, offset of first entry
|
||||
typedef std::tuple<int, int, qpdf_offset_t> Subsection;
|
||||
|
||||
struct Uncompressed
|
||||
{
|
||||
Uncompressed(qpdf_offset_t offset) :
|
||||
offset(offset)
|
||||
{
|
||||
}
|
||||
qpdf_offset_t offset;
|
||||
};
|
||||
|
||||
struct Compressed
|
||||
{
|
||||
Compressed(int stream_number, int stream_index) :
|
||||
stream_number(stream_number),
|
||||
stream_index(stream_index)
|
||||
{
|
||||
}
|
||||
int stream_number{0};
|
||||
int stream_index{0};
|
||||
};
|
||||
|
||||
typedef std::variant<std::monostate, Uncompressed, Compressed> Xref;
|
||||
|
||||
struct Entry
|
||||
{
|
||||
int gen{0};
|
||||
QPDFXRefEntry entry;
|
||||
int
|
||||
gen() const noexcept
|
||||
{
|
||||
return gen_;
|
||||
}
|
||||
|
||||
size_t
|
||||
type() const noexcept
|
||||
{
|
||||
return entry.index();
|
||||
}
|
||||
|
||||
qpdf_offset_t
|
||||
offset() const noexcept
|
||||
{
|
||||
return type() == 1 ? std::get<1>(entry).offset : 0;
|
||||
}
|
||||
|
||||
int
|
||||
stream_number() const noexcept
|
||||
{
|
||||
return type() == 2 ? std::get<2>(entry).stream_number : 0;
|
||||
}
|
||||
|
||||
int
|
||||
stream_index() const noexcept
|
||||
{
|
||||
return type() == 2 ? std::get<2>(entry).stream_index : 0;
|
||||
}
|
||||
|
||||
int gen_{0};
|
||||
Xref entry;
|
||||
};
|
||||
|
||||
void read(qpdf_offset_t offset);
|
||||
|
Loading…
Reference in New Issue
Block a user