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,10 +762,6 @@ class QPDF | ||
| 762 | void setTrailer(QPDFObjectHandle obj); | 762 | void setTrailer(QPDFObjectHandle obj); |
| 763 | void read_xref(qpdf_offset_t offset); | 763 | void read_xref(qpdf_offset_t offset); |
| 764 | bool resolveXRefTable(); | 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 | qpdf_offset_t read_xrefStream(qpdf_offset_t offset); | 765 | qpdf_offset_t read_xrefStream(qpdf_offset_t offset); |
| 770 | qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); | 766 | qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); |
| 771 | std::pair<int, std::array<int, 3>> | 767 | std::pair<int, std::array<int, 3>> |
libqpdf/QPDF.cc
| @@ -723,7 +723,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -723,7 +723,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 723 | while (QUtil::is_space(buf[skip])) { | 723 | while (QUtil::is_space(buf[skip])) { |
| 724 | ++skip; | 724 | ++skip; |
| 725 | } | 725 | } |
| 726 | - xref_offset = read_xrefTable(xref_offset + skip); | 726 | + xref_offset = m->xref_table.read_table(xref_offset + skip); |
| 727 | } else { | 727 | } else { |
| 728 | xref_offset = read_xrefStream(xref_offset); | 728 | xref_offset = read_xrefStream(xref_offset); |
| 729 | } | 729 | } |
| @@ -769,7 +769,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -769,7 +769,7 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 769 | } | 769 | } |
| 770 | 770 | ||
| 771 | bool | 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 | // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated | 774 | // is_space and is_digit both return false on '\0', so this will not overrun the null-terminated |
| 775 | // buffer. | 775 | // buffer. |
| @@ -817,8 +817,10 @@ QPDF::parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes) | @@ -817,8 +817,10 @@ QPDF::parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes) | ||
| 817 | } | 817 | } |
| 818 | 818 | ||
| 819 | bool | 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 | // Reposition after initial read attempt and reread. | 824 | // Reposition after initial read attempt and reread. |
| 823 | m->file->seek(m->file->getLastOffset(), SEEK_SET); | 825 | m->file->seek(m->file->getLastOffset(), SEEK_SET); |
| 824 | auto line = m->file->readLine(30); | 826 | auto line = m->file->readLine(30); |
| @@ -887,7 +889,7 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | @@ -887,7 +889,7 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | ||
| 887 | } | 889 | } |
| 888 | 890 | ||
| 889 | if (invalid) { | 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 | f1 = QUtil::string_to_ll(f1_str.c_str()); | 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,8 +901,10 @@ QPDF::read_bad_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | ||
| 899 | // Optimistically read and parse xref entry. If entry is bad, call read_bad_xrefEntry and return | 901 | // Optimistically read and parse xref entry. If entry is bad, call read_bad_xrefEntry and return |
| 900 | // result. | 902 | // result. |
| 901 | bool | 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 | std::array<char, 21> line; | 908 | std::array<char, 21> line; |
| 905 | if (m->file->read(line.data(), 20) != 20) { | 909 | if (m->file->read(line.data(), 20) != 20) { |
| 906 | // C++20: [[unlikely]] | 910 | // C++20: [[unlikely]] |
| @@ -948,13 +952,15 @@ QPDF::read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | @@ -948,13 +952,15 @@ QPDF::read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) | ||
| 948 | return true; | 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 | // Read a single cross-reference table section and associated trailer. | 958 | // Read a single cross-reference table section and associated trailer. |
| 955 | qpdf_offset_t | 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 | m->file->seek(xref_offset, SEEK_SET); | 964 | m->file->seek(xref_offset, SEEK_SET); |
| 959 | std::string line; | 965 | std::string line; |
| 960 | while (true) { | 966 | while (true) { |
| @@ -963,33 +969,32 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -963,33 +969,32 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 963 | int obj = 0; | 969 | int obj = 0; |
| 964 | int num = 0; | 970 | int num = 0; |
| 965 | int bytes = 0; | 971 | int bytes = 0; |
| 966 | - if (!parse_xrefFirst(line, obj, num, bytes)) { | 972 | + if (!parse_first(line, obj, num, bytes)) { |
| 967 | QTC::TC("qpdf", "QPDF invalid xref"); | 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 | m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET); | 976 | m->file->seek(m->file->getLastOffset() + bytes, SEEK_SET); |
| 971 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { | 977 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { |
| 972 | if (i == 0) { | 978 | if (i == 0) { |
| 973 | // This is needed by checkLinearization() | 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 | // For xref_table, these will always be small enough to be ints | 982 | // For xref_table, these will always be small enough to be ints |
| 977 | qpdf_offset_t f1 = 0; | 983 | qpdf_offset_t f1 = 0; |
| 978 | int f2 = 0; | 984 | int f2 = 0; |
| 979 | char type = '\0'; | 985 | char type = '\0'; |
| 980 | - if (!read_xrefEntry(f1, f2, type)) { | 986 | + if (!read_entry(f1, f2, type)) { |
| 981 | QTC::TC("qpdf", "QPDF invalid xref entry"); | 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 | if (type == 'f') { | 990 | if (type == 'f') { |
| 986 | - m->xref_table.insert_free(QPDFObjGen(toI(i), f2)); | 991 | + insert_free(QPDFObjGen(toI(i), f2)); |
| 987 | } else { | 992 | } else { |
| 988 | - m->xref_table.insert(toI(i), 1, f1, f2); | 993 | + insert(toI(i), 1, f1, f2); |
| 989 | } | 994 | } |
| 990 | } | 995 | } |
| 991 | qpdf_offset_t pos = m->file->tell(); | 996 | qpdf_offset_t pos = m->file->tell(); |
| 992 | - if (readToken(*m->file).isWord("trailer")) { | 997 | + if (qpdf.readToken(*m->file).isWord("trailer")) { |
| 993 | break; | 998 | break; |
| 994 | } else { | 999 | } else { |
| 995 | m->file->seek(pos, SEEK_SET); | 1000 | m->file->seek(pos, SEEK_SET); |
| @@ -997,35 +1002,35 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -997,35 +1002,35 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 997 | } | 1002 | } |
| 998 | 1003 | ||
| 999 | // Set offset to previous xref table if any | 1004 | // Set offset to previous xref table if any |
| 1000 | - QPDFObjectHandle cur_trailer = readTrailer(); | 1005 | + auto cur_trailer = qpdf.readTrailer(); |
| 1001 | if (!cur_trailer.isDictionary()) { | 1006 | if (!cur_trailer.isDictionary()) { |
| 1002 | QTC::TC("qpdf", "QPDF missing trailer"); | 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 | QTC::TC("qpdf", "QPDF trailer lacks size"); | 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 | QTC::TC("qpdf", "QPDF trailer size not integer"); | 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 | if (cur_trailer.hasKey("/XRefStm")) { | 1024 | if (cur_trailer.hasKey("/XRefStm")) { |
| 1020 | - if (m->xref_table.ignore_streams) { | 1025 | + if (ignore_streams) { |
| 1021 | QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer"); | 1026 | QTC::TC("qpdf", "QPDF ignoring XRefStm in trailer"); |
| 1022 | } else { | 1027 | } else { |
| 1023 | if (cur_trailer.getKey("/XRefStm").isInteger()) { | 1028 | if (cur_trailer.getKey("/XRefStm").isInteger()) { |
| 1024 | // Read the xref stream but disregard any return value -- we'll use our trailer's | 1029 | // Read the xref stream but disregard any return value -- we'll use our trailer's |
| 1025 | // /Prev key instead of the xref stream's. | 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 | } else { | 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,7 +1038,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 1033 | if (cur_trailer.hasKey("/Prev")) { | 1038 | if (cur_trailer.hasKey("/Prev")) { |
| 1034 | if (!cur_trailer.getKey("/Prev").isInteger()) { | 1039 | if (!cur_trailer.getKey("/Prev").isInteger()) { |
| 1035 | QTC::TC("qpdf", "QPDF trailer prev not integer"); | 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 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); | 1043 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); |
| 1039 | return cur_trailer.getKey("/Prev").getIntValue(); | 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,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 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); | 17 | void insert_reconstructed(int obj, qpdf_offset_t f1, int f2); |
| 16 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); | 18 | void insert(int obj, int f0, qpdf_offset_t f1, int f2); |
| 17 | void insert_free(QPDFObjGen); | 19 | void insert_free(QPDFObjGen); |
| @@ -33,12 +35,22 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> | @@ -33,12 +35,22 @@ class QPDF::Xref_table: public std::map<QPDFObjGen, QPDFXRefEntry> | ||
| 33 | qpdf_offset_t first_item_offset{0}; // actual value from file | 35 | qpdf_offset_t first_item_offset{0}; // actual value from file |
| 34 | 36 | ||
| 35 | private: | 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 | QPDFExc | 42 | QPDFExc |
| 37 | damaged_pdf(std::string const& msg) | 43 | damaged_pdf(std::string const& msg) |
| 38 | { | 44 | { |
| 39 | return qpdf.damagedPDF("", 0, msg); | 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 | void | 54 | void |
| 43 | warn_damaged(std::string const& msg) | 55 | warn_damaged(std::string const& msg) |
| 44 | { | 56 | { |