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,7 +574,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
574 574
575 // Delete all references to type 1 (uncompressed) objects 575 // Delete all references to type 1 (uncompressed) objects
576 for (auto& iter: table) { 576 for (auto& iter: table) {
577 - if (iter.entry.getType() == 1) { 577 + if (iter.type() == 1) {
578 iter = {}; 578 iter = {};
579 } 579 }
580 } 580 }
@@ -638,12 +638,12 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) @@ -638,12 +638,12 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
638 qpdf_offset_t max_offset{0}; 638 qpdf_offset_t max_offset{0};
639 // If there are any xref streams, take the last one to appear. 639 // If there are any xref streams, take the last one to appear.
640 int i = -1; 640 int i = -1;
641 - for (auto const& [gen, entry]: table) { 641 + for (auto const& item: table) {
642 ++i; 642 ++i;
643 - if (entry.getType() != 1) { 643 + if (item.type() != 1) {
644 continue; 644 continue;
645 } 645 }
646 - auto oh = qpdf.getObject(i, gen); 646 + auto oh = qpdf.getObject(i, item.gen());
647 try { 647 try {
648 if (!oh.isStreamOfType("/XRef")) { 648 if (!oh.isStreamOfType("/XRef")) {
649 continue; 649 continue;
@@ -651,7 +651,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) @@ -651,7 +651,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e)
651 } catch (std::exception&) { 651 } catch (std::exception&) {
652 continue; 652 continue;
653 } 653 }
654 - auto offset = entry.getOffset(); 654 + auto offset = item.offset();
655 if (offset > max_offset) { 655 if (offset > max_offset) {
656 max_offset = offset; 656 max_offset = offset;
657 trailer_ = oh.getDict(); 657 trailer_ = oh.getDict();
@@ -1334,9 +1334,9 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2) @@ -1334,9 +1334,9 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
1334 } 1334 }
1335 1335
1336 auto& entry = table[static_cast<size_t>(obj)]; 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 // At the moment we are processing the updates last to first and therefore the gen doesn't 1340 // At the moment we are processing the updates last to first and therefore the gen doesn't
1341 // matter as long as it > 0 to distinguish it from an uninitialized entry. This will need 1341 // matter as long as it > 0 to distinguish it from an uninitialized entry. This will need
1342 // to be revisited when we want to support incremental updates or more comprhensive 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,7 +1351,7 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
1351 return; 1351 return;
1352 } 1352 }
1353 1353
1354 - if (old_type && entry.gen >= new_gen) { 1354 + if (old_type && entry.gen() >= new_gen) {
1355 QTC::TC("qpdf", "QPDF xref reused object"); 1355 QTC::TC("qpdf", "QPDF xref reused object");
1356 return; 1356 return;
1357 } 1357 }
@@ -1360,11 +1360,11 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2) @@ -1360,11 +1360,11 @@ QPDF::Xref_table::insert(int obj, int f0, qpdf_offset_t f1, int f2)
1360 case 1: 1360 case 1:
1361 // f2 is generation 1361 // f2 is generation
1362 QTC::TC("qpdf", "QPDF xref gen > 0", (f2 > 0) ? 1 : 0); 1362 QTC::TC("qpdf", "QPDF xref gen > 0", (f2 > 0) ? 1 : 0);
1363 - entry = {f2, QPDFXRefEntry(f1)}; 1363 + entry = {f2, Uncompressed(f1)};
1364 break; 1364 break;
1365 1365
1366 case 2: 1366 case 2:
1367 - entry = {0, QPDFXRefEntry(toI(f1), f2)}; 1367 + entry = {0, Compressed(toI(f1), f2)};
1368 break; 1368 break;
1369 1369
1370 default: 1370 default:
@@ -1400,19 +1400,18 @@ QPDF::Xref_table::show() @@ -1400,19 +1400,18 @@ QPDF::Xref_table::show()
1400 { 1400 {
1401 auto& cout = *qpdf.m->log->getInfo(); 1401 auto& cout = *qpdf.m->log->getInfo();
1402 int i = -1; 1402 int i = -1;
1403 - for (auto const& [gen, entry]: table) { 1403 + for (auto const& item: table) {
1404 ++i; 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 case 1: 1408 case 1:
1410 - cout << "uncompressed; offset = " << entry.getOffset() << "\n"; 1409 + cout << "uncompressed; offset = " << item.offset() << "\n";
1411 break; 1410 break;
1412 1411
1413 case 2: 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 break; 1415 break;
1417 1416
1418 default: 1417 default:
@@ -1430,11 +1429,11 @@ QPDF::Xref_table::resolve() @@ -1430,11 +1429,11 @@ QPDF::Xref_table::resolve()
1430 { 1429 {
1431 bool may_change = !reconstructed_; 1430 bool may_change = !reconstructed_;
1432 int i = -1; 1431 int i = -1;
1433 - for (auto& iter: table) { 1432 + for (auto& item: table) {
1434 ++i; 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 if (may_change && reconstructed_) { 1437 if (may_change && reconstructed_) {
1439 return false; 1438 return false;
1440 } 1439 }
libqpdf/qpdf/QPDF_private.hh
@@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
3 3
4 #include <qpdf/QPDF.hh> 4 #include <qpdf/QPDF.hh>
5 5
  6 +#include <variant>
  7 +
6 // Xref_table encapsulates the pdf's xref table and trailer. 8 // Xref_table encapsulates the pdf's xref table and trailer.
7 class QPDF::Xref_table 9 class QPDF::Xref_table
8 { 10 {
@@ -34,54 +36,55 @@ class QPDF::Xref_table @@ -34,54 +36,55 @@ class QPDF::Xref_table
34 } 36 }
35 37
36 // Returns 0 if og is not in table. 38 // Returns 0 if og is not in table.
37 - int 39 + size_t
38 type(QPDFObjGen og) const 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 return 0; 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 // Returns 0 if og is not in table. 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 if (id >= table.size()) { 54 if (id >= table.size()) {
52 return 0; 55 return 0;
53 } 56 }
54 - return table[id].entry.getType(); 57 + return table[id].type();
55 } 58 }
56 59
57 // Returns 0 if og is not in table. 60 // Returns 0 if og is not in table.
58 qpdf_offset_t 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 return 0; 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 int 72 int
70 - stream_number(int id) const 73 + stream_number(int id) const noexcept
71 { 74 {
72 if (id < 1 || static_cast<size_t>(id) >= table.size()) { 75 if (id < 1 || static_cast<size_t>(id) >= table.size()) {
73 return 0; 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 int 81 int
79 - stream_index(int id) const 82 + stream_index(int id) const noexcept
80 { 83 {
81 if (id < 1 || static_cast<size_t>(id) >= table.size()) { 84 if (id < 1 || static_cast<size_t>(id) >= table.size()) {
82 return 0; 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 // Temporary access to underlying map 90 // Temporary access to underlying map
@@ -90,9 +93,19 @@ class QPDF::Xref_table @@ -90,9 +93,19 @@ class QPDF::Xref_table
90 { 93 {
91 std::map<QPDFObjGen, QPDFXRefEntry> result; 94 std::map<QPDFObjGen, QPDFXRefEntry> result;
92 int i{0}; 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 ++i; 110 ++i;
98 } 111 }
@@ -149,10 +162,62 @@ class QPDF::Xref_table @@ -149,10 +162,62 @@ class QPDF::Xref_table
149 // Object, count, offset of first entry 162 // Object, count, offset of first entry
150 typedef std::tuple<int, int, qpdf_offset_t> Subsection; 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 struct Entry 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 void read(qpdf_offset_t offset); 223 void read(qpdf_offset_t offset);