Commit a1b646fccafbdbc39c78f2bad4c21aa507f0477f
1 parent
6b9eb14c
Refactor Xref_table::Entry
Replace QPDFXRefEntry with a std::variant of structs.
Showing
2 changed files
with
107 additions
and
43 deletions
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); |