Commit a1b646fccafbdbc39c78f2bad4c21aa507f0477f

Authored by m-holger
1 parent 6b9eb14c

Refactor Xref_table::Entry

Replace QPDFXRefEntry with a std::variant of structs.
libqpdf/QPDF.cc
... ... @@ -574,7 +574,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
574 574  
575 575 // Delete all references to type 1 (uncompressed) objects
576 576 for (auto& iter: table) {
577   - if (iter.entry.getType() == 1) {
  577 + if (iter.type() == 1) {
578 578 iter = {};
579 579 }
580 580 }
... ... @@ -638,12 +638,12 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
638 638 qpdf_offset_t max_offset{0};
639 639 // If there are any xref streams, take the last one to appear.
640 640 int i = -1;
641   - for (auto const& [gen, entry]: table) {
  641 + for (auto const& item: table) {
642 642 ++i;
643   - if (entry.getType() != 1) {
  643 + if (item.type() != 1) {
644 644 continue;
645 645 }
646   - auto oh = qpdf.getObject(i, gen);
  646 + auto oh = qpdf.getObject(i, item.gen());
647 647 try {
648 648 if (!oh.isStreamOfType("/XRef")) {
649 649 continue;
... ... @@ -651,7 +651,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
651 651 } catch (std::exception&) {
652 652 continue;
653 653 }
654   - auto offset = entry.getOffset();
  654 + auto offset = item.offset();
655 655 if (offset > max_offset) {
656 656 max_offset = offset;
657 657 trailer_ = oh.getDict();
... ... @@ -1334,9 +1334,9 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
1334 1334 }
1335 1335  
1336 1336 auto& entry = table[static_cast<size_t>(obj)];
1337   - auto old_type = entry.entry.getType();
  1337 + auto old_type = entry.type();
1338 1338  
1339   - if (!old_type && entry.gen > 0) {
  1339 + if (!old_type && entry.gen() > 0) {
1340 1340 // At the moment we are processing the updates last to first and therefore the gen doesn't
1341 1341 // matter as long as it > 0 to distinguish it from an uninitialized entry. This will need
1342 1342 // 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)
1351 1351 return;
1352 1352 }
1353 1353  
1354   - if (old_type && entry.gen >= new_gen) {
  1354 + if (old_type && entry.gen() >= new_gen) {
1355 1355 QTC::TC("qpdf", "QPDF xref reused object");
1356 1356 return;
1357 1357 }
... ... @@ -1360,11 +1360,11 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
1360 1360 case 1:
1361 1361 // f2 is generation
1362 1362 QTC::TC("qpdf", "QPDF xref gen > 0", (f2 > 0) ? 1 : 0);
1363   - entry = {f2, QPDFXRefEntry(f1)};
  1363 + entry = {f2, Uncompressed(f1)};
1364 1364 break;
1365 1365  
1366 1366 case 2:
1367   - entry = {0, QPDFXRefEntry(toI(f1), f2)};
  1367 + entry = {0, Compressed(toI(f1), f2)};
1368 1368 break;
1369 1369  
1370 1370 default:
... ... @@ -1400,19 +1400,18 @@ QPDF::Xref_table::show()
1400 1400 {
1401 1401 auto& cout = *qpdf.m->log->getInfo();
1402 1402 int i = -1;
1403   - for (auto const& [gen, entry]: table) {
  1403 + for (auto const& item: table) {
1404 1404 ++i;
1405   - auto type = entry.getType();
1406   - if (type) {
1407   - cout << std::to_string(i) << "/" << std::to_string(gen) << ": ";
1408   - switch (type) {
  1405 + if (item.type()) {
  1406 + cout << std::to_string(i) << "/" << std::to_string(item.gen()) << ": ";
  1407 + switch (item.type()) {
1409 1408 case 1:
1410   - cout << "uncompressed; offset = " << entry.getOffset() << "\n";
  1409 + cout << "uncompressed; offset = " << item.offset() << "\n";
1411 1410 break;
1412 1411  
1413 1412 case 2:
1414   - cout << "compressed; stream = " << entry.getObjStreamNumber()
1415   - << ", index = " << entry.getObjStreamIndex() << "\n";
  1413 + cout << "compressed; stream = " << item.stream_number()
  1414 + << ", index = " << item.stream_index() << "\n";
1416 1415 break;
1417 1416  
1418 1417 default:
... ... @@ -1430,11 +1429,11 @@ QPDF::Xref_table::resolve()
1430 1429 {
1431 1430 bool may_change = !reconstructed_;
1432 1431 int i = -1;
1433   - for (auto& iter: table) {
  1432 + for (auto& item: table) {
1434 1433 ++i;
1435   - if (iter.entry.getType()) {
1436   - if (qpdf.isUnresolved(QPDFObjGen(i, iter.gen))) {
1437   - qpdf.resolve(QPDFObjGen(i, iter.gen));
  1434 + if (item.type()) {
  1435 + if (qpdf.isUnresolved(QPDFObjGen(i, item.gen()))) {
  1436 + qpdf.resolve(QPDFObjGen(i, item.gen()));
1438 1437 if (may_change && reconstructed_) {
1439 1438 return false;
1440 1439 }
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -3,6 +3,8 @@
3 3  
4 4 #include <qpdf/QPDF.hh>
5 5  
  6 +#include <variant>
  7 +
6 8 // Xref_table encapsulates the pdf's xref table and trailer.
7 9 class QPDF::Xref_table
8 10 {
... ... @@ -34,54 +36,55 @@ class QPDF::Xref_table
34 36 }
35 37  
36 38 // Returns 0 if og is not in table.
37   - int
  39 + size_t
38 40 type(QPDFObjGen og) const
39 41 {
40   - if (og.getObj() >= toI(table.size())) {
  42 + int id = og.getObj();
  43 + if (id < 1 || static_cast<size_t>(id) >= table.size()) {
41 44 return 0;
42 45 }
43   - auto& e = table.at(toS(og.getObj()));
44   - return e.gen == og.getGen() ? e.entry.getType() : 0;
  46 + auto& e = table[static_cast<size_t>(id)];
  47 + return e.gen() == og.getGen() ? e.type() : 0;
45 48 }
46 49  
47 50 // Returns 0 if og is not in table.
48   - int
49   - type(size_t id) const
  51 + size_t
  52 + type(size_t id) const noexcept
50 53 {
51 54 if (id >= table.size()) {
52 55 return 0;
53 56 }
54   - return table[id].entry.getType();
  57 + return table[id].type();
55 58 }
56 59  
57 60 // Returns 0 if og is not in table.
58 61 qpdf_offset_t
59   - offset(QPDFObjGen og) const
  62 + offset(QPDFObjGen og) const noexcept
60 63 {
61   - if (og.getObj() >= toI(table.size())) {
  64 + int id = og.getObj();
  65 + if (id < 1 || static_cast<size_t>(id) >= table.size()) {
62 66 return 0;
63 67 }
64   - auto& e = table.at(toS(og.getObj()));
65   - return e.gen == og.getGen() ? e.entry.getOffset() : 0;
  68 + return table[static_cast<size_t>(id)].offset();
66 69 }
67 70  
68   - // Returns 0 if og is not in table.
  71 + // Returns 0 if id is not in table.
69 72 int
70   - stream_number(int id) const
  73 + stream_number(int id) const noexcept
71 74 {
72 75 if (id < 1 || static_cast<size_t>(id) >= table.size()) {
73 76 return 0;
74 77 }
75   - return table[static_cast<size_t>(id)].entry.getObjStreamNumber();
  78 + return table[static_cast<size_t>(id)].stream_number();
76 79 }
77 80  
78 81 int
79   - stream_index(int id) const
  82 + stream_index(int id) const noexcept
80 83 {
81 84 if (id < 1 || static_cast<size_t>(id) >= table.size()) {
82 85 return 0;
83 86 }
84   - return table[static_cast<size_t>(id)].entry.getObjStreamIndex();
  87 + return table[static_cast<size_t>(id)].stream_index();
85 88 }
86 89  
87 90 // Temporary access to underlying map
... ... @@ -90,9 +93,19 @@ class QPDF::Xref_table
90 93 {
91 94 std::map<QPDFObjGen, QPDFXRefEntry> result;
92 95 int i{0};
93   - for (auto const& [gen, entry]: table) {
94   - if (entry.getType()) {
95   - result.emplace(QPDFObjGen(i, gen), entry);
  96 + for (auto const& item: table) {
  97 + switch (item.type()) {
  98 + case 0:
  99 + break;
  100 + case 1:
  101 + result.emplace(QPDFObjGen(i, item.gen()), item.offset());
  102 + break;
  103 + case 2:
  104 + result.emplace(
  105 + QPDFObjGen(i, 0), QPDFXRefEntry(item.stream_number(), item.stream_index()));
  106 + break;
  107 + default:
  108 + throw std::logic_error("Xref_table: invalid entry type");
96 109 }
97 110 ++i;
98 111 }
... ... @@ -149,10 +162,62 @@ class QPDF::Xref_table
149 162 // Object, count, offset of first entry
150 163 typedef std::tuple<int, int, qpdf_offset_t> Subsection;
151 164  
  165 + struct Uncompressed
  166 + {
  167 + Uncompressed(qpdf_offset_t offset) :
  168 + offset(offset)
  169 + {
  170 + }
  171 + qpdf_offset_t offset;
  172 + };
  173 +
  174 + struct Compressed
  175 + {
  176 + Compressed(int stream_number, int stream_index) :
  177 + stream_number(stream_number),
  178 + stream_index(stream_index)
  179 + {
  180 + }
  181 + int stream_number{0};
  182 + int stream_index{0};
  183 + };
  184 +
  185 + typedef std::variant<std::monostate, Uncompressed, Compressed> Xref;
  186 +
152 187 struct Entry
153 188 {
154   - int gen{0};
155   - QPDFXRefEntry entry;
  189 + int
  190 + gen() const noexcept
  191 + {
  192 + return gen_;
  193 + }
  194 +
  195 + size_t
  196 + type() const noexcept
  197 + {
  198 + return entry.index();
  199 + }
  200 +
  201 + qpdf_offset_t
  202 + offset() const noexcept
  203 + {
  204 + return type() == 1 ? std::get<1>(entry).offset : 0;
  205 + }
  206 +
  207 + int
  208 + stream_number() const noexcept
  209 + {
  210 + return type() == 2 ? std::get<2>(entry).stream_number : 0;
  211 + }
  212 +
  213 + int
  214 + stream_index() const noexcept
  215 + {
  216 + return type() == 2 ? std::get<2>(entry).stream_index : 0;
  217 + }
  218 +
  219 + int gen_{0};
  220 + Xref entry;
156 221 };
157 222  
158 223 void read(qpdf_offset_t offset);
... ...