Commit a4db9b3149562a6117b1d9edf89e3853480aeba8
1 parent
f30a5eb0
Move QPDF::read_xref to QPDF::Xref_table
Showing
3 changed files
with
28 additions
and
26 deletions
include/qpdf/QPDF.hh
| ... | ... | @@ -759,7 +759,6 @@ class QPDF |
| 759 | 759 | |
| 760 | 760 | void parse(char const* password); |
| 761 | 761 | void inParse(bool); |
| 762 | - void read_xref(qpdf_offset_t offset); | |
| 763 | 762 | bool resolveXRefTable(); |
| 764 | 763 | void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); |
| 765 | 764 | QPDFObjectHandle readTrailer(); | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -468,7 +468,7 @@ QPDF::parse(char const* password) |
| 468 | 468 | throw damagedPDF("", 0, "can't find startxref"); |
| 469 | 469 | } |
| 470 | 470 | try { |
| 471 | - read_xref(xref_offset); | |
| 471 | + m->xref_table.read(xref_offset); | |
| 472 | 472 | } catch (QPDFExc&) { |
| 473 | 473 | throw; |
| 474 | 474 | } catch (std::exception& e) { |
| ... | ... | @@ -625,7 +625,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) |
| 625 | 625 | } |
| 626 | 626 | if (max_offset > 0) { |
| 627 | 627 | try { |
| 628 | - qpdf.read_xref(max_offset); | |
| 628 | + read(max_offset); | |
| 629 | 629 | } catch (std::exception&) { |
| 630 | 630 | throw damaged_pdf( |
| 631 | 631 | "error decoding candidate xref stream while recovering damaged file"); |
| ... | ... | @@ -664,8 +664,10 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) |
| 664 | 664 | } |
| 665 | 665 | |
| 666 | 666 | void |
| 667 | -QPDF::read_xref(qpdf_offset_t xref_offset) | |
| 667 | +QPDF::Xref_table::read(qpdf_offset_t xref_offset) | |
| 668 | 668 | { |
| 669 | + auto* m = qpdf.m.get(); | |
| 670 | + | |
| 669 | 671 | std::map<int, int> free_table; |
| 670 | 672 | std::set<qpdf_offset_t> visited; |
| 671 | 673 | while (xref_offset) { |
| ... | ... | @@ -700,7 +702,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 700 | 702 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { |
| 701 | 703 | if (skipped_space) { |
| 702 | 704 | QTC::TC("qpdf", "QPDF xref skipped space"); |
| 703 | - warn(damagedPDF("", 0, "extraneous whitespace seen before xref")); | |
| 705 | + warn_damaged("extraneous whitespace seen before xref"); | |
| 704 | 706 | } |
| 705 | 707 | QTC::TC( |
| 706 | 708 | "qpdf", |
| ... | ... | @@ -714,46 +716,43 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 714 | 716 | while (QUtil::is_space(buf[skip])) { |
| 715 | 717 | ++skip; |
| 716 | 718 | } |
| 717 | - xref_offset = m->xref_table.read_table(xref_offset + skip); | |
| 719 | + xref_offset = read_table(xref_offset + skip); | |
| 718 | 720 | } else { |
| 719 | - xref_offset = m->xref_table.read_stream(xref_offset); | |
| 721 | + xref_offset = read_stream(xref_offset); | |
| 720 | 722 | } |
| 721 | 723 | if (visited.count(xref_offset) != 0) { |
| 722 | 724 | QTC::TC("qpdf", "QPDF xref loop"); |
| 723 | - throw damagedPDF("", 0, "loop detected following xref tables"); | |
| 725 | + throw damaged_pdf("loop detected following xref tables"); | |
| 724 | 726 | } |
| 725 | 727 | } |
| 726 | 728 | |
| 727 | - if (!m->xref_table.trailer) { | |
| 728 | - throw damagedPDF("", 0, "unable to find trailer while reading xref"); | |
| 729 | + if (!trailer) { | |
| 730 | + throw damaged_pdf("unable to find trailer while reading xref"); | |
| 729 | 731 | } |
| 730 | - int size = m->xref_table.trailer.getKey("/Size").getIntValueAsInt(); | |
| 732 | + int size = trailer.getKey("/Size").getIntValueAsInt(); | |
| 731 | 733 | int max_obj = 0; |
| 732 | - if (!m->xref_table.empty()) { | |
| 733 | - max_obj = m->xref_table.rbegin()->first.getObj(); | |
| 734 | + if (!empty()) { | |
| 735 | + max_obj = rbegin()->first.getObj(); | |
| 734 | 736 | } |
| 735 | - if (!m->xref_table.deleted_objects.empty()) { | |
| 736 | - max_obj = std::max(max_obj, *(m->xref_table.deleted_objects.rbegin())); | |
| 737 | + if (!deleted_objects.empty()) { | |
| 738 | + max_obj = std::max(max_obj, *deleted_objects.rbegin()); | |
| 737 | 739 | } |
| 738 | 740 | if ((size < 1) || (size - 1 != max_obj)) { |
| 739 | 741 | QTC::TC("qpdf", "QPDF xref size mismatch"); |
| 740 | - warn(damagedPDF( | |
| 741 | - "", | |
| 742 | - 0, | |
| 743 | - ("reported number of objects (" + std::to_string(size) + | |
| 744 | - ") is not one plus the highest object number (" + std::to_string(max_obj) + ")"))); | |
| 742 | + warn_damaged("reported number of objects (" + std::to_string(size) + | |
| 743 | + ") is not one plus the highest object number (" + std::to_string(max_obj) + ")"); | |
| 745 | 744 | } |
| 746 | 745 | |
| 747 | 746 | // We no longer need the deleted_objects table, so go ahead and clear it out to make sure we |
| 748 | 747 | // never depend on its being set. |
| 749 | - m->xref_table.deleted_objects.clear(); | |
| 748 | + deleted_objects.clear(); | |
| 750 | 749 | |
| 751 | 750 | // Make sure we keep only the highest generation for any object. |
| 752 | 751 | QPDFObjGen last_og{-1, 0}; |
| 753 | - for (auto const& item: m->xref_table) { | |
| 752 | + for (auto const& item: *this) { | |
| 754 | 753 | auto id = item.first.getObj(); |
| 755 | 754 | if (id == last_og.getObj() && id > 0) { |
| 756 | - removeObject(last_og); | |
| 755 | + qpdf.removeObject(last_og); | |
| 757 | 756 | } |
| 758 | 757 | last_og = item.first; |
| 759 | 758 | } | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -12,9 +12,7 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> |
| 12 | 12 | { |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | - qpdf_offset_t read_table(qpdf_offset_t offset); | |
| 16 | - qpdf_offset_t read_stream(qpdf_offset_t offset); | |
| 17 | - | |
| 15 | + void read(qpdf_offset_t offset); | |
| 18 | 16 | void reconstruct(QPDFExc& e); |
| 19 | 17 | |
| 20 | 18 | QPDFObjectHandle trailer; |
| ... | ... | @@ -32,9 +30,14 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> |
| 32 | 30 | qpdf_offset_t first_item_offset{0}; // actual value from file |
| 33 | 31 | |
| 34 | 32 | private: |
| 33 | + // Methods to parse tables | |
| 34 | + qpdf_offset_t read_table(qpdf_offset_t offset); | |
| 35 | 35 | bool parse_first(std::string const& line, int& obj, int& num, int& bytes); |
| 36 | 36 | bool read_entry(qpdf_offset_t& f1, int& f2, char& type); |
| 37 | 37 | bool read_bad_entry(qpdf_offset_t& f1, int& f2, char& type); |
| 38 | + | |
| 39 | + // Methods to parse streams | |
| 40 | + qpdf_offset_t read_stream(qpdf_offset_t offset); | |
| 38 | 41 | qpdf_offset_t process_stream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); |
| 39 | 42 | std::pair<int, std::array<int, 3>> |
| 40 | 43 | process_W(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged); |
| ... | ... | @@ -45,6 +48,7 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> |
| 45 | 48 | int max_num_entries, |
| 46 | 49 | std::function<QPDFExc(std::string_view)> damaged); |
| 47 | 50 | |
| 51 | + // Methods to insert table entries | |
| 48 | 52 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); |
| 49 | 53 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); |
| 50 | 54 | void insert_free(QPDFObjGen); | ... | ... |