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,6 +1194,22 @@ class QPDF | ||
| 1194 | std::shared_ptr<QPDFObject> const& object, | 1194 | std::shared_ptr<QPDFObject> const& object, |
| 1195 | qpdf_offset_t end_before_space, | 1195 | qpdf_offset_t end_before_space, |
| 1196 | qpdf_offset_t end_after_space); | 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 | // Calls finish() on the pipeline when done but does not delete it | 1214 | // Calls finish() on the pipeline when done but does not delete it |
| 1199 | bool pipeStreamData( | 1215 | bool pipeStreamData( |
libqpdf/QPDF.cc
| @@ -481,7 +481,7 @@ QPDF::parse(char const* password) | @@ -481,7 +481,7 @@ QPDF::parse(char const* password) | ||
| 481 | PatternFinder hf(*this, &QPDF::findHeader); | 481 | PatternFinder hf(*this, &QPDF::findHeader); |
| 482 | if (!this->m->file->findFirst("%PDF-", 0, 1024, hf)) { | 482 | if (!this->m->file->findFirst("%PDF-", 0, 1024, hf)) { |
| 483 | QTC::TC("qpdf", "QPDF not a pdf file"); | 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 | // QPDFWriter writes files that usually require at least | 485 | // QPDFWriter writes files that usually require at least |
| 486 | // version 1.2 for /FlateDecode | 486 | // version 1.2 for /FlateDecode |
| 487 | this->m->pdf_version = "1.2"; | 487 | this->m->pdf_version = "1.2"; |
| @@ -503,24 +503,15 @@ QPDF::parse(char const* password) | @@ -503,24 +503,15 @@ QPDF::parse(char const* password) | ||
| 503 | try { | 503 | try { |
| 504 | if (xref_offset == 0) { | 504 | if (xref_offset == 0) { |
| 505 | QTC::TC("qpdf", "QPDF can't find startxref"); | 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 | try { | 508 | try { |
| 514 | read_xref(xref_offset); | 509 | read_xref(xref_offset); |
| 515 | } catch (QPDFExc&) { | 510 | } catch (QPDFExc&) { |
| 516 | throw; | 511 | throw; |
| 517 | } catch (std::exception& e) { | 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 | } catch (QPDFExc& e) { | 516 | } catch (QPDFExc& e) { |
| 526 | if (this->m->attempt_recovery) { | 517 | if (this->m->attempt_recovery) { |
| @@ -589,13 +580,9 @@ QPDF::reconstruct_xref(QPDFExc& e) | @@ -589,13 +580,9 @@ QPDF::reconstruct_xref(QPDFExc& e) | ||
| 589 | 580 | ||
| 590 | this->m->reconstructed_xref = true; | 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 | warn(e); | 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 | // Delete all references to type 1 (uncompressed) objects | 587 | // Delete all references to type 1 (uncompressed) objects |
| 601 | std::set<QPDFObjGen> to_delete; | 588 | std::set<QPDFObjGen> to_delete; |
| @@ -655,13 +642,10 @@ QPDF::reconstruct_xref(QPDFExc& e) | @@ -655,13 +642,10 @@ QPDF::reconstruct_xref(QPDFExc& e) | ||
| 655 | // with bad startxref pointers even when they have object | 642 | // with bad startxref pointers even when they have object |
| 656 | // streams. | 643 | // streams. |
| 657 | 644 | ||
| 658 | - throw QPDFExc( | ||
| 659 | - qpdf_e_damaged_pdf, | ||
| 660 | - this->m->file->getName(), | 645 | + throw damagedPDF( |
| 661 | "", | 646 | "", |
| 662 | 0, | 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 | // We could iterate through the objects looking for streams and | 651 | // We could iterate through the objects looking for streams and |
| @@ -716,11 +700,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -716,11 +700,8 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 716 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { | 700 | if ((strncmp(buf, "xref", 4) == 0) && QUtil::is_space(buf[4])) { |
| 717 | if (skipped_space) { | 701 | if (skipped_space) { |
| 718 | QTC::TC("qpdf", "QPDF xref skipped space"); | 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 | QTC::TC( | 706 | QTC::TC( |
| 726 | "qpdf", | 707 | "qpdf", |
| @@ -741,22 +722,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -741,22 +722,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 741 | } | 722 | } |
| 742 | if (visited.count(xref_offset) != 0) { | 723 | if (visited.count(xref_offset) != 0) { |
| 743 | QTC::TC("qpdf", "QPDF xref loop"); | 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 | if (!this->m->trailer.isInitialized()) { | 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 | int size = this->m->trailer.getKey("/Size").getIntValueAsInt(); | 732 | int size = this->m->trailer.getKey("/Size").getIntValueAsInt(); |
| 762 | int max_obj = 0; | 733 | int max_obj = 0; |
| @@ -768,14 +739,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | @@ -768,14 +739,12 @@ QPDF::read_xref(qpdf_offset_t xref_offset) | ||
| 768 | } | 739 | } |
| 769 | if ((size < 1) || (size - 1 != max_obj)) { | 740 | if ((size < 1) || (size - 1 != max_obj)) { |
| 770 | QTC::TC("qpdf", "QPDF xref size mismatch"); | 741 | QTC::TC("qpdf", "QPDF xref size mismatch"); |
| 771 | - warn( | ||
| 772 | - qpdf_e_damaged_pdf, | 742 | + warn(damagedPDF( |
| 773 | "", | 743 | "", |
| 774 | 0, | 744 | 0, |
| 775 | - (std::string("reported number of objects (") + | ||
| 776 | - std::to_string(size) + | 745 | + ("reported number of objects (" + std::to_string(size) + |
| 777 | ") is not one plus the highest object number (" + | 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 | // We no longer need the deleted_objects table, so go ahead and | 750 | // We no longer need the deleted_objects table, so go ahead and |
| @@ -899,11 +868,7 @@ QPDF::parse_xrefEntry( | @@ -899,11 +868,7 @@ QPDF::parse_xrefEntry( | ||
| 899 | } | 868 | } |
| 900 | 869 | ||
| 901 | if (invalid) { | 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 | f1 = QUtil::string_to_ll(f1_str.c_str()); | 874 | f1 = QUtil::string_to_ll(f1_str.c_str()); |
| @@ -929,12 +894,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -929,12 +894,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 929 | int bytes = 0; | 894 | int bytes = 0; |
| 930 | if (!parse_xrefFirst(line, obj, num, bytes)) { | 895 | if (!parse_xrefFirst(line, obj, num, bytes)) { |
| 931 | QTC::TC("qpdf", "QPDF invalid xref"); | 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 | this->m->file->seek(this->m->file->getLastOffset() + bytes, SEEK_SET); | 899 | this->m->file->seek(this->m->file->getLastOffset() + bytes, SEEK_SET); |
| 940 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { | 900 | for (qpdf_offset_t i = obj; i - num < obj; ++i) { |
| @@ -949,11 +909,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -949,11 +909,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 949 | char type = '\0'; | 909 | char type = '\0'; |
| 950 | if (!parse_xrefEntry(xref_entry, f1, f2, type)) { | 910 | if (!parse_xrefEntry(xref_entry, f1, f2, type)) { |
| 951 | QTC::TC("qpdf", "QPDF invalid xref entry"); | 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 | "xref table", | 913 | "xref table", |
| 956 | - this->m->file->getLastOffset(), | ||
| 957 | "invalid xref entry (obj=" + std::to_string(i) + ")"); | 914 | "invalid xref entry (obj=" + std::to_string(i) + ")"); |
| 958 | } | 915 | } |
| 959 | if (type == 'f') { | 916 | if (type == 'f') { |
| @@ -978,12 +935,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -978,12 +935,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 978 | readObject(this->m->file, "trailer", QPDFObjGen(), false); | 935 | readObject(this->m->file, "trailer", QPDFObjGen(), false); |
| 979 | if (!cur_trailer.isDictionary()) { | 936 | if (!cur_trailer.isDictionary()) { |
| 980 | QTC::TC("qpdf", "QPDF missing trailer"); | 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 | if (!this->m->trailer.isInitialized()) { | 941 | if (!this->m->trailer.isInitialized()) { |
| @@ -991,22 +943,12 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | @@ -991,22 +943,12 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 991 | 943 | ||
| 992 | if (!this->m->trailer.hasKey("/Size")) { | 944 | if (!this->m->trailer.hasKey("/Size")) { |
| 993 | QTC::TC("qpdf", "QPDF trailer lacks size"); | 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 | if (!this->m->trailer.getKey("/Size").isInteger()) { | 948 | if (!this->m->trailer.getKey("/Size").isInteger()) { |
| 1002 | QTC::TC("qpdf", "QPDF trailer size not integer"); | 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,12 +963,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 1021 | (void)read_xrefStream( | 963 | (void)read_xrefStream( |
| 1022 | cur_trailer.getKey("/XRefStm").getIntValue()); | 964 | cur_trailer.getKey("/XRefStm").getIntValue()); |
| 1023 | } else { | 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,13 +977,8 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) | ||
| 1039 | if (cur_trailer.hasKey("/Prev")) { | 977 | if (cur_trailer.hasKey("/Prev")) { |
| 1040 | if (!cur_trailer.getKey("/Prev").isInteger()) { | 978 | if (!cur_trailer.getKey("/Prev").isInteger()) { |
| 1041 | QTC::TC("qpdf", "QPDF trailer prev not integer"); | 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 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); | 983 | QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); |
| 1051 | xref_offset = cur_trailer.getKey("/Prev").getIntValue(); | 984 | xref_offset = cur_trailer.getKey("/Prev").getIntValue(); |
| @@ -1078,12 +1011,7 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) | @@ -1078,12 +1011,7 @@ QPDF::read_xrefStream(qpdf_offset_t xref_offset) | ||
| 1078 | 1011 | ||
| 1079 | if (!found) { | 1012 | if (!found) { |
| 1080 | QTC::TC("qpdf", "QPDF can't find xref"); | 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 | return xref_offset; | 1017 | return xref_offset; |
| @@ -1101,13 +1029,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1101,13 +1029,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1101 | W_obj.getArrayItem(2).isInteger() && | 1029 | W_obj.getArrayItem(2).isInteger() && |
| 1102 | dict.getKey("/Size").isInteger() && | 1030 | dict.getKey("/Size").isInteger() && |
| 1103 | (Index_obj.isArray() || Index_obj.isNull()))) { | 1031 | (Index_obj.isArray() || Index_obj.isNull()))) { |
| 1104 | - throw QPDFExc( | ||
| 1105 | - qpdf_e_damaged_pdf, | ||
| 1106 | - this->m->file->getName(), | 1032 | + throw damagedPDF( |
| 1107 | "xref stream", | 1033 | "xref stream", |
| 1108 | xref_offset, | 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 | int W[3]; | 1038 | int W[3]; |
| @@ -1116,24 +1041,18 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1116,24 +1041,18 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1116 | for (int i = 0; i < 3; ++i) { | 1041 | for (int i = 0; i < 3; ++i) { |
| 1117 | W[i] = W_obj.getArrayItem(i).getIntValueAsInt(); | 1042 | W[i] = W_obj.getArrayItem(i).getIntValueAsInt(); |
| 1118 | if (W[i] > max_bytes) { | 1043 | if (W[i] > max_bytes) { |
| 1119 | - throw QPDFExc( | ||
| 1120 | - qpdf_e_damaged_pdf, | ||
| 1121 | - this->m->file->getName(), | 1044 | + throw damagedPDF( |
| 1122 | "xref stream", | 1045 | "xref stream", |
| 1123 | xref_offset, | 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 | entry_size += toS(W[i]); | 1049 | entry_size += toS(W[i]); |
| 1128 | } | 1050 | } |
| 1129 | if (entry_size == 0) { | 1051 | if (entry_size == 0) { |
| 1130 | - throw QPDFExc( | ||
| 1131 | - qpdf_e_damaged_pdf, | ||
| 1132 | - this->m->file->getName(), | 1052 | + throw damagedPDF( |
| 1133 | "xref stream", | 1053 | "xref stream", |
| 1134 | xref_offset, | 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 | unsigned long long max_num_entries = | 1057 | unsigned long long max_num_entries = |
| 1139 | static_cast<unsigned long long>(-1) / entry_size; | 1058 | static_cast<unsigned long long>(-1) / entry_size; |
| @@ -1142,21 +1061,17 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1142,21 +1061,17 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1142 | if (Index_obj.isArray()) { | 1061 | if (Index_obj.isArray()) { |
| 1143 | int n_index = Index_obj.getArrayNItems(); | 1062 | int n_index = Index_obj.getArrayNItems(); |
| 1144 | if ((n_index % 2) || (n_index < 2)) { | 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 | "xref stream", | 1065 | "xref stream", |
| 1149 | xref_offset, | 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 | for (int i = 0; i < n_index; ++i) { | 1070 | for (int i = 0; i < n_index; ++i) { |
| 1154 | if (Index_obj.getArrayItem(i).isInteger()) { | 1071 | if (Index_obj.getArrayItem(i).isInteger()) { |
| 1155 | indx.push_back(Index_obj.getArrayItem(i).getIntValue()); | 1072 | indx.push_back(Index_obj.getArrayItem(i).getIntValue()); |
| 1156 | } else { | 1073 | } else { |
| 1157 | - throw QPDFExc( | ||
| 1158 | - qpdf_e_damaged_pdf, | ||
| 1159 | - this->m->file->getName(), | 1074 | + throw damagedPDF( |
| 1160 | "xref stream", | 1075 | "xref stream", |
| 1161 | xref_offset, | 1076 | xref_offset, |
| 1162 | ("Cross-reference stream's /Index's item " + | 1077 | ("Cross-reference stream's /Index's item " + |
| @@ -1174,13 +1089,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1174,13 +1089,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1174 | size_t num_entries = 0; | 1089 | size_t num_entries = 0; |
| 1175 | for (size_t i = 1; i < indx.size(); i += 2) { | 1090 | for (size_t i = 1; i < indx.size(); i += 2) { |
| 1176 | if (indx.at(i) > QIntC::to_longlong(max_num_entries - num_entries)) { | 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 | "xref stream", | 1093 | "xref stream", |
| 1181 | xref_offset, | 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 | std::to_string(indx.at(i)) + " " + | 1096 | std::to_string(indx.at(i)) + " " + |
| 1185 | std::to_string(max_num_entries) + " " + | 1097 | std::to_string(max_num_entries) + " " + |
| 1186 | std::to_string(num_entries))); | 1098 | std::to_string(num_entries))); |
| @@ -1196,13 +1108,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1196,13 +1108,10 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1196 | size_t actual_size = bp->getSize(); | 1108 | size_t actual_size = bp->getSize(); |
| 1197 | 1109 | ||
| 1198 | if (expected_size != actual_size) { | 1110 | if (expected_size != actual_size) { |
| 1199 | - QPDFExc x( | ||
| 1200 | - qpdf_e_damaged_pdf, | ||
| 1201 | - this->m->file->getName(), | 1111 | + QPDFExc x = damagedPDF( |
| 1202 | "xref stream", | 1112 | "xref stream", |
| 1203 | xref_offset, | 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 | std::to_string(expected_size) + | 1115 | std::to_string(expected_size) + |
| 1207 | "; actual = " + std::to_string(actual_size))); | 1116 | "; actual = " + std::to_string(actual_size))); |
| 1208 | if (expected_size > actual_size) { | 1117 | if (expected_size > actual_size) { |
| @@ -1286,13 +1195,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | @@ -1286,13 +1195,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) | ||
| 1286 | 1195 | ||
| 1287 | if (dict.hasKey("/Prev")) { | 1196 | if (dict.hasKey("/Prev")) { |
| 1288 | if (!dict.getKey("/Prev").isInteger()) { | 1197 | if (!dict.getKey("/Prev").isInteger()) { |
| 1289 | - throw QPDFExc( | ||
| 1290 | - qpdf_e_damaged_pdf, | ||
| 1291 | - this->m->file->getName(), | 1198 | + throw damagedPDF( |
| 1292 | "xref stream", | 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 | QTC::TC("qpdf", "QPDF prev key in xref stream dictionary"); | 1202 | QTC::TC("qpdf", "QPDF prev key in xref stream dictionary"); |
| 1298 | xref_offset = dict.getKey("/Prev").getIntValue(); | 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,11 +1256,8 @@ QPDF::insertXrefEntry(int obj, int f0, qpdf_offset_t f1, int f2, bool overwrite) | ||
| 1351 | break; | 1256 | break; |
| 1352 | 1257 | ||
| 1353 | default: | 1258 | default: |
| 1354 | - throw QPDFExc( | ||
| 1355 | - qpdf_e_damaged_pdf, | ||
| 1356 | - this->m->file->getName(), | 1259 | + throw damagedPDF( |
| 1357 | "xref stream", | 1260 | "xref stream", |
| 1358 | - this->m->file->getLastOffset(), | ||
| 1359 | "unknown xref stream entry type " + std::to_string(f0)); | 1261 | "unknown xref stream entry type " + std::to_string(f0)); |
| 1360 | break; | 1262 | break; |
| 1361 | } | 1263 | } |
| @@ -1522,12 +1424,8 @@ QPDF::readObject( | @@ -1522,12 +1424,8 @@ QPDF::readObject( | ||
| 1522 | // Nothing in the PDF spec appears to allow empty objects, but | 1424 | // Nothing in the PDF spec appears to allow empty objects, but |
| 1523 | // they have been encountered in actual PDF files and Adobe | 1425 | // they have been encountered in actual PDF files and Adobe |
| 1524 | // Reader appears to ignore them. | 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 | } else if (object.isDictionary() && (!in_object_stream)) { | 1429 | } else if (object.isDictionary() && (!in_object_stream)) { |
| 1532 | // check for stream | 1430 | // check for stream |
| 1533 | qpdf_offset_t cur_offset = input->tell(); | 1431 | qpdf_offset_t cur_offset = input->tell(); |
| @@ -1569,34 +1467,27 @@ QPDF::readObject( | @@ -1569,34 +1467,27 @@ QPDF::readObject( | ||
| 1569 | // of not having seen a newline. | 1467 | // of not having seen a newline. |
| 1570 | QTC::TC("qpdf", "QPDF stream with CR only"); | 1468 | QTC::TC("qpdf", "QPDF stream with CR only"); |
| 1571 | input->unreadCh(ch); | 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 | input->tell(), | 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 | } else if (QUtil::is_space(ch)) { | 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 | input->tell(), | 1480 | input->tell(), |
| 1587 | - "stream keyword followed by" | ||
| 1588 | - " extraneous whitespace")); | 1481 | + "stream keyword followed by extraneous whitespace")); |
| 1589 | done = false; | 1482 | done = false; |
| 1590 | } else { | 1483 | } else { |
| 1591 | QTC::TC("qpdf", "QPDF stream without newline"); | 1484 | QTC::TC("qpdf", "QPDF stream without newline"); |
| 1592 | input->unreadCh(ch); | 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 | input->tell(), | 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,21 +1503,15 @@ QPDF::readObject( | ||
| 1612 | 1503 | ||
| 1613 | if (dict.count("/Length") == 0) { | 1504 | if (dict.count("/Length") == 0) { |
| 1614 | QTC::TC("qpdf", "QPDF stream without length"); | 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 | QPDFObjectHandle length_obj = dict["/Length"]; | 1510 | QPDFObjectHandle length_obj = dict["/Length"]; |
| 1624 | if (!length_obj.isInteger()) { | 1511 | if (!length_obj.isInteger()) { |
| 1625 | QTC::TC("qpdf", "QPDF stream length not integer"); | 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 | offset, | 1515 | offset, |
| 1631 | "/Length key in stream dictionary is not " | 1516 | "/Length key in stream dictionary is not " |
| 1632 | "an integer"); | 1517 | "an integer"); |
| @@ -1640,12 +1525,8 @@ QPDF::readObject( | @@ -1640,12 +1525,8 @@ QPDF::readObject( | ||
| 1640 | QPDFTokenizer::Token( | 1525 | QPDFTokenizer::Token( |
| 1641 | QPDFTokenizer::tt_word, "endstream"))) { | 1526 | QPDFTokenizer::tt_word, "endstream"))) { |
| 1642 | QTC::TC("qpdf", "QPDF missing endstream"); | 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 | } catch (QPDFExc& e) { | 1531 | } catch (QPDFExc& e) { |
| 1651 | if (this->m->attempt_recovery) { | 1532 | if (this->m->attempt_recovery) { |
| @@ -1689,12 +1570,8 @@ QPDF::recoverStreamLength( | @@ -1689,12 +1570,8 @@ QPDF::recoverStreamLength( | ||
| 1689 | { | 1570 | { |
| 1690 | // Try to reconstruct stream length by looking for | 1571 | // Try to reconstruct stream length by looking for |
| 1691 | // endstream or endobj | 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 | PatternFinder ef(*this, &QPDF::findEndstream); | 1576 | PatternFinder ef(*this, &QPDF::findEndstream); |
| 1700 | size_t length = 0; | 1577 | size_t length = 0; |
| @@ -1734,18 +1611,13 @@ QPDF::recoverStreamLength( | @@ -1734,18 +1611,13 @@ QPDF::recoverStreamLength( | ||
| 1734 | } | 1611 | } |
| 1735 | 1612 | ||
| 1736 | if (length == 0) { | 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 | stream_offset, | 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 | } else { | 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 | stream_offset, | 1621 | stream_offset, |
| 1750 | "recovered stream length: " + std::to_string(length))); | 1622 | "recovered stream length: " + std::to_string(length))); |
| 1751 | } | 1623 | } |
| @@ -1795,11 +1667,7 @@ QPDF::readObjectAtOffset( | @@ -1795,11 +1667,7 @@ QPDF::readObjectAtOffset( | ||
| 1795 | // ignore these. | 1667 | // ignore these. |
| 1796 | if (offset == 0) { | 1668 | if (offset == 0) { |
| 1797 | QTC::TC("qpdf", "QPDF bogus 0 offset", 0); | 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 | return QPDFObjectHandle::newNull(); | 1671 | return QPDFObjectHandle::newNull(); |
| 1804 | } | 1672 | } |
| 1805 | 1673 | ||
| @@ -1820,33 +1688,19 @@ QPDF::readObjectAtOffset( | @@ -1820,33 +1688,19 @@ QPDF::readObjectAtOffset( | ||
| 1820 | try { | 1688 | try { |
| 1821 | if (!(objidok && genok && objok)) { | 1689 | if (!(objidok && genok && objok)) { |
| 1822 | QTC::TC("qpdf", "QPDF expected n n obj"); | 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 | int objid = QUtil::string_to_int(tobjid.getValue().c_str()); | 1693 | int objid = QUtil::string_to_int(tobjid.getValue().c_str()); |
| 1831 | int generation = QUtil::string_to_int(tgen.getValue().c_str()); | 1694 | int generation = QUtil::string_to_int(tgen.getValue().c_str()); |
| 1832 | og = QPDFObjGen(objid, generation); | 1695 | og = QPDFObjGen(objid, generation); |
| 1833 | if (objid == 0) { | 1696 | if (objid == 0) { |
| 1834 | QTC::TC("qpdf", "QPDF object id 0"); | 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 | if (check_og && (exp_og != og)) { | 1700 | if (check_og && (exp_og != og)) { |
| 1843 | QTC::TC("qpdf", "QPDF err wrong objid/generation"); | 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 | if (try_recovery) { | 1704 | if (try_recovery) { |
| 1851 | // Will be retried below | 1705 | // Will be retried below |
| 1852 | throw e; | 1706 | throw e; |
| @@ -1870,14 +1724,12 @@ QPDF::readObjectAtOffset( | @@ -1870,14 +1724,12 @@ QPDF::readObjectAtOffset( | ||
| 1870 | return result; | 1724 | return result; |
| 1871 | } else { | 1725 | } else { |
| 1872 | QTC::TC("qpdf", "QPDF object gone after xref reconstruction"); | 1726 | QTC::TC("qpdf", "QPDF object gone after xref reconstruction"); |
| 1873 | - warn( | ||
| 1874 | - qpdf_e_damaged_pdf, | 1727 | + warn(damagedPDF( |
| 1875 | "", | 1728 | "", |
| 1876 | 0, | 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 | return QPDFObjectHandle::newNull(); | 1733 | return QPDFObjectHandle::newNull(); |
| 1882 | } | 1734 | } |
| 1883 | } else { | 1735 | } else { |
| @@ -1890,11 +1742,7 @@ QPDF::readObjectAtOffset( | @@ -1890,11 +1742,7 @@ QPDF::readObjectAtOffset( | ||
| 1890 | if (!(readToken(this->m->file) == | 1742 | if (!(readToken(this->m->file) == |
| 1891 | QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) { | 1743 | QPDFTokenizer::Token(QPDFTokenizer::tt_word, "endobj"))) { |
| 1892 | QTC::TC("qpdf", "QPDF err expected endobj"); | 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 | if (isUnresolved(og)) { | 1748 | if (isUnresolved(og)) { |
| @@ -1919,12 +1767,7 @@ QPDF::readObjectAtOffset( | @@ -1919,12 +1767,7 @@ QPDF::readObjectAtOffset( | ||
| 1919 | break; | 1767 | break; |
| 1920 | } | 1768 | } |
| 1921 | } else { | 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 | qpdf_offset_t end_after_space = this->m->file->tell(); | 1773 | qpdf_offset_t end_after_space = this->m->file->tell(); |
| @@ -1950,11 +1793,8 @@ QPDF::resolve(QPDFObjGen const& og) | @@ -1950,11 +1793,8 @@ QPDF::resolve(QPDFObjGen const& og) | ||
| 1950 | // indirectly in some key that has to be resolved during | 1793 | // indirectly in some key that has to be resolved during |
| 1951 | // object parsing, such as stream length. | 1794 | // object parsing, such as stream length. |
| 1952 | QTC::TC("qpdf", "QPDF recursion loop in resolve"); | 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 | updateCache(og, QPDF_Null::create(), -1, -1); | 1798 | updateCache(og, QPDF_Null::create(), -1, -1); |
| 1959 | return; | 1799 | return; |
| 1960 | } | 1800 | } |
| @@ -1979,9 +1819,7 @@ QPDF::resolve(QPDFObjGen const& og) | @@ -1979,9 +1819,7 @@ QPDF::resolve(QPDFObjGen const& og) | ||
| 1979 | break; | 1819 | break; |
| 1980 | 1820 | ||
| 1981 | default: | 1821 | default: |
| 1982 | - throw QPDFExc( | ||
| 1983 | - qpdf_e_damaged_pdf, | ||
| 1984 | - this->m->file->getName(), | 1822 | + throw damagedPDF( |
| 1985 | "", | 1823 | "", |
| 1986 | 0, | 1824 | 0, |
| 1987 | ("object " + og.unparse('/') + | 1825 | ("object " + og.unparse('/') + |
| @@ -1990,12 +1828,11 @@ QPDF::resolve(QPDFObjGen const& og) | @@ -1990,12 +1828,11 @@ QPDF::resolve(QPDFObjGen const& og) | ||
| 1990 | } catch (QPDFExc& e) { | 1828 | } catch (QPDFExc& e) { |
| 1991 | warn(e); | 1829 | warn(e); |
| 1992 | } catch (std::exception& e) { | 1830 | } catch (std::exception& e) { |
| 1993 | - warn( | ||
| 1994 | - qpdf_e_damaged_pdf, | 1831 | + warn(damagedPDF( |
| 1995 | "", | 1832 | "", |
| 1996 | 0, | 1833 | 0, |
| 1997 | ("object " + og.unparse('/') + | 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,13 +1858,9 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 2021 | // Force resolution of object stream | 1858 | // Force resolution of object stream |
| 2022 | QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0); | 1859 | QPDFObjectHandle obj_stream = getObjectByID(obj_stream_number, 0); |
| 2023 | if (!obj_stream.isStream()) { | 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 | // For linearization data in the object, use the data from the | 1866 | // For linearization data in the object, use the data from the |
| @@ -2041,20 +1874,13 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -2041,20 +1874,13 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 2041 | QPDFObjectHandle dict = obj_stream.getDict(); | 1874 | QPDFObjectHandle dict = obj_stream.getDict(); |
| 2042 | if (!dict.isDictionaryOfType("/ObjStm")) { | 1875 | if (!dict.isDictionaryOfType("/ObjStm")) { |
| 2043 | QTC::TC("qpdf", "QPDF ERR object stream with wrong type"); | 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 | if (!(dict.getKey("/N").isInteger() && dict.getKey("/First").isInteger())) { | 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 | ("object stream " + std::to_string(obj_stream_number) + | 1884 | ("object stream " + std::to_string(obj_stream_number) + |
| 2059 | " has incorrect keys")); | 1885 | " has incorrect keys")); |
| 2060 | } | 1886 | } |
| @@ -2077,10 +1903,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -2077,10 +1903,8 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 2077 | QPDFTokenizer::Token toffset = readToken(input); | 1903 | QPDFTokenizer::Token toffset = readToken(input); |
| 2078 | if (!((tnum.getType() == QPDFTokenizer::tt_integer) && | 1904 | if (!((tnum.getType() == QPDFTokenizer::tt_integer) && |
| 2079 | (toffset.getType() == QPDFTokenizer::tt_integer))) { | 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 | input->getLastOffset(), | 1908 | input->getLastOffset(), |
| 2085 | "expected integer in object stream header"); | 1909 | "expected integer in object stream header"); |
| 2086 | } | 1910 | } |
| @@ -2618,12 +2442,7 @@ QPDF::getRoot() | @@ -2618,12 +2442,7 @@ QPDF::getRoot() | ||
| 2618 | { | 2442 | { |
| 2619 | QPDFObjectHandle root = this->m->trailer.getKey("/Root"); | 2443 | QPDFObjectHandle root = this->m->trailer.getKey("/Root"); |
| 2620 | if (!root.isDictionary()) { | 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 | return root; | 2447 | return root; |
| 2629 | } | 2448 | } |
| @@ -2751,9 +2570,8 @@ QPDF::pipeStreamData( | @@ -2751,9 +2570,8 @@ QPDF::pipeStreamData( | ||
| 2751 | size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length); | 2570 | size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length); |
| 2752 | size_t len = file->read(buf, to_read); | 2571 | size_t len = file->read(buf, to_read); |
| 2753 | if (len == 0) { | 2572 | if (len == 0) { |
| 2754 | - throw QPDFExc( | ||
| 2755 | - qpdf_e_damaged_pdf, | ||
| 2756 | - file->getName(), | 2573 | + throw damagedPDF( |
| 2574 | + file, | ||
| 2757 | "", | 2575 | "", |
| 2758 | file->getLastOffset(), | 2576 | file->getLastOffset(), |
| 2759 | "unexpected EOF reading stream data"); | 2577 | "unexpected EOF reading stream data"); |
| @@ -2772,9 +2590,8 @@ QPDF::pipeStreamData( | @@ -2772,9 +2590,8 @@ QPDF::pipeStreamData( | ||
| 2772 | QTC::TC("qpdf", "QPDF decoding error warning"); | 2590 | QTC::TC("qpdf", "QPDF decoding error warning"); |
| 2773 | qpdf_for_warning.warn( | 2591 | qpdf_for_warning.warn( |
| 2774 | // line-break | 2592 | // line-break |
| 2775 | - QPDFExc( | ||
| 2776 | - qpdf_e_damaged_pdf, | ||
| 2777 | - file->getName(), | 2593 | + damagedPDF( |
| 2594 | + file, | ||
| 2778 | "", | 2595 | "", |
| 2779 | file->getLastOffset(), | 2596 | file->getLastOffset(), |
| 2780 | ("error decoding stream data for object " + | 2597 | ("error decoding stream data for object " + |
| @@ -2782,9 +2599,8 @@ QPDF::pipeStreamData( | @@ -2782,9 +2599,8 @@ QPDF::pipeStreamData( | ||
| 2782 | if (will_retry) { | 2599 | if (will_retry) { |
| 2783 | qpdf_for_warning.warn( | 2600 | qpdf_for_warning.warn( |
| 2784 | // line-break | 2601 | // line-break |
| 2785 | - QPDFExc( | ||
| 2786 | - qpdf_e_damaged_pdf, | ||
| 2787 | - file->getName(), | 2602 | + damagedPDF( |
| 2603 | + file, | ||
| 2788 | "", | 2604 | "", |
| 2789 | file->getLastOffset(), | 2605 | file->getLastOffset(), |
| 2790 | "stream will be re-processed without" | 2606 | "stream will be re-processed without" |
| @@ -2848,18 +2664,72 @@ QPDF::pipeForeignStreamData( | @@ -2848,18 +2664,72 @@ QPDF::pipeForeignStreamData( | ||
| 2848 | will_retry); | 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 | void | 2670 | void |
| 2852 | QPDF::stopOnError(std::string const& message) | 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 | bool | 2735 | bool |
libqpdf/QPDF_encryption.cc
| @@ -804,21 +804,12 @@ QPDF::initializeEncryption() | @@ -804,21 +804,12 @@ QPDF::initializeEncryption() | ||
| 804 | // Treating a missing ID as the empty string enables qpdf to | 804 | // Treating a missing ID as the empty string enables qpdf to |
| 805 | // decrypt some invalid encrypted files with no /ID that | 805 | // decrypt some invalid encrypted files with no /ID that |
| 806 | // poppler can read but Adobe Reader can't. | 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 | QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt"); | 810 | QPDFObjectHandle encryption_dict = this->m->trailer.getKey("/Encrypt"); |
| 815 | if (!encryption_dict.isDictionary()) { | 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 | if (!(encryption_dict.getKey("/Filter").isName() && | 815 | if (!(encryption_dict.getKey("/Filter").isName() && |
| @@ -835,8 +826,7 @@ QPDF::initializeEncryption() | @@ -835,8 +826,7 @@ QPDF::initializeEncryption() | ||
| 835 | qpdf_e_unsupported, | 826 | qpdf_e_unsupported, |
| 836 | "encryption dictionary", | 827 | "encryption dictionary", |
| 837 | this->m->file->getLastOffset(), | 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 | if (!(encryption_dict.getKey("/V").isInteger() && | 832 | if (!(encryption_dict.getKey("/V").isInteger() && |
| @@ -844,13 +834,10 @@ QPDF::initializeEncryption() | @@ -844,13 +834,10 @@ QPDF::initializeEncryption() | ||
| 844 | encryption_dict.getKey("/O").isString() && | 834 | encryption_dict.getKey("/O").isString() && |
| 845 | encryption_dict.getKey("/U").isString() && | 835 | encryption_dict.getKey("/U").isString() && |
| 846 | encryption_dict.getKey("/P").isInteger())) { | 836 | encryption_dict.getKey("/P").isInteger())) { |
| 847 | - throw QPDFExc( | ||
| 848 | - qpdf_e_damaged_pdf, | ||
| 849 | - this->m->file->getName(), | 837 | + throw damagedPDF( |
| 850 | "encryption dictionary", | 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 | int V = encryption_dict.getKey("/V").getIntValueAsInt(); | 843 | int V = encryption_dict.getKey("/V").getIntValueAsInt(); |
| @@ -886,25 +873,18 @@ QPDF::initializeEncryption() | @@ -886,25 +873,18 @@ QPDF::initializeEncryption() | ||
| 886 | pad_short_parameter(O, key_bytes); | 873 | pad_short_parameter(O, key_bytes); |
| 887 | pad_short_parameter(U, key_bytes); | 874 | pad_short_parameter(U, key_bytes); |
| 888 | if (!((O.length() == key_bytes) && (U.length() == key_bytes))) { | 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 | "encryption dictionary", | 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 | } else { | 880 | } else { |
| 898 | if (!(encryption_dict.getKey("/OE").isString() && | 881 | if (!(encryption_dict.getKey("/OE").isString() && |
| 899 | encryption_dict.getKey("/UE").isString() && | 882 | encryption_dict.getKey("/UE").isString() && |
| 900 | encryption_dict.getKey("/Perms").isString())) { | 883 | encryption_dict.getKey("/Perms").isString())) { |
| 901 | - throw QPDFExc( | ||
| 902 | - qpdf_e_damaged_pdf, | ||
| 903 | - this->m->file->getName(), | 884 | + throw damagedPDF( |
| 904 | "encryption dictionary", | 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 | OE = encryption_dict.getKey("/OE").getStringValue(); | 889 | OE = encryption_dict.getKey("/OE").getStringValue(); |
| 910 | UE = encryption_dict.getKey("/UE").getStringValue(); | 890 | UE = encryption_dict.getKey("/UE").getStringValue(); |
| @@ -1062,12 +1042,10 @@ QPDF::initializeEncryption() | @@ -1062,12 +1042,10 @@ QPDF::initializeEncryption() | ||
| 1062 | this->m->encp->encryption_key = recover_encryption_key_with_password( | 1042 | this->m->encp->encryption_key = recover_encryption_key_with_password( |
| 1063 | this->m->encp->provided_password, data, perms_valid); | 1043 | this->m->encp->provided_password, data, perms_valid); |
| 1064 | if (!perms_valid) { | 1044 | if (!perms_valid) { |
| 1065 | - warn( | ||
| 1066 | - qpdf_e_damaged_pdf, | 1045 | + warn(damagedPDF( |
| 1067 | "encryption dictionary", | 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,13 +1099,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) | ||
| 1121 | break; | 1099 | break; |
| 1122 | 1100 | ||
| 1123 | default: | 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 | // To avoid repeated warnings, reset cf_string. Assume | 1105 | // To avoid repeated warnings, reset cf_string. Assume |
| 1132 | // we'd want to use AES if V == 4. | 1106 | // we'd want to use AES if V == 4. |
| 1133 | this->m->encp->cf_string = e_aes; | 1107 | this->m->encp->cf_string = e_aes; |
| @@ -1166,13 +1140,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) | @@ -1166,13 +1140,9 @@ QPDF::decryptString(std::string& str, QPDFObjGen const& og) | ||
| 1166 | } catch (QPDFExc&) { | 1140 | } catch (QPDFExc&) { |
| 1167 | throw; | 1141 | throw; |
| 1168 | } catch (std::runtime_error& e) { | 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 | "error decrypting string for object " + og.unparse() + ": " + | 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,11 +1235,8 @@ QPDF::decryptStream( | ||
| 1265 | file->getName(), | 1235 | file->getName(), |
| 1266 | "", | 1236 | "", |
| 1267 | file->getLastOffset(), | 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 | // To avoid repeated warnings, reset cf_stream. Assume | 1240 | // To avoid repeated warnings, reset cf_stream. Assume |
| 1274 | // we'd want to use AES if V == 4. | 1241 | // we'd want to use AES if V == 4. |
| 1275 | encp->cf_stream = e_aes; | 1242 | encp->cf_stream = e_aes; |
libqpdf/QPDF_linearization.cc
| @@ -186,24 +186,16 @@ QPDF::readLinearizationData() | @@ -186,24 +186,16 @@ QPDF::readLinearizationData() | ||
| 186 | 186 | ||
| 187 | if (!(H.isArray() && O.isInteger() && E.isInteger() && N.isInteger() && | 187 | if (!(H.isArray() && O.isInteger() && E.isInteger() && N.isInteger() && |
| 188 | T.isInteger() && (P.isInteger() || P.isNull()))) { | 188 | T.isInteger() && (P.isInteger() || P.isNull()))) { |
| 189 | - throw QPDFExc( | ||
| 190 | - qpdf_e_damaged_pdf, | ||
| 191 | - this->m->file->getName(), | 189 | + throw damagedPDF( |
| 192 | "linearization dictionary", | 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 | // Hint table array: offset length [ offset length ] | 194 | // Hint table array: offset length [ offset length ] |
| 199 | size_t n_H_items = toS(H.getArrayNItems()); | 195 | size_t n_H_items = toS(H.getArrayNItems()); |
| 200 | if (!((n_H_items == 2) || (n_H_items == 4))) { | 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 | std::vector<int> H_items; | 201 | std::vector<int> H_items; |
| @@ -212,11 +204,8 @@ QPDF::readLinearizationData() | @@ -212,11 +204,8 @@ QPDF::readLinearizationData() | ||
| 212 | if (oh.isInteger()) { | 204 | if (oh.isInteger()) { |
| 213 | H_items.push_back(oh.getIntValueAsInt()); | 205 | H_items.push_back(oh.getIntValueAsInt()); |
| 214 | } else { | 206 | } else { |
| 215 | - throw QPDFExc( | ||
| 216 | - qpdf_e_damaged_pdf, | ||
| 217 | - this->m->file->getName(), | 207 | + throw damagedPDF( |
| 218 | "linearization dictionary", | 208 | "linearization dictionary", |
| 219 | - this->m->file->getLastOffset(), | ||
| 220 | "some H items are of the wrong type"); | 209 | "some H items are of the wrong type"); |
| 221 | } | 210 | } |
| 222 | } | 211 | } |
| @@ -249,12 +238,8 @@ QPDF::readLinearizationData() | @@ -249,12 +238,8 @@ QPDF::readLinearizationData() | ||
| 249 | // initialized from N, to pre-allocate memory, so make sure it's | 238 | // initialized from N, to pre-allocate memory, so make sure it's |
| 250 | // accurate and bail right now if it's not. | 239 | // accurate and bail right now if it's not. |
| 251 | if (N.getIntValue() != static_cast<long long>(getAllPages().size())) { | 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 | // file_size initialized by isLinearized() | 245 | // file_size initialized by isLinearized() |
| @@ -297,11 +282,8 @@ QPDF::readLinearizationData() | @@ -297,11 +282,8 @@ QPDF::readLinearizationData() | ||
| 297 | 282 | ||
| 298 | int HSi = HS.getIntValueAsInt(); | 283 | int HSi = HS.getIntValueAsInt(); |
| 299 | if ((HSi < 0) || (toS(HSi) >= h_size)) { | 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 | "linearization hint table", | 286 | "linearization hint table", |
| 304 | - this->m->file->getLastOffset(), | ||
| 305 | "/S (shared object) offset is out of bounds"); | 287 | "/S (shared object) offset is out of bounds"); |
| 306 | } | 288 | } |
| 307 | readHSharedObject(BitStream(h_buf + HSi, h_size - toS(HSi))); | 289 | readHSharedObject(BitStream(h_buf + HSi, h_size - toS(HSi))); |
| @@ -309,11 +291,8 @@ QPDF::readLinearizationData() | @@ -309,11 +291,8 @@ QPDF::readLinearizationData() | ||
| 309 | if (HO.isInteger()) { | 291 | if (HO.isInteger()) { |
| 310 | int HOi = HO.getIntValueAsInt(); | 292 | int HOi = HO.getIntValueAsInt(); |
| 311 | if ((HOi < 0) || (toS(HOi) >= h_size)) { | 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 | "linearization hint table", | 295 | "linearization hint table", |
| 316 | - this->m->file->getLastOffset(), | ||
| 317 | "/O (outline) offset is out of bounds"); | 296 | "/O (outline) offset is out of bounds"); |
| 318 | } | 297 | } |
| 319 | readHGeneric( | 298 | readHGeneric( |
| @@ -331,12 +310,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) | @@ -331,12 +310,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) | ||
| 331 | qpdf_offset_t min_end_offset = oc.end_before_space; | 310 | qpdf_offset_t min_end_offset = oc.end_before_space; |
| 332 | qpdf_offset_t max_end_offset = oc.end_after_space; | 311 | qpdf_offset_t max_end_offset = oc.end_after_space; |
| 333 | if (!H.isStream()) { | 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 | QPDFObjectHandle Hdict = H.getDict(); | 317 | QPDFObjectHandle Hdict = H.getDict(); |
| @@ -362,12 +337,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) | @@ -362,12 +337,8 @@ QPDF::readHintStream(Pipeline& pl, qpdf_offset_t offset, size_t length) | ||
| 362 | *this->m->log->getError() | 337 | *this->m->log->getError() |
| 363 | << "expected = " << computed_end << "; actual = " << min_end_offset | 338 | << "expected = " << computed_end << "; actual = " << min_end_offset |
| 364 | << ".." << max_end_offset << "\n"; | 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 | H.pipeStreamData(&pl, 0, qpdf_dl_specialized); | 343 | H.pipeStreamData(&pl, 0, qpdf_dl_specialized); |
| 373 | return Hdict; | 344 | return Hdict; |