Commit 253d3aee8fb231a777cae127af52c262dcdeb9a6
1 parent
3fbff845
Move QPDF::read_xrefEntry to QPDF::Xref_table
Showing
3 changed files
with
45 additions
and
32 deletions
include/qpdf/QPDF.hh
| ... | ... | @@ -762,10 +762,6 @@ class QPDF |
| 762 | 762 | void setTrailer(QPDFObjectHandle obj); |
| 763 | 763 | void read_xref(qpdf_offset_t offset); |
| 764 | 764 | bool resolveXRefTable(); |
| 765 | - bool parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes); | |
| 766 | - bool read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type); | |
| 767 | - bool read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type); | |
| 768 | - qpdf_offset_t read_xrefTable(qpdf_offset_t offset); | |
| 769 | 765 | qpdf_offset_t read_xrefStream(qpdf_offset_t offset); |
| 770 | 766 | qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); |
| 771 | 767 | std::pair<int, std::array<int, 3>> | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -723,7 +723,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 723 | 723 | while (QUtil::is_space(buf[skip])) { |
| 724 | 724 | ++skip; |
| 725 | 725 | } |
| 726 | - xref_offset = read_xrefTable(xref_offset + skip); | |
| 726 | + xref_offset = m->xref_table.read_table(xref_offset + skip); | |
| 727 | 727 | } else { |
| 728 | 728 | xref_offset = read_xrefStream(xref_offset); |
| 729 | 729 | } |
| ... | ... | @@ -769,7 +769,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 769 | 769 | } |
| 770 | 770 | |
| 771 | 771 | bool |
| 772 | -QPDF::parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes) | |
| 772 | +QPDF::Xref_table::parse_first(std::string const& line, int& obj, int& num, int& bytes) | |
| 773 | 773 | { |
| 774 | 774 | // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated |
| 775 | 775 | // buffer. |
| ... | ... | @@ -817,8 +817,10 @@ QPDF::parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes) |
| 817 | 817 | } |
| 818 | 818 | |
| 819 | 819 | bool |
| 820 | -QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | |
| 820 | +QPDF::Xref_table::read_bad_entry(qpdf_offset_t& f1, int& f2, char& type) | |
| 821 | 821 | { |
| 822 | + auto* m = qpdf.m.get(); | |
| 823 | + | |
| 822 | 824 | // Reposition after initial read attempt and reread. |
| 823 | 825 | m->file->seek(m->file->getLastOffset(), SEEK_SET); |
| 824 | 826 | auto line = m->file->readLine(30); |
| ... | ... | @@ -887,7 +889,7 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) |
| 887 | 889 | } |
| 888 | 890 | |
| 889 | 891 | if (invalid) { |
| 890 | - warn(damagedPDF("xref table", "accepting invalid xref table entry")); | |
| 892 | + qpdf.warn(damaged_table("accepting invalid xref table entry")); | |
| 891 | 893 | } |
| 892 | 894 | |
| 893 | 895 | f1 = QUtil::string_to_ll(f1_str.c_str()); |
| ... | ... | @@ -899,8 +901,10 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) |
| 899 | 901 | // Optimistically read and parse xref entry. If entry is bad, call read_bad_xrefEntry and return |
| 900 | 902 | // result. |
| 901 | 903 | bool |
| 902 | -QPDF::read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | |
| 904 | +QPDF::Xref_table::read_entry(qpdf_offset_t& f1, int& f2, char& type) | |
| 903 | 905 | { |
| 906 | + auto* m = qpdf.m.get(); | |
| 907 | + | |
| 904 | 908 | std::array<char, 21> line; |
| 905 | 909 | if (m->file->read(line.data(), 20) != 20) { |
| 906 | 910 | // C++20: [[unlikely]] |
| ... | ... | @@ -948,13 +952,15 @@ QPDF::read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) |
| 948 | 952 | return true; |
| 949 | 953 | } |
| 950 | 954 | } |
| 951 | - return read_bad_xrefEntry(f1, f2, type); | |
| 955 | + return read_bad_entry(f1, f2, type); | |
| 952 | 956 | } |
| 953 | 957 | |
| 954 | 958 | // Read a single cross-reference table section and associated trailer. |
| 955 | 959 | qpdf_offset_t |
| 956 | -QPDF::read_xrefTable(qpdf_offset_t xref_offset) | |
| 960 | +QPDF::Xref_table::read_table(qpdf_offset_t xref_offset) | |
| 957 | 961 | { |
| 962 | + auto* m = qpdf.m.get(); | |
| 963 | + | |
| 958 | 964 | m->file->seek(xref_offset, SEEK_SET); |
| 959 | 965 | std::string line; |
| 960 | 966 | while (true) { |
| ... | ... | @@ -963,33 +969,32 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 963 | 969 | int obj = 0; |
| 964 | 970 | int num = 0; |
| 965 | 971 | int bytes = 0; |
| 966 | - if (!parse_xrefFirst(line, obj, num, bytes)) { | |
| 972 | + if (!parse_first(line, obj, num, bytes)) { | |
| 967 | 973 | QTC::TC("qpdf", "QPDF invalid xref"); |
| 968 | - throw damagedPDF("xref table", "xref syntax invalid"); | |
| 974 | + throw damaged_table("xref syntax invalid"); | |
| 969 | 975 | } |
| 970 | 976 | m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET); |
| 971 | 977 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { |
| 972 | 978 | if (i == 0) { |
| 973 | 979 | // This is needed by checkLinearization() |
| 974 | - m->xref_table.first_item_offset = m->file->tell(); | |
| 980 | + first_item_offset = m->file->tell(); | |
| 975 | 981 | } |
| 976 | 982 | // For xref_table, these will always be small enough to be ints |
| 977 | 983 | qpdf_offset_t f1 = 0; |
| 978 | 984 | int f2 = 0; |
| 979 | 985 | char type = '\0'; |
| 980 | - if (!read_xrefEntry(f1, f2, type)) { | |
| 986 | + if (!read_entry(f1, f2, type)) { | |
| 981 | 987 | QTC::TC("qpdf", "QPDF invalid xref entry"); |
| 982 | - throw damagedPDF( | |
| 983 | - "xref table", "invalid xref entry (obj=" + std::to_string(i) + ")"); | |
| 988 | + throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")"); | |
| 984 | 989 | } |
| 985 | 990 | if (type == 'f') { |
| 986 | - m->xref_table.insert_free(QPDFObjGen(toI(i), f2)); | |
| 991 | + insert_free(QPDFObjGen(toI(i), f2)); | |
| 987 | 992 | } else { |
| 988 | - m->xref_table.insert(toI(i), 1, f1, f2); | |
| 993 | + insert(toI(i), 1, f1, f2); | |
| 989 | 994 | } |
| 990 | 995 | } |
| 991 | 996 | qpdf_offset_t pos = m->file->tell(); |
| 992 | - if (readToken(*m->file).isWord("trailer")) { | |
| 997 | + if (qpdf.readToken(*m->file).isWord("trailer")) { | |
| 993 | 998 | break; |
| 994 | 999 | } else { |
| 995 | 1000 | m->file->seek(pos, SEEK_SET); |
| ... | ... | @@ -997,35 +1002,35 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 997 | 1002 | } |
| 998 | 1003 | |
| 999 | 1004 | // Set offset to previous xref table if any |
| 1000 | - QPDFObjectHandle cur_trailer = readTrailer(); | |
| 1005 | + auto cur_trailer = qpdf.readTrailer(); | |
| 1001 | 1006 | if (!cur_trailer.isDictionary()) { |
| 1002 | 1007 | QTC::TC("qpdf", "QPDF missing trailer"); |
| 1003 | - throw damagedPDF("", "expected trailer dictionary"); | |
| 1008 | + throw qpdf.damagedPDF("", "expected trailer dictionary"); | |
| 1004 | 1009 | } |
| 1005 | 1010 | |
| 1006 | - if (!m->xref_table.trailer) { | |
| 1007 | - setTrailer(cur_trailer); | |
| 1011 | + if (!trailer) { | |
| 1012 | + trailer = cur_trailer; | |
| 1008 | 1013 | |
| 1009 | - if (!m->xref_table.trailer.hasKey("/Size")) { | |
| 1014 | + if (!trailer.hasKey("/Size")) { | |
| 1010 | 1015 | QTC::TC("qpdf", "QPDF trailer lacks size"); |
| 1011 | - throw damagedPDF("trailer", "trailer dictionary lacks /Size key"); | |
| 1016 | + throw qpdf.damagedPDF("trailer", "trailer dictionary lacks /Size key"); | |
| 1012 | 1017 | } |
| 1013 | - if (!m->xref_table.trailer.getKey("/Size").isInteger()) { | |
| 1018 | + if (!trailer.getKey("/Size").isInteger()) { | |
| 1014 | 1019 | QTC::TC("qpdf", "QPDF trailer size not integer"); |
| 1015 | - throw damagedPDF("trailer", "/Size key in trailer dictionary is not an integer"); | |
| 1020 | + throw qpdf.damagedPDF("trailer", "/Size key in trailer dictionary is not an integer"); | |
| 1016 | 1021 | } |
| 1017 | 1022 | } |
| 1018 | 1023 | |
| 1019 | 1024 | if (cur_trailer.hasKey("/XRefStm")) { |
| 1020 | - if (m->xref_table.ignore_streams) { | |
| 1025 | + if (ignore_streams) { | |
| 1021 | 1026 | QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer"); |
| 1022 | 1027 | } else { |
| 1023 | 1028 | if (cur_trailer.getKey("/XRefStm").isInteger()) { |
| 1024 | 1029 | // Read the xref stream but disregard any return value -- we'll use our trailer's |
| 1025 | 1030 | // /Prev key instead of the xref stream's. |
| 1026 | - (void)read_xrefStream(cur_trailer.getKey("/XRefStm").getIntValue()); | |
| 1031 | + (void)qpdf.read_xrefStream(cur_trailer.getKey("/XRefStm").getIntValue()); | |
| 1027 | 1032 | } else { |
| 1028 | - throw damagedPDF("xref stream", xref_offset, "invalid /XRefStm"); | |
| 1033 | + throw qpdf.damagedPDF("xref stream", xref_offset, "invalid /XRefStm"); | |
| 1029 | 1034 | } |
| 1030 | 1035 | } |
| 1031 | 1036 | } |
| ... | ... | @@ -1033,7 +1038,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 1033 | 1038 | if (cur_trailer.hasKey("/Prev")) { |
| 1034 | 1039 | if (!cur_trailer.getKey("/Prev").isInteger()) { |
| 1035 | 1040 | QTC::TC("qpdf", "QPDF trailer prev not integer"); |
| 1036 | - throw damagedPDF("trailer", "/Prev key in trailer dictionary is not an integer"); | |
| 1041 | + throw qpdf.damagedPDF("trailer", "/Prev key in trailer dictionary is not an integer"); | |
| 1037 | 1042 | } |
| 1038 | 1043 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); |
| 1039 | 1044 | return cur_trailer.getKey("/Prev").getIntValue(); | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -12,6 +12,8 @@ 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 | + | |
| 15 | 17 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); |
| 16 | 18 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); |
| 17 | 19 | void insert_free(QPDFObjGen); |
| ... | ... | @@ -33,12 +35,22 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> |
| 33 | 35 | qpdf_offset_t first_item_offset{0}; // actual value from file |
| 34 | 36 | |
| 35 | 37 | private: |
| 38 | + bool parse_first(std::string const& line, int& obj, int& num, int& bytes); | |
| 39 | + bool read_entry(qpdf_offset_t& f1, int& f2, char& type); | |
| 40 | + bool read_bad_entry(qpdf_offset_t& f1, int& f2, char& type); | |
| 41 | + | |
| 36 | 42 | QPDFExc |
| 37 | 43 | damaged_pdf(std::string const& msg) |
| 38 | 44 | { |
| 39 | 45 | return qpdf.damagedPDF("", 0, msg); |
| 40 | 46 | } |
| 41 | 47 | |
| 48 | + QPDFExc | |
| 49 | + damaged_table(std::string const& msg) | |
| 50 | + { | |
| 51 | + return qpdf.damagedPDF("xref table", msg); | |
| 52 | + } | |
| 53 | + | |
| 42 | 54 | void |
| 43 | 55 | warn_damaged(std::string const& msg) |
| 44 | 56 | { | ... | ... |