Commit 44a13951940def9699b2c169e8a8eabd35973934

Authored by m-holger
1 parent 06a2d955

Refactor QPDF::Xref_table::read_entry and read_bad_entry

Return results rather than using reference parameters.

Fixes bug in #1272 where parameters were not reinitialized when calling
read_bad_entry from read_entry.
libqpdf/QPDF.cc
@@ -832,10 +832,6 @@ std::vector<QPDF::Xref_table::Subsection> @@ -832,10 +832,6 @@ std::vector<QPDF::Xref_table::Subsection>
832 QPDF::Xref_table::bad_subsections(std::string& line, qpdf_offset_t start) 832 QPDF::Xref_table::bad_subsections(std::string& line, qpdf_offset_t start)
833 { 833 {
834 std::vector<QPDF::Xref_table::Subsection> result; 834 std::vector<QPDF::Xref_table::Subsection> result;
835 - qpdf_offset_t f1 = 0;  
836 - int f2 = 0;  
837 - char type = '\0';  
838 -  
839 file->seek(start, SEEK_SET); 835 file->seek(start, SEEK_SET);
840 836
841 while (true) { 837 while (true) {
@@ -844,7 +840,7 @@ QPDF::Xref_table::bad_subsections(std::string&amp; line, qpdf_offset_t start) @@ -844,7 +840,7 @@ QPDF::Xref_table::bad_subsections(std::string&amp; line, qpdf_offset_t start)
844 auto [obj, num, offset] = result.emplace_back(subsection(line)); 840 auto [obj, num, offset] = result.emplace_back(subsection(line));
845 file->seek(offset, SEEK_SET); 841 file->seek(offset, SEEK_SET);
846 for (qpdf_offset_t i = obj; i - num < obj; ++i) { 842 for (qpdf_offset_t i = obj; i - num < obj; ++i) {
847 - if (!read_entry(f1, f2, type)) { 843 + if (!std::get<0>(read_entry())) {
848 QTC::TC("qpdf", "QPDF invalid xref entry"); 844 QTC::TC("qpdf", "QPDF invalid xref entry");
849 throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")"); 845 throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")");
850 } 846 }
@@ -890,9 +886,13 @@ QPDF::Xref_table::subsections(std::string&amp; line) @@ -890,9 +886,13 @@ QPDF::Xref_table::subsections(std::string&amp; line)
890 } 886 }
891 } 887 }
892 888
893 -bool  
894 -QPDF::Xref_table::read_bad_entry(qpdf_offset_t& f1, int& f2, char& type) 889 +// Returns (success, f1, f2, type).
  890 +std::tuple<bool, qpdf_offset_t, int, char>
  891 +QPDF::Xref_table::read_bad_entry()
895 { 892 {
  893 + qpdf_offset_t f1{0};
  894 + int f2{0};
  895 + char type{'\0'};
896 // Reposition after initial read attempt and reread. 896 // Reposition after initial read attempt and reread.
897 file->seek(file->getLastOffset(), SEEK_SET); 897 file->seek(file->getLastOffset(), SEEK_SET);
898 auto line = file->readLine(30); 898 auto line = file->readLine(30);
@@ -910,7 +910,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -910,7 +910,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
910 } 910 }
911 // Require digit 911 // Require digit
912 if (!QUtil::is_digit(*p)) { 912 if (!QUtil::is_digit(*p)) {
913 - return false; 913 + return {false, 0, 0, '\0'};
914 } 914 }
915 // Gather digits 915 // Gather digits
916 std::string f1_str; 916 std::string f1_str;
@@ -919,7 +919,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -919,7 +919,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
919 } 919 }
920 // Require space 920 // Require space
921 if (!QUtil::is_space(*p)) { 921 if (!QUtil::is_space(*p)) {
922 - return false; 922 + return {false, 0, 0, '\0'};
923 } 923 }
924 if (QUtil::is_space(*(p + 1))) { 924 if (QUtil::is_space(*(p + 1))) {
925 QTC::TC("qpdf", "QPDF ignore first extra space in xref entry"); 925 QTC::TC("qpdf", "QPDF ignore first extra space in xref entry");
@@ -931,7 +931,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -931,7 +931,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
931 } 931 }
932 // Require digit 932 // Require digit
933 if (!QUtil::is_digit(*p)) { 933 if (!QUtil::is_digit(*p)) {
934 - return false; 934 + return {false, 0, 0, '\0'};
935 } 935 }
936 // Gather digits 936 // Gather digits
937 std::string f2_str; 937 std::string f2_str;
@@ -940,7 +940,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -940,7 +940,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
940 } 940 }
941 // Require space 941 // Require space
942 if (!QUtil::is_space(*p)) { 942 if (!QUtil::is_space(*p)) {
943 - return false; 943 + return {false, 0, 0, '\0'};
944 } 944 }
945 if (QUtil::is_space(*(p + 1))) { 945 if (QUtil::is_space(*(p + 1))) {
946 QTC::TC("qpdf", "QPDF ignore second extra space in xref entry"); 946 QTC::TC("qpdf", "QPDF ignore second extra space in xref entry");
@@ -953,7 +953,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -953,7 +953,7 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
953 if ((*p == 'f') || (*p == 'n')) { 953 if ((*p == 'f') || (*p == 'n')) {
954 type = *p; 954 type = *p;
955 } else { 955 } else {
956 - return false; 956 + return {false, 0, 0, '\0'};
957 } 957 }
958 if ((f1_str.length() != 10) || (f2_str.length() != 5)) { 958 if ((f1_str.length() != 10) || (f2_str.length() != 5)) {
959 QTC::TC("qpdf", "QPDF ignore length error xref entry"); 959 QTC::TC("qpdf", "QPDF ignore length error xref entry");
@@ -967,18 +967,23 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -967,18 +967,23 @@ QPDF::Xref_table::read_bad_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
967 f1 = QUtil::string_to_ll(f1_str.c_str()); 967 f1 = QUtil::string_to_ll(f1_str.c_str());
968 f2 = QUtil::string_to_int(f2_str.c_str()); 968 f2 = QUtil::string_to_int(f2_str.c_str());
969 969
970 - return true; 970 + return {true, f1, f2, type};
971 } 971 }
972 972
973 // Optimistically read and parse xref entry. If entry is bad, call read_bad_xrefEntry and return 973 // Optimistically read and parse xref entry. If entry is bad, call read_bad_xrefEntry and return
974 -// result.  
975 -bool  
976 -QPDF::Xref_table::read_entry(qpdf_offset_t& f1, int& f2, char& type) 974 +// result. Returns (success, f1, f2, type).
  975 +std::tuple<bool, qpdf_offset_t, int, char>
  976 +QPDF::Xref_table::read_entry()
977 { 977 {
  978 + qpdf_offset_t f1{0};
  979 + int f2{0};
  980 + char type{'\0'};
978 std::array<char, 21> line; 981 std::array<char, 21> line;
  982 + f1 = 0;
  983 + f2 = 0;
979 if (file->read(line.data(), 20) != 20) { 984 if (file->read(line.data(), 20) != 20) {
980 // C++20: [[unlikely]] 985 // C++20: [[unlikely]]
981 - return false; 986 + return {false, 0, 0, '\0'};
982 } 987 }
983 line[20] = '\0'; 988 line[20] = '\0';
984 char const* p = line.data(); 989 char const* p = line.data();
@@ -1002,7 +1007,7 @@ QPDF::Xref_table::read_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -1002,7 +1007,7 @@ QPDF::Xref_table::read_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
1002 if (!QUtil::is_space(*p++)) { 1007 if (!QUtil::is_space(*p++)) {
1003 // Entry doesn't start with space or digit. 1008 // Entry doesn't start with space or digit.
1004 // C++20: [[unlikely]] 1009 // C++20: [[unlikely]]
1005 - return false; 1010 + return {false, 0, 0, '\0'};
1006 } 1011 }
1007 // Gather digits. NB No risk of overflow as 99'999 < max int. 1012 // Gather digits. NB No risk of overflow as 99'999 < max int.
1008 while (*p == '0') { 1013 while (*p == '0') {
@@ -1019,10 +1024,10 @@ QPDF::Xref_table::read_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type) @@ -1019,10 +1024,10 @@ QPDF::Xref_table::read_entry(qpdf_offset_t&amp; f1, int&amp; f2, char&amp; type)
1019 // No test for valid line[19]. 1024 // No test for valid line[19].
1020 if (*(++p) && *(++p) && (*p == '\n' || *p == '\r') && f1_len == 10 && f2_len == 5) { 1025 if (*(++p) && *(++p) && (*p == '\n' || *p == '\r') && f1_len == 10 && f2_len == 5) {
1021 // C++20: [[likely]] 1026 // C++20: [[likely]]
1022 - return true; 1027 + return {true, f1, f2, type};
1023 } 1028 }
1024 } 1029 }
1025 - return read_bad_entry(f1, f2, type); 1030 + return read_bad_entry();
1026 } 1031 }
1027 1032
1028 // Read a single cross-reference table section and associated trailer. 1033 // Read a single cross-reference table section and associated trailer.
@@ -1064,10 +1069,8 @@ QPDF::Xref_table::process_section(qpdf_offset_t xref_offset) @@ -1064,10 +1069,8 @@ QPDF::Xref_table::process_section(qpdf_offset_t xref_offset)
1064 first_item_offset_ = file->tell(); 1069 first_item_offset_ = file->tell();
1065 } 1070 }
1066 // For xref_table, these will always be small enough to be ints 1071 // For xref_table, these will always be small enough to be ints
1067 - qpdf_offset_t f1 = 0;  
1068 - int f2 = 0;  
1069 - char type = '\0';  
1070 - if (!read_entry(f1, f2, type)) { 1072 + auto [success, f1, f2, type] = read_entry();
  1073 + if (!success) {
1071 throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")"); 1074 throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")");
1072 } 1075 }
1073 if (type == 'f') { 1076 if (type == 'f') {
@@ -1585,8 +1588,7 @@ QPDF::Xref_table::read_trailer() @@ -1585,8 +1588,7 @@ QPDF::Xref_table::read_trailer()
1585 { 1588 {
1586 qpdf_offset_t offset = file->tell(); 1589 qpdf_offset_t offset = file->tell();
1587 bool empty = false; 1590 bool empty = false;
1588 - auto object =  
1589 - QPDFParser(*file, "trailer", tokenizer, nullptr, &qpdf, true).parse(empty, false); 1591 + auto object = QPDFParser(*file, "trailer", tokenizer, nullptr, &qpdf, true).parse(empty, false);
1590 if (empty) { 1592 if (empty) {
1591 // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in 1593 // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
1592 // actual PDF files and Adobe Reader appears to ignore them. 1594 // actual PDF files and Adobe Reader appears to ignore them.
libqpdf/qpdf/QPDF_private.hh
@@ -292,8 +292,8 @@ class QPDF::Xref_table @@ -292,8 +292,8 @@ class QPDF::Xref_table
292 std::vector<Subsection> subsections(std::string& line); 292 std::vector<Subsection> subsections(std::string& line);
293 std::vector<Subsection> bad_subsections(std::string& line, qpdf_offset_t offset); 293 std::vector<Subsection> bad_subsections(std::string& line, qpdf_offset_t offset);
294 Subsection subsection(std::string const& line); 294 Subsection subsection(std::string const& line);
295 - bool read_entry(qpdf_offset_t& f1, int& f2, char& type);  
296 - bool read_bad_entry(qpdf_offset_t& f1, int& f2, char& type); 295 + std::tuple<bool, qpdf_offset_t, int, char> read_entry();
  296 + std::tuple<bool, qpdf_offset_t, int, char> read_bad_entry();
297 297
298 // Methods to parse streams 298 // Methods to parse streams
299 qpdf_offset_t read_stream(qpdf_offset_t offset); 299 qpdf_offset_t read_stream(qpdf_offset_t offset);