diff --git a/ChangeLog b/ChangeLog index 5be7129f..bff50287 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-07-27 Jay Berkenbilt + + * Significantly improve recoverability from invalid qpdf objects. + Most conditions in basic object parsing that used to cause qpdf to + exit are now warnings. There are still many more opportunities for + improvements of this sort beyond just object parsing. + 2017-07-26 Jay Berkenbilt * Fixes to infinite loops below also fix problems reported in diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 4742275f..0788316d 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -522,6 +522,18 @@ class QPDF }; friend class Resolver; + // Warner class allows QPDFObjectHandle to create warnings + class Warner + { + friend class QPDFObjectHandle; + private: + static void warn(QPDF* qpdf, QPDFExc const& e) + { + qpdf->warn(e); + } + }; + friend class Warner; + // Pipe class is restricted to QPDF_Stream class Pipe { diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index bd1f1f19..0fc989a5 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -28,6 +28,7 @@ class QPDF; class QPDF_Dictionary; class QPDF_Array; class QPDFTokenizer; +class QPDFExc; class QPDFObjectHandle { @@ -623,6 +624,9 @@ class QPDFObjectHandle static void parseContentStream_internal( QPDFObjectHandle stream, ParserCallbacks* callbacks); + // Other methods + static void warn(QPDF*, QPDFExc const&); + bool initialized; QPDF* qpdf; // 0 for direct object diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index ecc13491..087013d7 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -334,8 +334,9 @@ QPDF::reconstruct_xref(QPDFExc& e) { if (this->reconstructed_xref) { - // Avoid xref reconstruction infinite loops - QTC::TC("qpdf", "QPDF caught recursive xref reconstruction"); + // Avoid xref reconstruction infinite loops. This is getting + // very hard to reproduce because qpdf is throwing many fewer + // exceptions while parsing. Most situations are warnings now. throw e; } diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index fcf9b976..7618cdf3 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -850,6 +850,11 @@ QPDFObjectHandle::parseInternal(PointerHolder input, bool in_array, bool in_dictionary, bool content_stream) { + // This method must take care not to resolve any objects. Don't + // check the tpye of any object without first ensuring that it is + // a direct object. Otherwise, doing so may have the side effect + // of reading the object and changing the file pointer. + empty = false; if (in_dictionary && in_array) { @@ -891,12 +896,13 @@ QPDFObjectHandle::parseInternal(PointerHolder input, case QPDFTokenizer::tt_brace_open: case QPDFTokenizer::tt_brace_close: - // Don't know what to do with these for now QTC::TC("qpdf", "QPDFObjectHandle bad brace"); - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "unexpected brace token"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "treating unexpected brace token as null")); + object = newNull(); break; case QPDFTokenizer::tt_array_close: @@ -907,10 +913,12 @@ QPDFObjectHandle::parseInternal(PointerHolder input, else { QTC::TC("qpdf", "QPDFObjectHandle bad array close"); - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "unexpected array close token"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "treating unexpected array close token as null")); + object = newNull(); } break; @@ -922,10 +930,12 @@ QPDFObjectHandle::parseInternal(PointerHolder input, else { QTC::TC("qpdf", "QPDFObjectHandle bad dictionary close"); - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "unexpected dictionary close token"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "unexpected dictionary close token")); + object = newNull(); } break; @@ -1002,11 +1012,14 @@ QPDFObjectHandle::parseInternal(PointerHolder input, } else { - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "unknown token while reading object (" + - value + ")"); + QTC::TC("qpdf", "QPDFObjectHandle treat word as string"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "unknown token while reading object;" + " treating as string")); + object = newString(value); } } break; @@ -1024,10 +1037,13 @@ QPDFObjectHandle::parseInternal(PointerHolder input, break; default: - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "unknown token type while reading object"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "treating unknown token type as null while " + "reading object")); + object = newNull(); break; } @@ -1040,10 +1056,12 @@ QPDFObjectHandle::parseInternal(PointerHolder input, } else if (! object.isInitialized()) { - throw QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "parse error while reading object"); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "parse error while reading object")); + object = newNull(); } else { @@ -1057,30 +1075,65 @@ QPDFObjectHandle::parseInternal(PointerHolder input, } else if (in_dictionary) { - // Convert list to map. Alternating elements are keys. - std::map dict; - if (olist.size() % 2) - { - QTC::TC("qpdf", "QPDFObjectHandle dictionary odd number of elements"); - throw QPDFExc( - qpdf_e_damaged_pdf, input->getName(), - object_description, input->getLastOffset(), - "dictionary ending here has an odd number of elements"); - } - for (unsigned int i = 0; i < olist.size(); i += 2) - { - QPDFObjectHandle key_obj = olist.at(i); - QPDFObjectHandle val = olist.at(i + 1); - if (! key_obj.isName()) - { - throw QPDFExc( - qpdf_e_damaged_pdf, - input->getName(), object_description, offset, - std::string("dictionary key is not not a name token")); - } - dict[key_obj.getName()] = val; - } - object = newDictionary(dict); + // Convert list to map. Alternating elements are keys. Attempt + // to recover more or less gracefully from invalid + // dictionaries. + std::set names; + for (std::vector::iterator iter = olist.begin(); + iter != olist.end(); ++iter) + { + if ((! (*iter).isIndirect()) && (*iter).isName()) + { + names.insert((*iter).getName()); + } + } + + std::map dict; + int next_fake_key = 1; + for (unsigned int i = 0; i < olist.size(); ++i) + { + QPDFObjectHandle key_obj = olist.at(i); + QPDFObjectHandle val; + if (key_obj.isIndirect() || (! key_obj.isName())) + { + bool found_fake = false; + std::string candidate; + while (! found_fake) + { + candidate = + "/QPDFFake" + QUtil::int_to_string(next_fake_key++); + found_fake = (names.count(candidate) == 0); + QTC::TC("qpdf", "QPDFObjectHandle found fake", + (found_fake ? 0 : 1)); + } + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + input->getName(), object_description, offset, + "expected dictionary key but found" + " non-name object; inserting key " + + candidate)); + val = key_obj; + key_obj = newName(candidate); + } + else if (i + 1 >= olist.size()) + { + QTC::TC("qpdf", "QPDFObjectHandle no val for last key"); + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + input->getName(), object_description, offset, + "dictionary ended prematurely; using null as value" + " for last key")); + val = newNull(); + } + else + { + val = olist.at(++i); + } + dict[key_obj.getName()] = val; + } + object = newDictionary(dict); } return object; @@ -1544,3 +1597,20 @@ QPDFObjectHandle::dereference() } } } + +void +QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) +{ + // If parsing on behalf of a QPDF object and want to give a + // warning, we can warn through the object. If parsing for some + // other reason, such as an explicit creation of an object from a + // string, then just throw the exception. + if (qpdf) + { + QPDF::Warner::warn(qpdf, e); + } + else + { + throw e; + } +} diff --git a/libqpdf/qpdf-c.cc b/libqpdf/qpdf-c.cc index c8adb9e4..975e9707 100644 --- a/libqpdf/qpdf-c.cc +++ b/libqpdf/qpdf-c.cc @@ -261,7 +261,15 @@ QPDF_ERROR_CODE qpdf_read(qpdf_data qpdf, char const* filename, qpdf->filename = filename; qpdf->password = password; status = trap_errors(qpdf, &call_read); - QTC::TC("qpdf", "qpdf-c called qpdf_read", status); + // We no longer have a good way to exercise a file with both + // warnings and errors because qpdf is getting much better at + // recovering. + QTC::TC("qpdf", "qpdf-c called qpdf_read", + (status == 0) ? 0 + : (status & QPDF_WARNINGS) ? 1 + : (status & QPDF_ERRORS) ? 2 : + -1 + ); return status; } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 8144d2c3..20859984 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -61,7 +61,6 @@ QPDF trailer size not integer 0 QPDF trailer prev not integer 0 QPDFObjectHandle bad brace 0 QPDFObjectHandle bad array close 0 -QPDFObjectHandle dictionary odd number of elements 0 QPDF stream without length 0 QPDF stream length not integer 0 QPDF missing endstream 0 @@ -124,7 +123,7 @@ qpdf-c qpdf_next_warning returned warning 0 qpdf-c called qpdf_set_suppress_warnings 0 qpdf-c called qpdf_set_ignore_xref_streams 0 qpdf-c called qpdf_set_attempt_recovery 0 -qpdf-c called qpdf_read 3 +qpdf-c called qpdf_read 2 qpdf-c called qpdf_get_pdf_version 0 qpdf-c called qpdf_get_user_password 0 qpdf-c called qpdf_is_linearized 0 @@ -275,5 +274,7 @@ QPDFWriter deterministic with no data 0 qpdf-c called qpdf_set_deterministic_ID 0 QPDFObjectHandle indirect with 0 objid 0 QPDF object id 0 0 -QPDF caught recursive xref reconstruction 0 QPDF recursion loop in resolve 0 +QPDFObjectHandle treat word as string 0 +QPDFObjectHandle found fake 1 +QPDFObjectHandle no val for last key 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 242ee149..d69ccdc2 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -220,22 +220,22 @@ $td->runtest("C API: qpdf version", # Files to reproduce various bugs foreach my $d ( - ["51", "resolve loop"], - ["99", "object 0"], - ["99b", "object 0"], - ["100","xref reconstruction loop"], - ["101", "resolve for exception text"], - ["117", "other infinite loop"], - ["118", "other infinite loop"], - ["119", "other infinite loop"], - ["120", "other infinite loop"], + ["51", "resolve loop", 2], + ["99", "object 0", 2], + ["99b", "object 0", 2], + ["100", "xref reconstruction loop", 2], + ["101", "resolve for exception text", 2], + ["117", "other infinite loop", 2], + ["118", "other infinite loop", 2], + ["119", "other infinite loop", 3], + ["120", "other infinite loop", 2], ) { - my ($n, $description) = @$d; + my ($n, $description, $exit_status) = @$d; $td->runtest($description, {$td->COMMAND => "qpdf issue-$n.pdf a.pdf"}, {$td->FILE => "issue-$n.out", - $td->EXIT_STATUS => 2}, + $td->EXIT_STATUS => $exit_status}, $td->NORMALIZE_NEWLINES); } @@ -593,7 +593,7 @@ $td->runtest("no type key for page nodes", $td->NORMALIZE_NEWLINES); $td->runtest("ensure arguments to R are direct", {$td->COMMAND => "qpdf --check indirect-r-arg.pdf"}, - {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 2}, + {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 3}, $td->NORMALIZE_NEWLINES); $td->runtest("detect loops in pages structure", {$td->COMMAND => "qpdf --check pages-loop.pdf"}, @@ -784,16 +784,19 @@ my @badfiles = ("not a PDF file", # 1 "invalid stream /Filter and xref", # 33 "obj/gen in wrong place", # 34 "object stream of wrong type", # 35 + "bad dictionary key", # 36 ); -$n_tests += @badfiles + 5; +$n_tests += @badfiles + 4; # Test 6 contains errors in the free table consistency, but we no # longer have any consistency check for this since it is not important # neither Acrobat nor other PDF viewers really care. Tests 12 and 28 # have error conditions that used to be fatal but are now considered # non-fatal. -my %badtest_overrides = (6 => 0, 12 => 0, 28 => 0, 31 => 0); +my %badtest_overrides = (6 => 0, 12 => 0, 13 => 0, + 14 => 0, 15 => 0, 17 => 0, + 28 => 0, 31 => 0, 36 => 0); for (my $i = 1; $i <= scalar(@badfiles); ++$i) { my $status = $badtest_overrides{$i}; @@ -810,11 +813,6 @@ $td->runtest("C API: errors", {$td->FILE => "c-read-errors.out", $td->EXIT_STATUS => 0}, $td->NORMALIZE_NEWLINES); -$td->runtest("C API: warnings and errors", - {$td->COMMAND => "qpdf-ctest 2 bad17.pdf '' a.pdf"}, - {$td->FILE => "c-read-warnings-and-errors.out", - $td->EXIT_STATUS => 0}, - $td->NORMALIZE_NEWLINES); $td->runtest("C API: errors writing", {$td->COMMAND => "qpdf-ctest 2 bad30.pdf '' a.pdf"}, {$td->FILE => "c-write-errors.out", @@ -842,7 +840,7 @@ $n_tests += @badfiles + 8; # though in some cases it may. Acrobat Reader would not be able to # recover any of these files any better. my %recover_failures = (); -for (1, 7, 13..21, 24, 29..30, 33, 35) +for (1, 7, 16, 18..21, 24, 29..30, 33, 35) { $recover_failures{$_} = 1; } diff --git a/qpdf/qtest/qpdf/bad13-recover.out b/qpdf/qtest/qpdf/bad13-recover.out index c20d98a7..862fac7b 100644 --- a/qpdf/qtest/qpdf/bad13-recover.out +++ b/qpdf/qtest/qpdf/bad13-recover.out @@ -1,4 +1,7 @@ -WARNING: bad13.pdf: file is damaged -WARNING: bad13.pdf (trailer, file position 753): unexpected brace token -WARNING: bad13.pdf: Attempting to reconstruct cross-reference table -bad13.pdf (trailer, file position 753): unexpected brace token +WARNING: bad13.pdf (trailer, file position 753): treating unexpected brace token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad13.out b/qpdf/qtest/qpdf/bad13.out index 04c34e36..da69c50c 100644 --- a/qpdf/qtest/qpdf/bad13.out +++ b/qpdf/qtest/qpdf/bad13.out @@ -1 +1,7 @@ -bad13.pdf (trailer, file position 753): unexpected brace token +WARNING: bad13.pdf (trailer, file position 753): treating unexpected brace token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad14-recover.out b/qpdf/qtest/qpdf/bad14-recover.out index e66441a8..7cc59a67 100644 --- a/qpdf/qtest/qpdf/bad14-recover.out +++ b/qpdf/qtest/qpdf/bad14-recover.out @@ -1,4 +1,7 @@ -WARNING: bad14.pdf: file is damaged -WARNING: bad14.pdf (trailer, file position 753): unexpected brace token -WARNING: bad14.pdf: Attempting to reconstruct cross-reference table -bad14.pdf (trailer, file position 753): unexpected brace token +WARNING: bad14.pdf (trailer, file position 753): treating unexpected brace token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad14.out b/qpdf/qtest/qpdf/bad14.out index 6d32b70c..cbb403ba 100644 --- a/qpdf/qtest/qpdf/bad14.out +++ b/qpdf/qtest/qpdf/bad14.out @@ -1 +1,7 @@ -bad14.pdf (trailer, file position 753): unexpected brace token +WARNING: bad14.pdf (trailer, file position 753): treating unexpected brace token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad15-recover.out b/qpdf/qtest/qpdf/bad15-recover.out index 0575a338..d1ce2b90 100644 --- a/qpdf/qtest/qpdf/bad15-recover.out +++ b/qpdf/qtest/qpdf/bad15-recover.out @@ -1,4 +1,7 @@ -WARNING: bad15.pdf: file is damaged -WARNING: bad15.pdf (trailer, file position 753): unexpected array close token -WARNING: bad15.pdf: Attempting to reconstruct cross-reference table -bad15.pdf (trailer, file position 753): unexpected array close token +WARNING: bad15.pdf (trailer, file position 753): treating unexpected array close token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad15.out b/qpdf/qtest/qpdf/bad15.out index 54e799df..49de89c7 100644 --- a/qpdf/qtest/qpdf/bad15.out +++ b/qpdf/qtest/qpdf/bad15.out @@ -1 +1,7 @@ -bad15.pdf (trailer, file position 753): unexpected array close token +WARNING: bad15.pdf (trailer, file position 753): treating unexpected array close token as null +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad16-recover.out b/qpdf/qtest/qpdf/bad16-recover.out index 1256ceab..4cc66e23 100644 --- a/qpdf/qtest/qpdf/bad16-recover.out +++ b/qpdf/qtest/qpdf/bad16-recover.out @@ -1,4 +1,10 @@ -WARNING: bad16.pdf: file is damaged WARNING: bad16.pdf (trailer, file position 753): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 756): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 759): unknown token while reading object; treating as string +WARNING: bad16.pdf: file is damaged +WARNING: bad16.pdf (trailer, file position 773): EOF while reading token WARNING: bad16.pdf: Attempting to reconstruct cross-reference table -bad16.pdf (trailer, file position 753): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 753): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 756): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 759): unknown token while reading object; treating as string +bad16.pdf (trailer, file position 773): EOF while reading token diff --git a/qpdf/qtest/qpdf/bad16.out b/qpdf/qtest/qpdf/bad16.out index d3a72218..e3947f9d 100644 --- a/qpdf/qtest/qpdf/bad16.out +++ b/qpdf/qtest/qpdf/bad16.out @@ -1 +1,4 @@ -bad16.pdf (trailer, file position 753): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 753): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 756): unexpected dictionary close token +WARNING: bad16.pdf (trailer, file position 759): unknown token while reading object; treating as string +bad16.pdf (trailer, file position 773): EOF while reading token diff --git a/qpdf/qtest/qpdf/bad17-recover.out b/qpdf/qtest/qpdf/bad17-recover.out index d09805ae..f6f4dfa0 100644 --- a/qpdf/qtest/qpdf/bad17-recover.out +++ b/qpdf/qtest/qpdf/bad17-recover.out @@ -1,4 +1,7 @@ -WARNING: bad17.pdf: file is damaged -WARNING: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements -WARNING: bad17.pdf: Attempting to reconstruct cross-reference table -bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements +WARNING: bad17.pdf (trailer, file position 715): dictionary ended prematurely; using null as value for last key +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad17.out b/qpdf/qtest/qpdf/bad17.out index 7285b0ae..5744fc29 100644 --- a/qpdf/qtest/qpdf/bad17.out +++ b/qpdf/qtest/qpdf/bad17.out @@ -1 +1,7 @@ -bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements +WARNING: bad17.pdf (trailer, file position 715): dictionary ended prematurely; using null as value for last key +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad36-recover.out b/qpdf/qtest/qpdf/bad36-recover.out new file mode 100644 index 00000000..59669a8a --- /dev/null +++ b/qpdf/qtest/qpdf/bad36-recover.out @@ -0,0 +1,9 @@ +WARNING: bad36.pdf (trailer, file position 764): unknown token while reading object; treating as string +WARNING: bad36.pdf (trailer, file position 715): expected dictionary key but found non-name object; inserting key /QPDFFake2 +WARNING: bad36.pdf (trailer, file position 715): dictionary ended prematurely; using null as value for last key +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 1 done diff --git a/qpdf/qtest/qpdf/bad36.out b/qpdf/qtest/qpdf/bad36.out new file mode 100644 index 00000000..f137afd9 --- /dev/null +++ b/qpdf/qtest/qpdf/bad36.out @@ -0,0 +1,9 @@ +WARNING: bad36.pdf (trailer, file position 764): unknown token while reading object; treating as string +WARNING: bad36.pdf (trailer, file position 715): expected dictionary key but found non-name object; inserting key /QPDFFake2 +WARNING: bad36.pdf (trailer, file position 715): dictionary ended prematurely; using null as value for last key +/QTest is implicit +/QTest is direct and has type null (2) +/QTest is null +unparse: null +unparseResolved: null +test 0 done diff --git a/qpdf/qtest/qpdf/bad36.pdf b/qpdf/qtest/qpdf/bad36.pdf new file mode 100644 index 00000000..ea4a3c66 --- /dev/null +++ b/qpdf/qtest/qpdf/bad36.pdf @@ -0,0 +1,81 @@ +%PDF-1.3 +1 0 obj +<< + /Type /Catalog + /Pages 2 0 R +>> +endobj + +2 0 obj +<< + /Type /Pages + /Kids [ + 3 0 R + ] + /Count 1 +>> +endobj + +3 0 obj +<< + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] + /Contents 4 0 R + /Resources << + /ProcSet 5 0 R + /Font << + /F1 6 0 R + >> + >> +>> +endobj + +4 0 obj +<< + /Length 44 +>> +stream +BT + /F1 24 Tf + 72 720 Td + (Potato) Tj +ET +endstream +endobj + +5 0 obj +[ + /PDF + /Text +] +endobj + +6 0 obj +<< + /Type /Font + /Subtype /Type1 + /Name /F1 + /BaseFont /Helvetica + /Encoding /WinAnsiEncoding +>> +endobj + +xref +0 7 +0000000000 65535 f +0000000009 00000 n +0000000063 00000 n +0000000135 00000 n +0000000307 00000 n +0000000403 00000 n +0000000438 00000 n +trailer << + /Size 7 + /Root 1 0 R + /QPDFFake1 (potato) + x /Something +>> +startxref +556 +%%EOF diff --git a/qpdf/qtest/qpdf/c-read-warnings-and-errors.out b/qpdf/qtest/qpdf/c-read-warnings-and-errors.out deleted file mode 100644 index 117663e9..00000000 --- a/qpdf/qtest/qpdf/c-read-warnings-and-errors.out +++ /dev/null @@ -1,20 +0,0 @@ -warning: bad17.pdf: file is damaged - code: 5 - file: bad17.pdf - pos : 0 - text: file is damaged -warning: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements - code: 5 - file: bad17.pdf - pos : 753 - text: dictionary ending here has an odd number of elements -warning: bad17.pdf: Attempting to reconstruct cross-reference table - code: 5 - file: bad17.pdf - pos : 0 - text: Attempting to reconstruct cross-reference table -error: bad17.pdf (trailer, file position 753): dictionary ending here has an odd number of elements - code: 5 - file: bad17.pdf - pos : 753 - text: dictionary ending here has an odd number of elements diff --git a/qpdf/qtest/qpdf/indirect-r-arg.out b/qpdf/qtest/qpdf/indirect-r-arg.out index e065ec16..e39d8f55 100644 --- a/qpdf/qtest/qpdf/indirect-r-arg.out +++ b/qpdf/qtest/qpdf/indirect-r-arg.out @@ -1 +1,7 @@ -indirect-r-arg.pdf (file position 76): unknown token while reading object (R) +WARNING: indirect-r-arg.pdf (file position 76): unknown token while reading object; treating as string +WARNING: indirect-r-arg.pdf (file position 62): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: indirect-r-arg.pdf (file position 62): expected dictionary key but found non-name object; inserting key /QPDFFake2 +checking indirect-r-arg.pdf +PDF Version: 1.3 +File is not encrypted +File is not linearized diff --git a/qpdf/qtest/qpdf/issue-100.out b/qpdf/qtest/qpdf/issue-100.out index 37bd3207..691e2282 100644 --- a/qpdf/qtest/qpdf/issue-100.out +++ b/qpdf/qtest/qpdf/issue-100.out @@ -1,5 +1,13 @@ WARNING: issue-100.pdf: file is damaged WARNING: issue-100.pdf (file position 736): xref not found WARNING: issue-100.pdf: Attempting to reconstruct cross-reference table +WARNING: issue-100.pdf (file position 268): unknown token while reading object; treating as string +WARNING: issue-100.pdf (file position 286): unknown token while reading object; treating as string +WARNING: issue-100.pdf (file position 289): unknown token while reading object; treating as string +WARNING: issue-100.pdf (file position 294): unknown token while reading object; treating as string +WARNING: issue-100.pdf (file position 297): unknown token while reading object; treating as string +WARNING: issue-100.pdf (file position 304): unknown token while reading object; treating as string WARNING: issue-100.pdf (object 5 0, file position 489): attempting to recover stream length -issue-100.pdf (object 6 0, file position 59): expected n n obj +WARNING: issue-100.pdf (trailer, file position 953): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: issue-100.pdf (trailer, file position 953): dictionary ended prematurely; using null as value for last key +operation for Dictionary object attempted on object of wrong type diff --git a/qpdf/qtest/qpdf/issue-101.out b/qpdf/qtest/qpdf/issue-101.out index 59bd8103..f2dc4715 100644 --- a/qpdf/qtest/qpdf/issue-101.out +++ b/qpdf/qtest/qpdf/issue-101.out @@ -1,6 +1,17 @@ WARNING: issue-101.pdf: file is damaged WARNING: issue-101.pdf (file position 3526): xref not found WARNING: issue-101.pdf: Attempting to reconstruct cross-reference table +WARNING: issue-101.pdf (file position 1242): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: issue-101.pdf (file position 1242): dictionary ended prematurely; using null as value for last key WARNING: issue-101.pdf (object 5 0, file position 1509): attempting to recover stream length -WARNING: issue-101.pdf (object 5 0, file position 2097): attempting to recover stream length -issue-101.pdf (trailer, file position 2928): unknown token while reading object (ÿ) +WARNING: issue-101.pdf (trailer, file position 2097): attempting to recover stream length +WARNING: issue-101.pdf (trailer, file position 2928): unknown token while reading object; treating as string +WARNING: issue-101.pdf (trailer, file position 2930): unknown token while reading object; treating as string +WARNING: issue-101.pdf (trailer, file position 2928): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: issue-101.pdf (trailer, file position 2928): expected dictionary key but found non-name object; inserting key /QPDFFake2 +WARNING: issue-101.pdf (trailer, file position 2928): expected dictionary key but found non-name object; inserting key /QPDFFake3 +WARNING: issue-101.pdf (trailer, file position 2996): attempting to recover stream length +WARNING: issue-101.pdf (trailer, file position 3410): attempting to recover stream length +WARNING: issue-101.pdf (trailer, file position 3631): attempting to recover stream length +WARNING: issue-101.pdf (trailer, file position 4184): attempting to recover stream length +issue-101.pdf (trailer, file position 4184): unable to recover stream data diff --git a/qpdf/qtest/qpdf/issue-119.out b/qpdf/qtest/qpdf/issue-119.out index bc6ffb3e..b83cfe16 100644 --- a/qpdf/qtest/qpdf/issue-119.out +++ b/qpdf/qtest/qpdf/issue-119.out @@ -1,2 +1,3 @@ -WARNING: issue-119.pdf (file position 336): loop detected resolving object 4 0 -issue-119.pdf (file position 298): dictionary key is not not a name token +WARNING: issue-119.pdf (file position 298): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: issue-119.pdf (file position 298): expected dictionary key but found non-name object; inserting key /QPDFFake2 +qpdf: operation succeeded with warnings; resulting file may have some problems