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,7 +759,6 @@ class QPDF | ||
| 759 | 759 | ||
| 760 | void parse(char const* password); | 760 | void parse(char const* password); |
| 761 | void inParse(bool); | 761 | void inParse(bool); |
| 762 | - void read_xref(qpdf_offset_t offset); | ||
| 763 | bool resolveXRefTable(); | 762 | bool resolveXRefTable(); |
| 764 | void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); | 763 | void setLastObjectDescription(std::string const& description, QPDFObjGen const& og); |
| 765 | QPDFObjectHandle readTrailer(); | 764 | QPDFObjectHandle readTrailer(); |
libqpdf/QPDF.cc
| @@ -468,7 +468,7 @@ QPDF::parse(char const* password) | @@ -468,7 +468,7 @@ QPDF::parse(char const* password) | ||
| 468 | throw damagedPDF("", 0, "can't find startxref"); | 468 | throw damagedPDF("", 0, "can't find startxref"); |
| 469 | } | 469 | } |
| 470 | try { | 470 | try { |
| 471 | - read_xref(xref_offset); | 471 | + m->xref_table.read(xref_offset); |
| 472 | } catch (QPDFExc&) { | 472 | } catch (QPDFExc&) { |
| 473 | throw; | 473 | throw; |
| 474 | } catch (std::exception& e) { | 474 | } catch (std::exception& e) { |
| @@ -625,7 +625,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) | @@ -625,7 +625,7 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) | ||
| 625 | } | 625 | } |
| 626 | if (max_offset > 0) { | 626 | if (max_offset > 0) { |
| 627 | try { | 627 | try { |
| 628 | - qpdf.read_xref(max_offset); | 628 | + read(max_offset); |
| 629 | } catch (std::exception&) { | 629 | } catch (std::exception&) { |
| 630 | throw damaged_pdf( | 630 | throw damaged_pdf( |
| 631 | "error decoding candidate xref stream while recovering damaged file"); | 631 | "error decoding candidate xref stream while recovering damaged file"); |
| @@ -664,8 +664,10 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) | @@ -664,8 +664,10 @@ QPDF::Xref_table::reconstruct(QPDFExc& e) | ||
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | void | 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 | std::map<int, int> free_table; | 671 | std::map<int, int> free_table; |
| 670 | std::set<qpdf_offset_t> visited; | 672 | std::set<qpdf_offset_t> visited; |
| 671 | while (xref_offset) { | 673 | while (xref_offset) { |
| @@ -700,7 +702,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -700,7 +702,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 700 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { | 702 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { |
| 701 | if (skipped_space) { | 703 | if (skipped_space) { |
| 702 | QTC::TC("qpdf", "QPDF xref skipped space"); | 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 | QTC::TC( | 707 | QTC::TC( |
| 706 | "qpdf", | 708 | "qpdf", |
| @@ -714,46 +716,43 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -714,46 +716,43 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 714 | while (QUtil::is_space(buf[skip])) { | 716 | while (QUtil::is_space(buf[skip])) { |
| 715 | ++skip; | 717 | ++skip; |
| 716 | } | 718 | } |
| 717 | - xref_offset = m->xref_table.read_table(xref_offset + skip); | 719 | + xref_offset = read_table(xref_offset + skip); |
| 718 | } else { | 720 | } else { |
| 719 | - xref_offset = m->xref_table.read_stream(xref_offset); | 721 | + xref_offset = read_stream(xref_offset); |
| 720 | } | 722 | } |
| 721 | if (visited.count(xref_offset) != 0) { | 723 | if (visited.count(xref_offset) != 0) { |
| 722 | QTC::TC("qpdf", "QPDF xref loop"); | 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 | int max_obj = 0; | 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 | if ((size < 1) || (size - 1 != max_obj)) { | 740 | if ((size < 1) || (size - 1 != max_obj)) { |
| 739 | QTC::TC("qpdf", "QPDF xref size mismatch"); | 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 | // We no longer need the deleted_objects table, so go ahead and clear it out to make sure we | 746 | // We no longer need the deleted_objects table, so go ahead and clear it out to make sure we |
| 748 | // never depend on its being set. | 747 | // never depend on its being set. |
| 749 | - m->xref_table.deleted_objects.clear(); | 748 | + deleted_objects.clear(); |
| 750 | 749 | ||
| 751 | // Make sure we keep only the highest generation for any object. | 750 | // Make sure we keep only the highest generation for any object. |
| 752 | QPDFObjGen last_og{-1, 0}; | 751 | QPDFObjGen last_og{-1, 0}; |
| 753 | - for (auto const& item: m->xref_table) { | 752 | + for (auto const& item: *this) { |
| 754 | auto id = item.first.getObj(); | 753 | auto id = item.first.getObj(); |
| 755 | if (id == last_og.getObj() && id > 0) { | 754 | if (id == last_og.getObj() && id > 0) { |
| 756 | - removeObject(last_og); | 755 | + qpdf.removeObject(last_og); |
| 757 | } | 756 | } |
| 758 | last_og = item.first; | 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,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 | void reconstruct(QPDFExc& e); | 16 | void reconstruct(QPDFExc& e); |
| 19 | 17 | ||
| 20 | QPDFObjectHandle trailer; | 18 | QPDFObjectHandle trailer; |
| @@ -32,9 +30,14 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> | @@ -32,9 +30,14 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> | ||
| 32 | qpdf_offset_t first_item_offset{0}; // actual value from file | 30 | qpdf_offset_t first_item_offset{0}; // actual value from file |
| 33 | 31 | ||
| 34 | private: | 32 | private: |
| 33 | + // Methods to parse tables | ||
| 34 | + qpdf_offset_t read_table(qpdf_offset_t offset); | ||
| 35 | bool parse_first(std::string const& line, int& obj, int& num, int& bytes); | 35 | bool parse_first(std::string const& line, int& obj, int& num, int& bytes); |
| 36 | bool read_entry(qpdf_offset_t& f1, int& f2, char& type); | 36 | bool read_entry(qpdf_offset_t& f1, int& f2, char& type); |
| 37 | bool read_bad_entry(qpdf_offset_t& f1, int& f2, char& type); | 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 | qpdf_offset_t process_stream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); | 41 | qpdf_offset_t process_stream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); |
| 39 | std::pair<int, std::array<int, 3>> | 42 | std::pair<int, std::array<int, 3>> |
| 40 | process_W(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged); | 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,6 +48,7 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> | ||
| 45 | int max_num_entries, | 48 | int max_num_entries, |
| 46 | std::function<QPDFExc(std::string_view)> damaged); | 49 | std::function<QPDFExc(std::string_view)> damaged); |
| 47 | 50 | ||
| 51 | + // Methods to insert table entries | ||
| 48 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); | 52 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); |
| 49 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); | 53 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); |
| 50 | void insert_free(QPDFObjGen); | 54 | void insert_free(QPDFObjGen); |