Commit f74b28f0d1cf2c6302dedd2c24dac1cc077c77a5
1 parent
0186d60d
Add new private method QPDF::processXRefW
Showing
2 changed files
with
37 additions
and
21 deletions
include/qpdf/QPDF.hh
| @@ -1028,6 +1028,8 @@ class QPDF | @@ -1028,6 +1028,8 @@ class QPDF | ||
| 1028 | qpdf_offset_t read_xrefTable(qpdf_offset_t offset); | 1028 | qpdf_offset_t read_xrefTable(qpdf_offset_t offset); |
| 1029 | qpdf_offset_t read_xrefStream(qpdf_offset_t offset); | 1029 | qpdf_offset_t read_xrefStream(qpdf_offset_t offset); |
| 1030 | qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); | 1030 | qpdf_offset_t processXRefStream(qpdf_offset_t offset, QPDFObjectHandle& xref_stream); |
| 1031 | + std::pair<size_t, std::array<int, 3>> | ||
| 1032 | + processXRefW(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged); | ||
| 1031 | std::pair<size_t, std::vector<long long>> processXRefIndex( | 1033 | std::pair<size_t, std::vector<long long>> processXRefIndex( |
| 1032 | QPDFObjectHandle& dict, | 1034 | QPDFObjectHandle& dict, |
| 1033 | size_t entry_size, | 1035 | size_t entry_size, |
libqpdf/QPDF.cc
| @@ -968,6 +968,36 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) | @@ -968,6 +968,36 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) | ||
| 968 | return 0; // unreachable | 968 | return 0; // unreachable |
| 969 | } | 969 | } |
| 970 | 970 | ||
| 971 | +// Return the entry size of the xref stream and the processed W array. | ||
| 972 | +std::pair<size_t, std::array<int, 3>> | ||
| 973 | +QPDF::processXRefW(QPDFObjectHandle& dict, std::function<QPDFExc(std::string_view)> damaged) | ||
| 974 | +{ | ||
| 975 | + auto W_obj = dict.getKey("/W"); | ||
| 976 | + if (!(W_obj.isArray() && (W_obj.getArrayNItems() >= 3) && W_obj.getArrayItem(0).isInteger() && | ||
| 977 | + W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger())) { | ||
| 978 | + throw damaged("Cross-reference stream does not have a proper /W key"); | ||
| 979 | + } | ||
| 980 | + | ||
| 981 | + std::array<int, 3> W; | ||
| 982 | + int entry_size = 0; | ||
| 983 | + auto w_vector = W_obj.getArrayAsVector(); | ||
| 984 | + int max_bytes = sizeof(qpdf_offset_t); | ||
| 985 | + for (size_t i = 0; i < 3; ++i) { | ||
| 986 | + W[i] = w_vector[i].getIntValueAsInt(); | ||
| 987 | + if (W[i] > max_bytes) { | ||
| 988 | + throw damaged("Cross-reference stream's /W contains impossibly large values"); | ||
| 989 | + } | ||
| 990 | + if (W[i] < 0) { | ||
| 991 | + throw damaged("Cross-reference stream's /W contains negative values"); | ||
| 992 | + } | ||
| 993 | + entry_size += W[i]; | ||
| 994 | + } | ||
| 995 | + if (entry_size == 0) { | ||
| 996 | + throw damaged("Cross-reference stream's /W indicates entry size of 0"); | ||
| 997 | + } | ||
| 998 | + return {toS(entry_size), W}; | ||
| 999 | +} | ||
| 1000 | + | ||
| 971 | // Return the expected size of the xref stream and the processed Index array. | 1001 | // Return the expected size of the xref stream and the processed Index array. |
| 972 | std::pair<size_t, std::vector<long long>> | 1002 | std::pair<size_t, std::vector<long long>> |
| 973 | QPDF::processXRefIndex( | 1003 | QPDF::processXRefIndex( |
| @@ -1033,28 +1063,12 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1033,28 +1063,12 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1033 | }; | 1063 | }; |
| 1034 | 1064 | ||
| 1035 | auto dict = xref_obj.getDict(); | 1065 | auto dict = xref_obj.getDict(); |
| 1036 | - auto W_obj = dict.getKey("/W"); | ||
| 1037 | auto Size_obj = dict.getKey("/Size"); | 1066 | auto Size_obj = dict.getKey("/Size"); |
| 1038 | - if (!(W_obj.isArray() && (W_obj.getArrayNItems() >= 3) && W_obj.getArrayItem(0).isInteger() && | ||
| 1039 | - W_obj.getArrayItem(1).isInteger() && W_obj.getArrayItem(2).isInteger() && | ||
| 1040 | - Size_obj.isInteger())) { | ||
| 1041 | - throw damaged("Cross-reference stream does not have a proper /W key"); | ||
| 1042 | - } | ||
| 1043 | - | ||
| 1044 | - int W[3]; | ||
| 1045 | - size_t entry_size = 0; | ||
| 1046 | - int max_bytes = sizeof(qpdf_offset_t); | ||
| 1047 | - for (int i = 0; i < 3; ++i) { | ||
| 1048 | - W[i] = W_obj.getArrayItem(i).getIntValueAsInt(); | ||
| 1049 | - if (W[i] > max_bytes) { | ||
| 1050 | - throw damaged("Cross-reference stream's /W contains impossibly large values"); | ||
| 1051 | - } | ||
| 1052 | - entry_size += toS(W[i]); | ||
| 1053 | - } | ||
| 1054 | - if (entry_size == 0) { | ||
| 1055 | - throw damaged("Cross-reference stream's /W indicates entry size of 0"); | 1067 | + if (!Size_obj.isInteger()) { |
| 1068 | + throw damaged("Cross-reference stream does not have a proper /Size key"); | ||
| 1056 | } | 1069 | } |
| 1057 | 1070 | ||
| 1071 | + auto [entry_size, W] = processXRefW(dict, damaged); | ||
| 1058 | auto [expected_size, indx] = processXRefIndex(dict, entry_size, damaged); | 1072 | auto [expected_size, indx] = processXRefIndex(dict, entry_size, damaged); |
| 1059 | 1073 | ||
| 1060 | std::shared_ptr<Buffer> bp = xref_obj.getStreamData(qpdf_dl_specialized); | 1074 | std::shared_ptr<Buffer> bp = xref_obj.getStreamData(qpdf_dl_specialized); |
| @@ -1090,8 +1104,8 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1090,8 +1104,8 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1090 | throw std::range_error(msg.str()); | 1104 | throw std::range_error(msg.str()); |
| 1091 | } | 1105 | } |
| 1092 | // Read this entry | 1106 | // Read this entry |
| 1093 | - qpdf_offset_t fields[3]; | ||
| 1094 | - for (int j = 0; j < 3; ++j) { | 1107 | + std::array<qpdf_offset_t, 3> fields; |
| 1108 | + for (size_t j = 0; j < 3; ++j) { | ||
| 1095 | fields[j] = 0; | 1109 | fields[j] = 0; |
| 1096 | if ((j == 0) && (W[0] == 0)) { | 1110 | if ((j == 0) && (W[0] == 0)) { |
| 1097 | QTC::TC("qpdf", "QPDF default for xref stream field 0"); | 1111 | QTC::TC("qpdf", "QPDF default for xref stream field 0"); |