Commit 5ccab4be03701744f9795b37b4e5835b1a7b1c1d
Committed by
Jay Berkenbilt
1 parent
b9483662
Add private methods QPDF::damagedPDF
Showing
5 changed files
with
217 additions
and
392 deletions
include/qpdf/QPDF.hh
| ... | ... | @@ -1194,6 +1194,22 @@ class QPDF |
| 1194 | 1194 | std::shared_ptr<QPDFObject> const& object, |
| 1195 | 1195 | qpdf_offset_t end_before_space, |
| 1196 | 1196 | qpdf_offset_t end_after_space); |
| 1197 | + static QPDFExc damagedPDF( | |
| 1198 | + std::shared_ptr<InputSource> const& input, | |
| 1199 | + std::string const& object, | |
| 1200 | + qpdf_offset_t offset, | |
| 1201 | + std::string const& message); | |
| 1202 | + QPDFExc damagedPDF( | |
| 1203 | + std::shared_ptr<InputSource> const& input, | |
| 1204 | + qpdf_offset_t offset, | |
| 1205 | + std::string const& message); | |
| 1206 | + QPDFExc damagedPDF( | |
| 1207 | + std::string const& object, | |
| 1208 | + qpdf_offset_t offset, | |
| 1209 | + std::string const& message); | |
| 1210 | + QPDFExc damagedPDF(std::string const& object, std::string const& message); | |
| 1211 | + QPDFExc damagedPDF(qpdf_offset_t offset, std::string const& message); | |
| 1212 | + QPDFExc damagedPDF(std::string const& message); | |
| 1197 | 1213 | |
| 1198 | 1214 | // Calls finish() on the pipeline when done but does not delete it |
| 1199 | 1215 | bool pipeStreamData( | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -481,7 +481,7 @@ QPDF::parse(char const* password) |
| 481 | 481 | PatternFinder hf(*this, &QPDF::findHeader); |
| 482 | 482 | if (!this->m->file->findFirst("%PDF-", 0, 1024, hf)) { |
| 483 | 483 | QTC::TC("qpdf", "QPDF not a pdf file"); |
| 484 | - warn(qpdf_e_damaged_pdf, "", 0, "can't find PDF header"); | |
| 484 | + warn(damagedPDF("", 0, "can't find PDF header")); | |
| 485 | 485 | // QPDFWriter writes files that usually require at least |
| 486 | 486 | // version 1.2 for /FlateDecode |
| 487 | 487 | this->m->pdf_version = "1.2"; |
| ... | ... | @@ -503,24 +503,15 @@ QPDF::parse(char const* password) |
| 503 | 503 | try { |
| 504 | 504 | if (xref_offset == 0) { |
| 505 | 505 | QTC::TC("qpdf", "QPDF can't find startxref"); |
| 506 | - throw QPDFExc( | |
| 507 | - qpdf_e_damaged_pdf, | |
| 508 | - this->m->file->getName(), | |
| 509 | - "", | |
| 510 | - 0, | |
| 511 | - "can't find startxref"); | |
| 506 | + throw damagedPDF("", 0, "can't find startxref"); | |
| 512 | 507 | } |
| 513 | 508 | try { |
| 514 | 509 | read_xref(xref_offset); |
| 515 | 510 | } catch (QPDFExc&) { |
| 516 | 511 | throw; |
| 517 | 512 | } catch (std::exception& e) { |
| 518 | - throw QPDFExc( | |
| 519 | - qpdf_e_damaged_pdf, | |
| 520 | - this->m->file->getName(), | |
| 521 | - "", | |
| 522 | - 0, | |
| 523 | - std::string("error reading xref: ") + e.what()); | |
| 513 | + throw damagedPDF( | |
| 514 | + "", 0, std::string("error reading xref: ") + e.what()); | |
| 524 | 515 | } |
| 525 | 516 | } catch (QPDFExc& e) { |
| 526 | 517 | if (this->m->attempt_recovery) { |
| ... | ... | @@ -589,13 +580,9 @@ QPDF::reconstruct_xref(QPDFExc& e) |
| 589 | 580 | |
| 590 | 581 | this->m->reconstructed_xref = true; |
| 591 | 582 | |
| 592 | - warn(qpdf_e_damaged_pdf, "", 0, "file is damaged"); | |
| 583 | + warn(damagedPDF("", 0, "file is damaged")); | |
| 593 | 584 | warn(e); |
| 594 | - warn( | |
| 595 | - qpdf_e_damaged_pdf, | |
| 596 | - "", | |
| 597 | - 0, | |
| 598 | - "Attempting to reconstruct cross-reference table"); | |
| 585 | + warn(damagedPDF("", 0, "Attempting to reconstruct cross-reference table")); | |
| 599 | 586 | |
| 600 | 587 | // Delete all references to type 1 (uncompressed) objects |
| 601 | 588 | std::set<QPDFObjGen> to_delete; |
| ... | ... | @@ -655,13 +642,10 @@ QPDF::reconstruct_xref(QPDFExc& e) |
| 655 | 642 | // with bad startxref pointers even when they have object |
| 656 | 643 | // streams. |
| 657 | 644 | |
| 658 | - throw QPDFExc( | |
| 659 | - qpdf_e_damaged_pdf, | |
| 660 | - this->m->file->getName(), | |
| 645 | + throw damagedPDF( | |
| 661 | 646 | "", |
| 662 | 647 | 0, |
| 663 | - "unable to find trailer " | |
| 664 | - "dictionary while recovering damaged file"); | |
| 648 | + "unable to find trailer dictionary while recovering damaged file"); | |
| 665 | 649 | } |
| 666 | 650 | |
| 667 | 651 | // We could iterate through the objects looking for streams and |
| ... | ... | @@ -716,11 +700,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 716 | 700 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { |
| 717 | 701 | if (skipped_space) { |
| 718 | 702 | QTC::TC("qpdf", "QPDF xref skipped space"); |
| 719 | - warn( | |
| 720 | - qpdf_e_damaged_pdf, | |
| 721 | - "", | |
| 722 | - 0, | |
| 723 | - "extraneous whitespace seen before xref"); | |
| 703 | + warn(damagedPDF( | |
| 704 | + "", 0, "extraneous whitespace seen before xref")); | |
| 724 | 705 | } |
| 725 | 706 | QTC::TC( |
| 726 | 707 | "qpdf", |
| ... | ... | @@ -741,22 +722,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 741 | 722 | } |
| 742 | 723 | if (visited.count(xref_offset) != 0) { |
| 743 | 724 | QTC::TC("qpdf", "QPDF xref loop"); |
| 744 | - throw QPDFExc( | |
| 745 | - qpdf_e_damaged_pdf, | |
| 746 | - this->m->file->getName(), | |
| 747 | - "", | |
| 748 | - 0, | |
| 749 | - "loop detected following xref tables"); | |
| 725 | + throw damagedPDF("", 0, "loop detected following xref tables"); | |
| 750 | 726 | } |
| 751 | 727 | } |
| 752 | 728 | |
| 753 | 729 | if (!this->m->trailer.isInitialized()) { |
| 754 | - throw QPDFExc( | |
| 755 | - qpdf_e_damaged_pdf, | |
| 756 | - this->m->file->getName(), | |
| 757 | - "", | |
| 758 | - 0, | |
| 759 | - "unable to find trailer while reading xref"); | |
| 730 | + throw damagedPDF("", 0, "unable to find trailer while reading xref"); | |
| 760 | 731 | } |
| 761 | 732 | int size = this->m->trailer.getKey("/Size").getIntValueAsInt(); |
| 762 | 733 | int max_obj = 0; |
| ... | ... | @@ -768,14 +739,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) |
| 768 | 739 | } |
| 769 | 740 | if ((size < 1) || (size - 1 != max_obj)) { |
| 770 | 741 | QTC::TC("qpdf", "QPDF xref size mismatch"); |
| 771 | - warn( | |
| 772 | - qpdf_e_damaged_pdf, | |
| 742 | + warn(damagedPDF( | |
| 773 | 743 | "", |
| 774 | 744 | 0, |
| 775 | - (std::string("reported number of objects (") + | |
| 776 | - std::to_string(size) + | |
| 745 | + ("reported number of objects (" + std::to_string(size) + | |
| 777 | 746 | ") is not one plus the highest object number (" + |
| 778 | - std::to_string(max_obj) + ")")); | |
| 747 | + std::to_string(max_obj) + ")"))); | |
| 779 | 748 | } |
| 780 | 749 | |
| 781 | 750 | // We no longer need the deleted_objects table, so go ahead and |
| ... | ... | @@ -899,11 +868,7 @@ QPDF::parse_xrefEntry( |
| 899 | 868 | } |
| 900 | 869 | |
| 901 | 870 | if (invalid) { |
| 902 | - warn( | |
| 903 | - qpdf_e_damaged_pdf, | |
| 904 | - "xref table", | |
| 905 | - this->m->file->getLastOffset(), | |
| 906 | - "accepting invalid xref table entry"); | |
| 871 | + warn(damagedPDF("xref table", "accepting invalid xref table entry")); | |
| 907 | 872 | } |
| 908 | 873 | |
| 909 | 874 | f1 = QUtil::string_to_ll(f1_str.c_str()); |
| ... | ... | @@ -929,12 +894,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 929 | 894 | int bytes = 0; |
| 930 | 895 | if (!parse_xrefFirst(line, obj, num, bytes)) { |
| 931 | 896 | QTC::TC("qpdf", "QPDF invalid xref"); |
| 932 | - throw QPDFExc( | |
| 933 | - qpdf_e_damaged_pdf, | |
| 934 | - this->m->file->getName(), | |
| 935 | - "xref table", | |
| 936 | - this->m->file->getLastOffset(), | |
| 937 | - "xref syntax invalid"); | |
| 897 | + throw damagedPDF("xref table", "xref syntax invalid"); | |
| 938 | 898 | } |
| 939 | 899 | this->m->file->seek(this->m->file->getLastOffset() + bytes, SEEK_SET); |
| 940 | 900 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { |
| ... | ... | @@ -949,11 +909,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 949 | 909 | char type = '\0'; |
| 950 | 910 | if (!parse_xrefEntry(xref_entry, f1, f2, type)) { |
| 951 | 911 | QTC::TC("qpdf", "QPDF invalid xref entry"); |
| 952 | - throw QPDFExc( | |
| 953 | - qpdf_e_damaged_pdf, | |
| 954 | - this->m->file->getName(), | |
| 912 | + throw damagedPDF( | |
| 955 | 913 | "xref table", |
| 956 | - this->m->file->getLastOffset(), | |
| 957 | 914 | "invalid xref entry (obj=" + std::to_string(i) + ")"); |
| 958 | 915 | } |
| 959 | 916 | if (type == 'f') { |
| ... | ... | @@ -978,12 +935,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 978 | 935 | readObject(this->m->file, "trailer", QPDFObjGen(), false); |
| 979 | 936 | if (!cur_trailer.isDictionary()) { |
| 980 | 937 | QTC::TC("qpdf", "QPDF missing trailer"); |
| 981 | - throw QPDFExc( | |
| 982 | - qpdf_e_damaged_pdf, | |
| 983 | - this->m->file->getName(), | |
| 984 | - "", | |
| 985 | - this->m->file->getLastOffset(), | |
| 986 | - "expected trailer dictionary"); | |
| 938 | + throw damagedPDF("", "expected trailer dictionary"); | |
| 987 | 939 | } |
| 988 | 940 | |
| 989 | 941 | if (!this->m->trailer.isInitialized()) { |
| ... | ... | @@ -991,22 +943,12 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 991 | 943 | |
| 992 | 944 | if (!this->m->trailer.hasKey("/Size")) { |
| 993 | 945 | QTC::TC("qpdf", "QPDF trailer lacks size"); |
| 994 | - throw QPDFExc( | |
| 995 | - qpdf_e_damaged_pdf, | |
| 996 | - this->m->file->getName(), | |
| 997 | - "trailer", | |
| 998 | - this->m->file->getLastOffset(), | |
| 999 | - "trailer dictionary lacks /Size key"); | |
| 946 | + throw damagedPDF("trailer", "trailer dictionary lacks /Size key"); | |
| 1000 | 947 | } |
| 1001 | 948 | if (!this->m->trailer.getKey("/Size").isInteger()) { |
| 1002 | 949 | QTC::TC("qpdf", "QPDF trailer size not integer"); |
| 1003 | - throw QPDFExc( | |
| 1004 | - qpdf_e_damaged_pdf, | |
| 1005 | - this->m->file->getName(), | |
| 1006 | - "trailer", | |
| 1007 | - this->m->file->getLastOffset(), | |
| 1008 | - "/Size key in trailer dictionary is not " | |
| 1009 | - "an integer"); | |
| 950 | + throw damagedPDF( | |
| 951 | + "trailer", "/Size key in trailer dictionary is not an integer"); | |
| 1010 | 952 | } |
| 1011 | 953 | } |
| 1012 | 954 | |
| ... | ... | @@ -1021,12 +963,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 1021 | 963 | (void)read_xrefStream( |
| 1022 | 964 | cur_trailer.getKey("/XRefStm").getIntValue()); |
| 1023 | 965 | } else { |
| 1024 | - throw QPDFExc( | |
| 1025 | - qpdf_e_damaged_pdf, | |
| 1026 | - this->m->file->getName(), | |
| 1027 | - "xref stream", | |
| 1028 | - xref_offset, | |
| 1029 | - "invalid /XRefStm"); | |
| 966 | + throw damagedPDF( | |
| 967 | + "xref stream", xref_offset, "invalid /XRefStm"); | |
| 1030 | 968 | } |
| 1031 | 969 | } |
| 1032 | 970 | } |
| ... | ... | @@ -1039,13 +977,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) |
| 1039 | 977 | if (cur_trailer.hasKey("/Prev")) { |
| 1040 | 978 | if (!cur_trailer.getKey("/Prev").isInteger()) { |
| 1041 | 979 | QTC::TC("qpdf", "QPDF trailer prev not integer"); |
| 1042 | - throw QPDFExc( | |
| 1043 | - qpdf_e_damaged_pdf, | |
| 1044 | - this->m->file->getName(), | |
| 1045 | - "trailer", | |
| 1046 | - this->m->file->getLastOffset(), | |
| 1047 | - "/Prev key in trailer dictionary is not " | |
| 1048 | - "an integer"); | |
| 980 | + throw damagedPDF( | |
| 981 | + "trailer", "/Prev key in trailer dictionary is not an integer"); | |
| 1049 | 982 | } |
| 1050 | 983 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); |
| 1051 | 984 | xref_offset = cur_trailer.getKey("/Prev").getIntValue(); |
| ... | ... | @@ -1078,12 +1011,7 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) |
| 1078 | 1011 | |
| 1079 | 1012 | if (!found) { |
| 1080 | 1013 | QTC::TC("qpdf", "QPDF can't find xref"); |
| 1081 | - throw QPDFExc( | |
| 1082 | - qpdf_e_damaged_pdf, | |
| 1083 | - this->m->file->getName(), | |
| 1084 | - "", | |
| 1085 | - xref_offset, | |
| 1086 | - "xref not found"); | |
| 1014 | + throw damagedPDF("", xref_offset, "xref not found"); | |
| 1087 | 1015 | } |
| 1088 | 1016 | |
| 1089 | 1017 | return xref_offset; |
| ... | ... | @@ -1101,13 +1029,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1101 | 1029 | W_obj.getArrayItem(2).isInteger() && |
| 1102 | 1030 | dict.getKey("/Size").isInteger() && |
| 1103 | 1031 | (Index_obj.isArray() || Index_obj.isNull()))) { |
| 1104 | - throw QPDFExc( | |
| 1105 | - qpdf_e_damaged_pdf, | |
| 1106 | - this->m->file->getName(), | |
| 1032 | + throw damagedPDF( | |
| 1107 | 1033 | "xref stream", |
| 1108 | 1034 | xref_offset, |
| 1109 | - "Cross-reference stream does not have" | |
| 1110 | - " proper /W and /Index keys"); | |
| 1035 | + "Cross-reference stream does not have proper /W and /Index keys"); | |
| 1111 | 1036 | } |
| 1112 | 1037 | |
| 1113 | 1038 | int W[3]; |
| ... | ... | @@ -1116,24 +1041,18 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1116 | 1041 | for (int i = 0; i < 3; ++i) { |
| 1117 | 1042 | W[i] = W_obj.getArrayItem(i).getIntValueAsInt(); |
| 1118 | 1043 | if (W[i] > max_bytes) { |
| 1119 | - throw QPDFExc( | |
| 1120 | - qpdf_e_damaged_pdf, | |
| 1121 | - this->m->file->getName(), | |
| 1044 | + throw damagedPDF( | |
| 1122 | 1045 | "xref stream", |
| 1123 | 1046 | xref_offset, |
| 1124 | - "Cross-reference stream's /W contains" | |
| 1125 | - " impossibly large values"); | |
| 1047 | + "Cross-reference stream's /W contains impossibly large values"); | |
| 1126 | 1048 | } |
| 1127 | 1049 | entry_size += toS(W[i]); |
| 1128 | 1050 | } |
| 1129 | 1051 | if (entry_size == 0) { |
| 1130 | - throw QPDFExc( | |
| 1131 | - qpdf_e_damaged_pdf, | |
| 1132 | - this->m->file->getName(), | |
| 1052 | + throw damagedPDF( | |
| 1133 | 1053 | "xref stream", |
| 1134 | 1054 | xref_offset, |
| 1135 | - "Cross-reference stream's /W indicates" | |
| 1136 | - " entry size of 0"); | |
| 1055 | + "Cross-reference stream's /W indicates entry size of 0"); | |
| 1137 | 1056 | } |
| 1138 | 1057 | unsigned long long max_num_entries = |
| 1139 | 1058 | static_cast<unsigned long long>(-1) / entry_size; |
| ... | ... | @@ -1142,21 +1061,17 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1142 | 1061 | if (Index_obj.isArray()) { |
| 1143 | 1062 | int n_index = Index_obj.getArrayNItems(); |
| 1144 | 1063 | if ((n_index % 2) || (n_index < 2)) { |
| 1145 | - throw QPDFExc( | |
| 1146 | - qpdf_e_damaged_pdf, | |
| 1147 | - this->m->file->getName(), | |
| 1064 | + throw damagedPDF( | |
| 1148 | 1065 | "xref stream", |
| 1149 | 1066 | xref_offset, |
| 1150 | - "Cross-reference stream's /Index has an" | |
| 1151 | - " invalid number of values"); | |
| 1067 | + "Cross-reference stream's /Index has an invalid number of " | |
| 1068 | + "values"); | |
| 1152 | 1069 | } |
| 1153 | 1070 | for (int i = 0; i < n_index; ++i) { |
| 1154 | 1071 | if (Index_obj.getArrayItem(i).isInteger()) { |
| 1155 | 1072 | indx.push_back(Index_obj.getArrayItem(i).getIntValue()); |
| 1156 | 1073 | } else { |
| 1157 | - throw QPDFExc( | |
| 1158 | - qpdf_e_damaged_pdf, | |
| 1159 | - this->m->file->getName(), | |
| 1074 | + throw damagedPDF( | |
| 1160 | 1075 | "xref stream", |
| 1161 | 1076 | xref_offset, |
| 1162 | 1077 | ("Cross-reference stream's /Index's item " + |
| ... | ... | @@ -1174,13 +1089,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1174 | 1089 | size_t num_entries = 0; |
| 1175 | 1090 | for (size_t i = 1; i < indx.size(); i += 2) { |
| 1176 | 1091 | if (indx.at(i) > QIntC::to_longlong(max_num_entries - num_entries)) { |
| 1177 | - throw QPDFExc( | |
| 1178 | - qpdf_e_damaged_pdf, | |
| 1179 | - this->m->file->getName(), | |
| 1092 | + throw damagedPDF( | |
| 1180 | 1093 | "xref stream", |
| 1181 | 1094 | xref_offset, |
| 1182 | - ("Cross-reference stream claims to contain" | |
| 1183 | - " too many entries: " + | |
| 1095 | + ("Cross-reference stream claims to contain too many entries: " + | |
| 1184 | 1096 | std::to_string(indx.at(i)) + " " + |
| 1185 | 1097 | std::to_string(max_num_entries) + " " + |
| 1186 | 1098 | std::to_string(num_entries))); |
| ... | ... | @@ -1196,13 +1108,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1196 | 1108 | size_t actual_size = bp->getSize(); |
| 1197 | 1109 | |
| 1198 | 1110 | if (expected_size != actual_size) { |
| 1199 | - QPDFExc x( | |
| 1200 | - qpdf_e_damaged_pdf, | |
| 1201 | - this->m->file->getName(), | |
| 1111 | + QPDFExc x = damagedPDF( | |
| 1202 | 1112 | "xref stream", |
| 1203 | 1113 | xref_offset, |
| 1204 | - ("Cross-reference stream data has the wrong size;" | |
| 1205 | - " expected = " + | |
| 1114 | + ("Cross-reference stream data has the wrong size; expected = " + | |
| 1206 | 1115 | std::to_string(expected_size) + |
| 1207 | 1116 | "; actual = " + std::to_string(actual_size))); |
| 1208 | 1117 | if (expected_size > actual_size) { |
| ... | ... | @@ -1286,13 +1195,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) |
| 1286 | 1195 | |
| 1287 | 1196 | if (dict.hasKey("/Prev")) { |
| 1288 | 1197 | if (!dict.getKey("/Prev").isInteger()) { |
| 1289 | - throw QPDFExc( | |
| 1290 | - qpdf_e_damaged_pdf, | |
| 1291 | - this->m->file->getName(), | |
| 1198 | + throw damagedPDF( | |
| 1292 | 1199 | "xref stream", |
| 1293 | - this->m->file->getLastOffset(), | |
| 1294 | - "/Prev key in xref stream dictionary is not " | |
| 1295 | - "an integer"); | |
| 1200 | + "/Prev key in xref stream dictionary is not an integer"); | |
| 1296 | 1201 | } |
| 1297 | 1202 | QTC::TC("qpdf", "QPDF prev key in xref stream dictionary"); |
| 1298 | 1203 | xref_offset = dict.getKey("/Prev").getIntValue(); |
| ... | ... | @@ -1351,11 +1256,8 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite) |
| 1351 | 1256 | break; |
| 1352 | 1257 | |
| 1353 | 1258 | default: |
| 1354 | - throw QPDFExc( | |
| 1355 | - qpdf_e_damaged_pdf, | |
| 1356 | - this->m->file->getName(), | |
| 1259 | + throw damagedPDF( | |
| 1357 | 1260 | "xref stream", |
| 1358 | - this->m->file->getLastOffset(), | |
| 1359 | 1261 | "unknown xref stream entry type " + std::to_string(f0)); |
| 1360 | 1262 | break; |
| 1361 | 1263 | } |
| ... | ... | @@ -1522,12 +1424,8 @@ QPDF::readObject( |
| 1522 | 1424 | // Nothing in the PDF spec appears to allow empty objects, but |
| 1523 | 1425 | // they have been encountered in actual PDF files and Adobe |
| 1524 | 1426 | // Reader appears to ignore them. |
| 1525 | - warn(QPDFExc( | |
| 1526 | - qpdf_e_damaged_pdf, | |
| 1527 | - input->getName(), | |
| 1528 | - this->m->last_object_description, | |
| 1529 | - input->getLastOffset(), | |
| 1530 | - "empty object treated as null")); | |
| 1427 | + warn(damagedPDF( | |
| 1428 | + input, input->getLastOffset(), "empty object treated as null")); | |
| 1531 | 1429 | } else if (object.isDictionary() && (!in_object_stream)) { |
| 1532 | 1430 | // check for stream |
| 1533 | 1431 | qpdf_offset_t cur_offset = input->tell(); |
| ... | ... | @@ -1569,34 +1467,27 @@ QPDF::readObject( |
| 1569 | 1467 | // of not having seen a newline. |
| 1570 | 1468 | QTC::TC("qpdf", "QPDF stream with CR only"); |
| 1571 | 1469 | input->unreadCh(ch); |
| 1572 | - warn(QPDFExc( | |
| 1573 | - qpdf_e_damaged_pdf, | |
| 1574 | - input->getName(), | |
| 1575 | - this->m->last_object_description, | |
| 1470 | + warn(damagedPDF( | |
| 1471 | + input, | |
| 1576 | 1472 | input->tell(), |
| 1577 | - "stream keyword followed" | |
| 1578 | - " by carriage return only")); | |
| 1473 | + "stream keyword followed by carriage return " | |
| 1474 | + "only")); | |
| 1579 | 1475 | } |
| 1580 | 1476 | } |
| 1581 | 1477 | } else if (QUtil::is_space(ch)) { |
| 1582 | - warn(QPDFExc( | |
| 1583 | - qpdf_e_damaged_pdf, | |
| 1584 | - input->getName(), | |
| 1585 | - this->m->last_object_description, | |
| 1478 | + warn(damagedPDF( | |
| 1479 | + input, | |
| 1586 | 1480 | input->tell(), |
| 1587 | - "stream keyword followed by" | |
| 1588 | - " extraneous whitespace")); | |
| 1481 | + "stream keyword followed by extraneous whitespace")); | |
| 1589 | 1482 | done = false; |
| 1590 | 1483 | } else { |
| 1591 | 1484 | QTC::TC("qpdf", "QPDF stream without newline"); |
| 1592 | 1485 | input->unreadCh(ch); |
| 1593 | - warn(QPDFExc( | |
| 1594 | - qpdf_e_damaged_pdf, | |
| 1595 | - input->getName(), | |
| 1596 | - this->m->last_object_description, | |
| 1486 | + warn(damagedPDF( | |
| 1487 | + input, | |
| 1597 | 1488 | input->tell(), |
| 1598 | - "stream keyword not followed" | |
| 1599 | - " by proper line terminator")); | |
| 1489 | + "stream keyword not followed by proper line " | |
| 1490 | + "terminator")); | |
| 1600 | 1491 | } |
| 1601 | 1492 | } |
| 1602 | 1493 | |
| ... | ... | @@ -1612,21 +1503,15 @@ QPDF::readObject( |
| 1612 | 1503 | |
| 1613 | 1504 | if (dict.count("/Length") == 0) { |
| 1614 | 1505 | QTC::TC("qpdf", "QPDF stream without length"); |
| 1615 | - throw QPDFExc( | |
| 1616 | - qpdf_e_damaged_pdf, | |
| 1617 | - input->getName(), | |
| 1618 | - this->m->last_object_description, | |
| 1619 | - offset, | |
| 1620 | - "stream dictionary lacks /Length key"); | |
| 1506 | + throw damagedPDF( | |
| 1507 | + input, offset, "stream dictionary lacks /Length key"); | |
| 1621 | 1508 | } |
| 1622 | 1509 | |
| 1623 | 1510 | QPDFObjectHandle length_obj = dict["/Length"]; |
| 1624 | 1511 | if (!length_obj.isInteger()) { |
| 1625 | 1512 | QTC::TC("qpdf", "QPDF stream length not integer"); |
| 1626 | - throw QPDFExc( | |
| 1627 | - qpdf_e_damaged_pdf, | |
| 1628 | - input->getName(), | |
| 1629 | - this->m->last_object_description, | |
| 1513 | + throw damagedPDF( | |
| 1514 | + input, | |
| 1630 | 1515 | offset, |
| 1631 | 1516 | "/Length key in stream dictionary is not " |
| 1632 | 1517 | "an integer"); |
| ... | ... | @@ -1640,12 +1525,8 @@ QPDF::readObject( |
| 1640 | 1525 | QPDFTokenizer::Token( |
| 1641 | 1526 | QPDFTokenizer::tt_word, "endstream"))) { |
| 1642 | 1527 | QTC::TC("qpdf", "QPDF missing endstream"); |
| 1643 | - throw QPDFExc( | |
| 1644 | - qpdf_e_damaged_pdf, | |
| 1645 | - input->getName(), | |
| 1646 | - this->m->last_object_description, | |
| 1647 | - input->getLastOffset(), | |
| 1648 | - "expected endstream"); | |
| 1528 | + throw damagedPDF( | |
| 1529 | + input, input->getLastOffset(), "expected endstream"); | |
| 1649 | 1530 | } |
| 1650 | 1531 | } catch (QPDFExc& e) { |
| 1651 | 1532 | if (this->m->attempt_recovery) { |
| ... | ... | @@ -1689,12 +1570,8 @@ QPDF::recoverStreamLength( |
| 1689 | 1570 | { |
| 1690 | 1571 | // Try to reconstruct stream length by looking for |
| 1691 | 1572 | // endstream or endobj |
| 1692 | - warn(QPDFExc( | |
| 1693 | - qpdf_e_damaged_pdf, | |
| 1694 | - input->getName(), | |
| 1695 | - this->m->last_object_description, | |
| 1696 | - stream_offset, | |
| 1697 | - "attempting to recover stream length")); | |
| 1573 | + warn(damagedPDF( | |
| 1574 | + input, stream_offset, "attempting to recover stream length")); | |
| 1698 | 1575 | |
| 1699 | 1576 | PatternFinder ef(*this, &QPDF::findEndstream); |
| 1700 | 1577 | size_t length = 0; |
| ... | ... | @@ -1734,18 +1611,13 @@ QPDF::recoverStreamLength( |
| 1734 | 1611 | } |
| 1735 | 1612 | |
| 1736 | 1613 | if (length == 0) { |
| 1737 | - warn(QPDFExc( | |
| 1738 | - qpdf_e_damaged_pdf, | |
| 1739 | - input->getName(), | |
| 1740 | - this->m->last_object_description, | |
| 1614 | + warn(damagedPDF( | |
| 1615 | + input, | |
| 1741 | 1616 | stream_offset, |
| 1742 | - "unable to recover stream data;" | |
| 1743 | - " treating stream as empty")); | |
| 1617 | + "unable to recover stream data; treating stream as empty")); | |
| 1744 | 1618 | } else { |
| 1745 | - warn(QPDFExc( | |
| 1746 | - qpdf_e_damaged_pdf, | |
| 1747 | - input->getName(), | |
| 1748 | - this->m->last_object_description, | |
| 1619 | + warn(damagedPDF( | |
| 1620 | + input, | |
| 1749 | 1621 | stream_offset, |
| 1750 | 1622 | "recovered stream length: " + std::to_string(length))); |
| 1751 | 1623 | } |
| ... | ... | @@ -1795,11 +1667,7 @@ QPDF::readObjectAtOffset( |
| 1795 | 1667 | // ignore these. |
| 1796 | 1668 | if (offset == 0) { |
| 1797 | 1669 | QTC::TC("qpdf", "QPDF bogus 0 offset", 0); |
| 1798 | - warn( | |
| 1799 | - qpdf_e_damaged_pdf, | |
| 1800 | - this->m->last_object_description, | |
| 1801 | - 0, | |
| 1802 | - "object has offset 0"); | |
| 1670 | + warn(damagedPDF(0, "object has offset 0")); | |
| 1803 | 1671 | return QPDFObjectHandle::newNull(); |
| 1804 | 1672 | } |
| 1805 | 1673 | |
| ... | ... | @@ -1820,33 +1688,19 @@ QPDF::readObjectAtOffset( |
| 1820 | 1688 | try { |
| 1821 | 1689 | if (!(objidok && genok && objok)) { |
| 1822 | 1690 | QTC::TC("qpdf", "QPDF expected n n obj"); |
| 1823 | - throw QPDFExc( | |
| 1824 | - qpdf_e_damaged_pdf, | |
| 1825 | - this->m->file->getName(), | |
| 1826 | - this->m->last_object_description, | |
| 1827 | - offset, | |
| 1828 | - "expected n n obj"); | |
| 1691 | + throw damagedPDF(offset, "expected n n obj"); | |
| 1829 | 1692 | } |
| 1830 | 1693 | int objid = QUtil::string_to_int(tobjid.getValue().c_str()); |
| 1831 | 1694 | int generation = QUtil::string_to_int(tgen.getValue().c_str()); |
| 1832 | 1695 | og = QPDFObjGen(objid, generation); |
| 1833 | 1696 | if (objid == 0) { |
| 1834 | 1697 | QTC::TC("qpdf", "QPDF object id 0"); |
| 1835 | - throw QPDFExc( | |
| 1836 | - qpdf_e_damaged_pdf, | |
| 1837 | - this->m->file->getName(), | |
| 1838 | - this->m->last_object_description, | |
| 1839 | - offset, | |
| 1840 | - "object with ID 0"); | |
| 1698 | + throw damagedPDF(offset, "object with ID 0"); | |
| 1841 | 1699 | } |
| 1842 | 1700 | if (check_og && (exp_og != og)) { |
| 1843 | 1701 | QTC::TC("qpdf", "QPDF err wrong objid/generation"); |
| 1844 | - QPDFExc e( | |
| 1845 | - qpdf_e_damaged_pdf, | |
| 1846 | - this->m->file->getName(), | |
| 1847 | - this->m->last_object_description, | |
| 1848 | - offset, | |
| 1849 | - (std::string("expected ") + exp_og.unparse(' ') + " obj")); | |
| 1702 | + QPDFExc e = | |
| 1703 | + damagedPDF(offset, "expected " + exp_og.unparse(' ') + " obj"); | |
| 1850 | 1704 | if (try_recovery) { |
| 1851 | 1705 | // Will be retried below |
| 1852 | 1706 | throw e; |
| ... | ... | @@ -1870,14 +1724,12 @@ QPDF::readObjectAtOffset( |
| 1870 | 1724 | return result; |
| 1871 | 1725 | } else { |
| 1872 | 1726 | QTC::TC("qpdf", "QPDF object gone after xref reconstruction"); |
| 1873 | - warn( | |
| 1874 | - qpdf_e_damaged_pdf, | |
| 1727 | + warn(damagedPDF( | |
| 1875 | 1728 | "", |
| 1876 | 1729 | 0, |
| 1877 | - std::string( | |
| 1878 | - "object " + exp_og.unparse(' ') + | |
| 1879 | - " not found in file after regenerating" | |
| 1880 | - " cross reference table")); | |
| 1730 | + ("object " + exp_og.unparse(' ') + | |
| 1731 | + " not found in file after regenerating cross reference " | |
| 1732 | + "table"))); | |
| 1881 | 1733 | return QPDFObjectHandle::newNull(); |
| 1882 | 1734 | } |
| 1883 | 1735 | } else { |
| ... | ... | @@ -1890,11 +1742,7 @@ QPDF::readObjectAtOffset( |
| 1890 | 1742 | if (!(readToken(this->m->file) == |
| 1891 | 1743 | QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) { |
| 1892 | 1744 | QTC::TC("qpdf", "QPDF err expected endobj"); |
| 1893 | - warn( | |
| 1894 | - qpdf_e_damaged_pdf, | |
| 1895 | - this->m->last_object_description, | |
| 1896 | - this->m->file->getLastOffset(), | |
| 1897 | - "expected endobj"); | |
| 1745 | + warn(damagedPDF("expected endobj")); | |
| 1898 | 1746 | } |
| 1899 | 1747 | |
| 1900 | 1748 | if (isUnresolved(og)) { |
| ... | ... | @@ -1919,12 +1767,7 @@ QPDF::readObjectAtOffset( |
| 1919 | 1767 | break; |
| 1920 | 1768 | } |
| 1921 | 1769 | } else { |
| 1922 | - throw QPDFExc( | |
| 1923 | - qpdf_e_damaged_pdf, | |
| 1924 | - this->m->file->getName(), | |
| 1925 | - this->m->last_object_description, | |
| 1926 | - this->m->file->tell(), | |
| 1927 | - "EOF after endobj"); | |
| 1770 | + throw damagedPDF(m->file->tell(), "EOF after endobj"); | |
| 1928 | 1771 | } |
| 1929 | 1772 | } |
| 1930 | 1773 | qpdf_offset_t end_after_space = this->m->file->tell(); |
| ... | ... | @@ -1950,11 +1793,8 @@ QPDF::resolve(QPDFObjGen const& og) |
| 1950 | 1793 | // indirectly in some key that has to be resolved during |
| 1951 | 1794 | // object parsing, such as stream length. |
| 1952 | 1795 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); |
| 1953 | - warn( | |
| 1954 | - qpdf_e_damaged_pdf, | |
| 1955 | - "", | |
| 1956 | - this->m->file->getLastOffset(), | |
| 1957 | - ("loop detected resolving object " + og.unparse(' '))); | |
| 1796 | + warn(damagedPDF( | |
| 1797 | + "", "loop detected resolving object " + og.unparse(' '))); | |
| 1958 | 1798 | updateCache(og, QPDF_Null::create(), -1, -1); |
| 1959 | 1799 | return; |
| 1960 | 1800 | } |
| ... | ... | @@ -1979,9 +1819,7 @@ QPDF::resolve(QPDFObjGen const& og) |
| 1979 | 1819 | break; |
| 1980 | 1820 | |
| 1981 | 1821 | default: |
| 1982 | - throw QPDFExc( | |
| 1983 | - qpdf_e_damaged_pdf, | |
| 1984 | - this->m->file->getName(), | |
| 1822 | + throw damagedPDF( | |
| 1985 | 1823 | "", |
| 1986 | 1824 | 0, |
| 1987 | 1825 | ("object " + og.unparse('/') + |
| ... | ... | @@ -1990,12 +1828,11 @@ QPDF::resolve(QPDFObjGen const& og) |
| 1990 | 1828 | } catch (QPDFExc& e) { |
| 1991 | 1829 | warn(e); |
| 1992 | 1830 | } catch (std::exception& e) { |
| 1993 | - warn( | |
| 1994 | - qpdf_e_damaged_pdf, | |
| 1831 | + warn(damagedPDF( | |
| 1995 | 1832 | "", |
| 1996 | 1833 | 0, |
| 1997 | 1834 | ("object " + og.unparse('/') + |
| 1998 | - ": error reading object: " + e.what())); | |
| 1835 | + ": error reading object: " + e.what()))); | |
| 1999 | 1836 | } |
| 2000 | 1837 | } |
| 2001 | 1838 | |
| ... | ... | @@ -2021,13 +1858,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 2021 | 1858 | // Force resolution of object stream |
| 2022 | 1859 | QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0); |
| 2023 | 1860 | if (!obj_stream.isStream()) { |
| 2024 | - throw QPDFExc( | |
| 2025 | - qpdf_e_damaged_pdf, | |
| 2026 | - this->m->file->getName(), | |
| 2027 | - this->m->last_object_description, | |
| 2028 | - this->m->file->getLastOffset(), | |
| 2029 | - ("supposed object stream " + std::to_string(obj_stream_number) + | |
| 2030 | - " is not a stream")); | |
| 1861 | + throw damagedPDF( | |
| 1862 | + "supposed object stream " + std::to_string(obj_stream_number) + | |
| 1863 | + " is not a stream"); | |
| 2031 | 1864 | } |
| 2032 | 1865 | |
| 2033 | 1866 | // For linearization data in the object, use the data from the |
| ... | ... | @@ -2041,20 +1874,13 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 2041 | 1874 | QPDFObjectHandle dict = obj_stream.getDict(); |
| 2042 | 1875 | if (!dict.isDictionaryOfType("/ObjStm")) { |
| 2043 | 1876 | QTC::TC("qpdf", "QPDF ERR object stream with wrong type"); |
| 2044 | - warn( | |
| 2045 | - qpdf_e_damaged_pdf, | |
| 2046 | - this->m->last_object_description, | |
| 2047 | - this->m->file->getLastOffset(), | |
| 2048 | - ("supposed object stream " + std::to_string(obj_stream_number) + | |
| 2049 | - " has wrong type")); | |
| 1877 | + warn(damagedPDF( | |
| 1878 | + "supposed object stream " + std::to_string(obj_stream_number) + | |
| 1879 | + " has wrong type")); | |
| 2050 | 1880 | } |
| 2051 | 1881 | |
| 2052 | 1882 | if (!(dict.getKey("/N").isInteger() && dict.getKey("/First").isInteger())) { |
| 2053 | - throw QPDFExc( | |
| 2054 | - qpdf_e_damaged_pdf, | |
| 2055 | - this->m->file->getName(), | |
| 2056 | - this->m->last_object_description, | |
| 2057 | - this->m->file->getLastOffset(), | |
| 1883 | + throw damagedPDF( | |
| 2058 | 1884 | ("object stream " + std::to_string(obj_stream_number) + |
| 2059 | 1885 | " has incorrect keys")); |
| 2060 | 1886 | } |
| ... | ... | @@ -2077,10 +1903,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 2077 | 1903 | QPDFTokenizer::Token toffset = readToken(input); |
| 2078 | 1904 | if (!((tnum.getType() == QPDFTokenizer::tt_integer) && |
| 2079 | 1905 | (toffset.getType() == QPDFTokenizer::tt_integer))) { |
| 2080 | - throw QPDFExc( | |
| 2081 | - qpdf_e_damaged_pdf, | |
| 2082 | - input->getName(), | |
| 2083 | - this->m->last_object_description, | |
| 1906 | + throw damagedPDF( | |
| 1907 | + input, | |
| 2084 | 1908 | input->getLastOffset(), |
| 2085 | 1909 | "expected integer in object stream header"); |
| 2086 | 1910 | } |
| ... | ... | @@ -2618,12 +2442,7 @@ QPDF::getRoot() |
| 2618 | 2442 | { |
| 2619 | 2443 | QPDFObjectHandle root = this->m->trailer.getKey("/Root"); |
| 2620 | 2444 | if (!root.isDictionary()) { |
| 2621 | - throw QPDFExc( | |
| 2622 | - qpdf_e_damaged_pdf, | |
| 2623 | - this->m->file->getName(), | |
| 2624 | - "", | |
| 2625 | - 0, | |
| 2626 | - "unable to find /Root dictionary"); | |
| 2445 | + throw damagedPDF("", 0, "unable to find /Root dictionary"); | |
| 2627 | 2446 | } |
| 2628 | 2447 | return root; |
| 2629 | 2448 | } |
| ... | ... | @@ -2751,9 +2570,8 @@ QPDF::pipeStreamData( |
| 2751 | 2570 | size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length); |
| 2752 | 2571 | size_t len = file->read(buf, to_read); |
| 2753 | 2572 | if (len == 0) { |
| 2754 | - throw QPDFExc( | |
| 2755 | - qpdf_e_damaged_pdf, | |
| 2756 | - file->getName(), | |
| 2573 | + throw damagedPDF( | |
| 2574 | + file, | |
| 2757 | 2575 | "", |
| 2758 | 2576 | file->getLastOffset(), |
| 2759 | 2577 | "unexpected EOF reading stream data"); |
| ... | ... | @@ -2772,9 +2590,8 @@ QPDF::pipeStreamData( |
| 2772 | 2590 | QTC::TC("qpdf", "QPDF decoding error warning"); |
| 2773 | 2591 | qpdf_for_warning.warn( |
| 2774 | 2592 | // line-break |
| 2775 | - QPDFExc( | |
| 2776 | - qpdf_e_damaged_pdf, | |
| 2777 | - file->getName(), | |
| 2593 | + damagedPDF( | |
| 2594 | + file, | |
| 2778 | 2595 | "", |
| 2779 | 2596 | file->getLastOffset(), |
| 2780 | 2597 | ("error decoding stream data for object " + |
| ... | ... | @@ -2782,9 +2599,8 @@ QPDF::pipeStreamData( |
| 2782 | 2599 | if (will_retry) { |
| 2783 | 2600 | qpdf_for_warning.warn( |
| 2784 | 2601 | // line-break |
| 2785 | - QPDFExc( | |
| 2786 | - qpdf_e_damaged_pdf, | |
| 2787 | - file->getName(), | |
| 2602 | + damagedPDF( | |
| 2603 | + file, | |
| 2788 | 2604 | "", |
| 2789 | 2605 | file->getLastOffset(), |
| 2790 | 2606 | "stream will be re-processed without" |
| ... | ... | @@ -2848,18 +2664,72 @@ QPDF::pipeForeignStreamData( |
| 2848 | 2664 | will_retry); |
| 2849 | 2665 | } |
| 2850 | 2666 | |
| 2667 | +// Throw a generic exception when we lack context for something | |
| 2668 | +// more specific. New code should not use this. This method exists | |
| 2669 | +// to improve somewhat from calling assert in very old code. | |
| 2851 | 2670 | void |
| 2852 | 2671 | QPDF::stopOnError(std::string const& message) |
| 2853 | 2672 | { |
| 2854 | - // Throw a generic exception when we lack context for something | |
| 2855 | - // more specific. New code should not use this. This method exists | |
| 2856 | - // to improve somewhat from calling assert in very old code. | |
| 2857 | - throw QPDFExc( | |
| 2858 | - qpdf_e_damaged_pdf, | |
| 2859 | - this->m->file->getName(), | |
| 2860 | - "", | |
| 2861 | - this->m->file->getLastOffset(), | |
| 2862 | - message); | |
| 2673 | + throw damagedPDF("", message); | |
| 2674 | +} | |
| 2675 | + | |
| 2676 | +// Return an exception of type qpdf_e_damaged_pdf. | |
| 2677 | +QPDFExc | |
| 2678 | +QPDF::damagedPDF( | |
| 2679 | + std::shared_ptr<InputSource> const& input, | |
| 2680 | + std::string const& object, | |
| 2681 | + qpdf_offset_t offset, | |
| 2682 | + std::string const& message) | |
| 2683 | +{ | |
| 2684 | + return QPDFExc( | |
| 2685 | + qpdf_e_damaged_pdf, input->getName(), object, offset, message); | |
| 2686 | +} | |
| 2687 | + | |
| 2688 | +// Return an exception of type qpdf_e_damaged_pdf. The object is taken from | |
| 2689 | +// m->last_object_description. | |
| 2690 | +QPDFExc | |
| 2691 | +QPDF::damagedPDF( | |
| 2692 | + std::shared_ptr<InputSource> const& input, | |
| 2693 | + qpdf_offset_t offset, | |
| 2694 | + std::string const& message) | |
| 2695 | +{ | |
| 2696 | + return damagedPDF(input, m->last_object_description, offset, message); | |
| 2697 | +} | |
| 2698 | + | |
| 2699 | +// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from | |
| 2700 | +// m->file. | |
| 2701 | +QPDFExc | |
| 2702 | +QPDF::damagedPDF( | |
| 2703 | + std::string const& object, qpdf_offset_t offset, std::string const& message) | |
| 2704 | +{ | |
| 2705 | + return QPDFExc( | |
| 2706 | + qpdf_e_damaged_pdf, m->file->getName(), object, offset, message); | |
| 2707 | +} | |
| 2708 | + | |
| 2709 | +// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from | |
| 2710 | +// m->file and the offset from .m->file->getLastOffset(). | |
| 2711 | +QPDFExc | |
| 2712 | +QPDF::damagedPDF(std::string const& object, std::string const& message) | |
| 2713 | +{ | |
| 2714 | + return damagedPDF(object, m->file->getLastOffset(), message); | |
| 2715 | +} | |
| 2716 | + | |
| 2717 | +// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from | |
| 2718 | +// m->file and the object from .m->last_object_description. | |
| 2719 | +QPDFExc | |
| 2720 | +QPDF::damagedPDF(qpdf_offset_t offset, std::string const& message) | |
| 2721 | +{ | |
| 2722 | + return damagedPDF(m->last_object_description, offset, message); | |
| 2723 | +} | |
| 2724 | + | |
| 2725 | +// Return an exception of type qpdf_e_damaged_pdf. The filename is taken from | |
| 2726 | +// m->file, the object from m->last_object_description and the offset from | |
| 2727 | +// m->file->getLastOffset(). | |
| 2728 | +QPDFExc | |
| 2729 | +QPDF::damagedPDF(std::string const& message) | |
| 2730 | +{ | |
| 2731 | + return damagedPDF( | |
| 2732 | + m->last_object_description, m->file->getLastOffset(), message); | |
| 2863 | 2733 | } |
| 2864 | 2734 | |
| 2865 | 2735 | bool | ... | ... |
libqpdf/QPDF_encryption.cc
| ... | ... | @@ -804,21 +804,12 @@ QPDF::initializeEncryption() |
| 804 | 804 | // Treating a missing ID as the empty string enables qpdf to |
| 805 | 805 | // decrypt some invalid encrypted files with no /ID that |
| 806 | 806 | // poppler can read but Adobe Reader can't. |
| 807 | - warn( | |
| 808 | - qpdf_e_damaged_pdf, | |
| 809 | - "trailer", | |
| 810 | - this->m->file->getLastOffset(), | |
| 811 | - "invalid /ID in trailer dictionary"); | |
| 807 | + warn(damagedPDF("trailer", "invalid /ID in trailer dictionary")); | |
| 812 | 808 | } |
| 813 | 809 | |
| 814 | 810 | QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt"); |
| 815 | 811 | if (!encryption_dict.isDictionary()) { |
| 816 | - throw QPDFExc( | |
| 817 | - qpdf_e_damaged_pdf, | |
| 818 | - this->m->file->getName(), | |
| 819 | - this->m->last_object_description, | |
| 820 | - this->m->file->getLastOffset(), | |
| 821 | - "/Encrypt in trailer dictionary is not a dictionary"); | |
| 812 | + throw damagedPDF("/Encrypt in trailer dictionary is not a dictionary"); | |
| 822 | 813 | } |
| 823 | 814 | |
| 824 | 815 | if (!(encryption_dict.getKey("/Filter").isName() && |
| ... | ... | @@ -835,8 +826,7 @@ QPDF::initializeEncryption() |
| 835 | 826 | qpdf_e_unsupported, |
| 836 | 827 | "encryption dictionary", |
| 837 | 828 | this->m->file->getLastOffset(), |
| 838 | - "file uses encryption SubFilters," | |
| 839 | - " which qpdf does not support"); | |
| 829 | + "file uses encryption SubFilters, which qpdf does not support"); | |
| 840 | 830 | } |
| 841 | 831 | |
| 842 | 832 | if (!(encryption_dict.getKey("/V").isInteger() && |
| ... | ... | @@ -844,13 +834,10 @@ QPDF::initializeEncryption() |
| 844 | 834 | encryption_dict.getKey("/O").isString() && |
| 845 | 835 | encryption_dict.getKey("/U").isString() && |
| 846 | 836 | encryption_dict.getKey("/P").isInteger())) { |
| 847 | - throw QPDFExc( | |
| 848 | - qpdf_e_damaged_pdf, | |
| 849 | - this->m->file->getName(), | |
| 837 | + throw damagedPDF( | |
| 850 | 838 | "encryption dictionary", |
| 851 | - this->m->file->getLastOffset(), | |
| 852 | - "some encryption dictionary parameters are missing " | |
| 853 | - "or the wrong type"); | |
| 839 | + "some encryption dictionary parameters are missing or the wrong " | |
| 840 | + "type"); | |
| 854 | 841 | } |
| 855 | 842 | |
| 856 | 843 | int V = encryption_dict.getKey("/V").getIntValueAsInt(); |
| ... | ... | @@ -886,25 +873,18 @@ QPDF::initializeEncryption() |
| 886 | 873 | pad_short_parameter(O, key_bytes); |
| 887 | 874 | pad_short_parameter(U, key_bytes); |
| 888 | 875 | if (!((O.length() == key_bytes) && (U.length() == key_bytes))) { |
| 889 | - throw QPDFExc( | |
| 890 | - qpdf_e_damaged_pdf, | |
| 891 | - this->m->file->getName(), | |
| 876 | + throw damagedPDF( | |
| 892 | 877 | "encryption dictionary", |
| 893 | - this->m->file->getLastOffset(), | |
| 894 | - "incorrect length for /O and/or /U in " | |
| 895 | - "encryption dictionary"); | |
| 878 | + "incorrect length for /O and/or /U in encryption dictionary"); | |
| 896 | 879 | } |
| 897 | 880 | } else { |
| 898 | 881 | if (!(encryption_dict.getKey("/OE").isString() && |
| 899 | 882 | encryption_dict.getKey("/UE").isString() && |
| 900 | 883 | encryption_dict.getKey("/Perms").isString())) { |
| 901 | - throw QPDFExc( | |
| 902 | - qpdf_e_damaged_pdf, | |
| 903 | - this->m->file->getName(), | |
| 884 | + throw damagedPDF( | |
| 904 | 885 | "encryption dictionary", |
| 905 | - this->m->file->getLastOffset(), | |
| 906 | - "some V=5 encryption dictionary parameters are " | |
| 907 | - "missing or the wrong type"); | |
| 886 | + "some V=5 encryption dictionary parameters are missing or the " | |
| 887 | + "wrong type"); | |
| 908 | 888 | } |
| 909 | 889 | OE = encryption_dict.getKey("/OE").getStringValue(); |
| 910 | 890 | UE = encryption_dict.getKey("/UE").getStringValue(); |
| ... | ... | @@ -1062,12 +1042,10 @@ QPDF::initializeEncryption() |
| 1062 | 1042 | this->m->encp->encryption_key = recover_encryption_key_with_password( |
| 1063 | 1043 | this->m->encp->provided_password, data, perms_valid); |
| 1064 | 1044 | if (!perms_valid) { |
| 1065 | - warn( | |
| 1066 | - qpdf_e_damaged_pdf, | |
| 1045 | + warn(damagedPDF( | |
| 1067 | 1046 | "encryption dictionary", |
| 1068 | - this->m->file->getLastOffset(), | |
| 1069 | - "/Perms field in encryption dictionary" | |
| 1070 | - " doesn't match expected value"); | |
| 1047 | + "/Perms field in encryption dictionary doesn't match expected " | |
| 1048 | + "value")); | |
| 1071 | 1049 | } |
| 1072 | 1050 | } |
| 1073 | 1051 | } |
| ... | ... | @@ -1121,13 +1099,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) |
| 1121 | 1099 | break; |
| 1122 | 1100 | |
| 1123 | 1101 | default: |
| 1124 | - warn( | |
| 1125 | - qpdf_e_damaged_pdf, | |
| 1126 | - this->m->last_object_description, | |
| 1127 | - this->m->file->getLastOffset(), | |
| 1128 | - "unknown encryption filter for strings" | |
| 1129 | - " (check /StrF in /Encrypt dictionary);" | |
| 1130 | - " strings may be decrypted improperly"); | |
| 1102 | + warn(damagedPDF( | |
| 1103 | + "unknown encryption filter for strings (check /StrF in " | |
| 1104 | + "/Encrypt dictionary); strings may be decrypted improperly")); | |
| 1131 | 1105 | // To avoid repeated warnings, reset cf_string. Assume |
| 1132 | 1106 | // we'd want to use AES if V == 4. |
| 1133 | 1107 | this->m->encp->cf_string = e_aes; |
| ... | ... | @@ -1166,13 +1140,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) |
| 1166 | 1140 | } catch (QPDFExc&) { |
| 1167 | 1141 | throw; |
| 1168 | 1142 | } catch (std::runtime_error& e) { |
| 1169 | - throw QPDFExc( | |
| 1170 | - qpdf_e_damaged_pdf, | |
| 1171 | - this->m->file->getName(), | |
| 1172 | - this->m->last_object_description, | |
| 1173 | - this->m->file->getLastOffset(), | |
| 1143 | + throw damagedPDF( | |
| 1174 | 1144 | "error decrypting string for object " + og.unparse() + ": " + |
| 1175 | - e.what()); | |
| 1145 | + e.what()); | |
| 1176 | 1146 | } |
| 1177 | 1147 | } |
| 1178 | 1148 | |
| ... | ... | @@ -1265,11 +1235,8 @@ QPDF::decryptStream( |
| 1265 | 1235 | file->getName(), |
| 1266 | 1236 | "", |
| 1267 | 1237 | file->getLastOffset(), |
| 1268 | - "unknown encryption filter for streams" | |
| 1269 | - " (check " + | |
| 1270 | - method_source + | |
| 1271 | - ");" | |
| 1272 | - " streams may be decrypted improperly")); | |
| 1238 | + "unknown encryption filter for streams (check " + | |
| 1239 | + method_source + "); streams may be decrypted improperly")); | |
| 1273 | 1240 | // To avoid repeated warnings, reset cf_stream. Assume |
| 1274 | 1241 | // we'd want to use AES if V == 4. |
| 1275 | 1242 | encp->cf_stream = e_aes; | ... | ... |
libqpdf/QPDF_linearization.cc
| ... | ... | @@ -186,24 +186,16 @@ QPDF::readLinearizationData() |
| 186 | 186 | |
| 187 | 187 | if (!(H.isArray() && O.isInteger() && E.isInteger() && N.isInteger() && |
| 188 | 188 | T.isInteger() && (P.isInteger() || P.isNull()))) { |
| 189 | - throw QPDFExc( | |
| 190 | - qpdf_e_damaged_pdf, | |
| 191 | - this->m->file->getName(), | |
| 189 | + throw damagedPDF( | |
| 192 | 190 | "linearization dictionary", |
| 193 | - this->m->file->getLastOffset(), | |
| 194 | - "some keys in linearization dictionary are of " | |
| 195 | - "the wrong type"); | |
| 191 | + "some keys in linearization dictionary are of the wrong type"); | |
| 196 | 192 | } |
| 197 | 193 | |
| 198 | 194 | // Hint table array: offset length [ offset length ] |
| 199 | 195 | size_t n_H_items = toS(H.getArrayNItems()); |
| 200 | 196 | if (!((n_H_items == 2) || (n_H_items == 4))) { |
| 201 | - throw QPDFExc( | |
| 202 | - qpdf_e_damaged_pdf, | |
| 203 | - this->m->file->getName(), | |
| 204 | - "linearization dictionary", | |
| 205 | - this->m->file->getLastOffset(), | |
| 206 | - "H has the wrong number of items"); | |
| 197 | + throw damagedPDF( | |
| 198 | + "linearization dictionary", "H has the wrong number of items"); | |
| 207 | 199 | } |
| 208 | 200 | |
| 209 | 201 | std::vector<int> H_items; |
| ... | ... | @@ -212,11 +204,8 @@ QPDF::readLinearizationData() |
| 212 | 204 | if (oh.isInteger()) { |
| 213 | 205 | H_items.push_back(oh.getIntValueAsInt()); |
| 214 | 206 | } else { |
| 215 | - throw QPDFExc( | |
| 216 | - qpdf_e_damaged_pdf, | |
| 217 | - this->m->file->getName(), | |
| 207 | + throw damagedPDF( | |
| 218 | 208 | "linearization dictionary", |
| 219 | - this->m->file->getLastOffset(), | |
| 220 | 209 | "some H items are of the wrong type"); |
| 221 | 210 | } |
| 222 | 211 | } |
| ... | ... | @@ -249,12 +238,8 @@ QPDF::readLinearizationData() |
| 249 | 238 | // initialized from N, to pre-allocate memory, so make sure it's |
| 250 | 239 | // accurate and bail right now if it's not. |
| 251 | 240 | if (N.getIntValue() != static_cast<long long>(getAllPages().size())) { |
| 252 | - throw QPDFExc( | |
| 253 | - qpdf_e_damaged_pdf, | |
| 254 | - this->m->file->getName(), | |
| 255 | - "linearization hint table", | |
| 256 | - this->m->file->getLastOffset(), | |
| 257 | - "/N does not match number of pages"); | |
| 241 | + throw damagedPDF( | |
| 242 | + "linearization hint table", "/N does not match number of pages"); | |
| 258 | 243 | } |
| 259 | 244 | |
| 260 | 245 | // file_size initialized by isLinearized() |
| ... | ... | @@ -297,11 +282,8 @@ QPDF::readLinearizationData() |
| 297 | 282 | |
| 298 | 283 | int HSi = HS.getIntValueAsInt(); |
| 299 | 284 | if ((HSi < 0) || (toS(HSi) >= h_size)) { |
| 300 | - throw QPDFExc( | |
| 301 | - qpdf_e_damaged_pdf, | |
| 302 | - this->m->file->getName(), | |
| 285 | + throw damagedPDF( | |
| 303 | 286 | "linearization hint table", |
| 304 | - this->m->file->getLastOffset(), | |
| 305 | 287 | "/S (shared object) offset is out of bounds"); |
| 306 | 288 | } |
| 307 | 289 | readHSharedObject(BitStream(h_buf + HSi, h_size - toS(HSi))); |
| ... | ... | @@ -309,11 +291,8 @@ QPDF::readLinearizationData() |
| 309 | 291 | if (HO.isInteger()) { |
| 310 | 292 | int HOi = HO.getIntValueAsInt(); |
| 311 | 293 | if ((HOi < 0) || (toS(HOi) >= h_size)) { |
| 312 | - throw QPDFExc( | |
| 313 | - qpdf_e_damaged_pdf, | |
| 314 | - this->m->file->getName(), | |
| 294 | + throw damagedPDF( | |
| 315 | 295 | "linearization hint table", |
| 316 | - this->m->file->getLastOffset(), | |
| 317 | 296 | "/O (outline) offset is out of bounds"); |
| 318 | 297 | } |
| 319 | 298 | readHGeneric( |
| ... | ... | @@ -331,12 +310,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) |
| 331 | 310 | qpdf_offset_t min_end_offset = oc.end_before_space; |
| 332 | 311 | qpdf_offset_t max_end_offset = oc.end_after_space; |
| 333 | 312 | if (!H.isStream()) { |
| 334 | - throw QPDFExc( | |
| 335 | - qpdf_e_damaged_pdf, | |
| 336 | - this->m->file->getName(), | |
| 337 | - "linearization dictionary", | |
| 338 | - this->m->file->getLastOffset(), | |
| 339 | - "hint table is not a stream"); | |
| 313 | + throw damagedPDF( | |
| 314 | + "linearization dictionary", "hint table is not a stream"); | |
| 340 | 315 | } |
| 341 | 316 | |
| 342 | 317 | QPDFObjectHandle Hdict = H.getDict(); |
| ... | ... | @@ -362,12 +337,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) |
| 362 | 337 | *this->m->log->getError() |
| 363 | 338 | << "expected = " << computed_end << "; actual = " << min_end_offset |
| 364 | 339 | << ".." << max_end_offset << "\n"; |
| 365 | - throw QPDFExc( | |
| 366 | - qpdf_e_damaged_pdf, | |
| 367 | - this->m->file->getName(), | |
| 368 | - "linearization dictionary", | |
| 369 | - this->m->file->getLastOffset(), | |
| 370 | - "hint table length mismatch"); | |
| 340 | + throw damagedPDF( | |
| 341 | + "linearization dictionary", "hint table length mismatch"); | |
| 371 | 342 | } |
| 372 | 343 | H.pipeStreamData(&pl, 0, qpdf_dl_specialized); |
| 373 | 344 | return Hdict; | ... | ... |