diff --git a/ChangeLog b/ChangeLog index 17e0c973..5d6a0862 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2019-06-22 Jay Berkenbilt + * When a file has linearization warnings but no errors, qpdf + --check and --check-linearization now exit with code 3 instead + of 2. Fixes #50. + * Add new function QUtil::read_file_into_memory. 2019-06-21 Jay Berkenbilt diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index f8a84ce9..d534a4df 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -483,6 +483,9 @@ class QPDF // specified in a call to setOutputStreams. QPDF_DLL bool checkLinearization(); + // Separately indicate whether there were errors or warnings. + QPDF_DLL + void checkLinearization(bool& errors, bool& warnings); // Calls checkLinearization() and, if possible, prints normalized // contents of some of the hints tables to std::cout or the output @@ -1226,7 +1229,7 @@ class QPDF // methods to support linearization checking -- implemented in // QPDF_linearization.cc void readLinearizationData(); - bool checkLinearizationInternal(); + void checkLinearizationInternal(bool& errors, bool& warnings); void dumpLinearizationDataInternal(); QPDFObjectHandle readHintStream( Pipeline&, qpdf_offset_t offset, size_t length); diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index 5eb6277e..cb607fed 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -65,17 +65,25 @@ load_vector_vector(BitStream& bit_stream, bool QPDF::checkLinearization() { - bool result = false; + bool errors = false; + bool warnings = false; + checkLinearization(errors, warnings); + return (! (errors || warnings)); +} + +void +QPDF::checkLinearization(bool& errors, bool& warnings) +{ try { readLinearizationData(); - result = checkLinearizationInternal(); + checkLinearizationInternal(errors, warnings); } catch (QPDFExc& e) { *this->m->out_stream << e.what() << std::endl; + errors = true; } - return result; } bool @@ -499,8 +507,8 @@ QPDF::readHGeneric(BitStream h, HGeneric& t) t.group_length = h.getBitsInt(32); // 4 } -bool -QPDF::checkLinearizationInternal() +void +QPDF::checkLinearizationInternal(bool& any_errors, bool& any_warnings) { // All comments referring to the PDF spec refer to the spec for // version 1.4. @@ -648,11 +656,11 @@ QPDF::checkLinearizationInternal() // Report errors - bool result = true; + any_errors = (! errors.empty()); + any_warnings = (! warnings.empty()); - if (! errors.empty()) + if (any_errors) { - result = false; for (std::list::iterator iter = errors.begin(); iter != errors.end(); ++iter) { @@ -660,17 +668,14 @@ QPDF::checkLinearizationInternal() } } - if (! warnings.empty()) + if (any_warnings) { - result = false; for (std::list::iterator iter = warnings.begin(); iter != warnings.end(); ++iter) { *this->m->out_stream << "WARNING: " << (*iter) << std::endl; } } - - return result; } qpdf_offset_t @@ -1084,7 +1089,9 @@ QPDF::showLinearizationData() try { readLinearizationData(); - checkLinearizationInternal(); + bool errors = false; + bool warnings = false; + checkLinearizationInternal(errors, warnings); dumpLinearizationDataInternal(); } catch (QPDFExc& e) diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 59c452e8..c0cbeb10 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -4329,6 +4329,14 @@ print "\n"; Google's OSS-Fuzz project. + + + When qpdf --check or qpdf + --check-linearization encounters a file with + linearization warnings but not errors, it now properly exits + with exit code 3 instead of 2. + + @@ -4412,6 +4420,14 @@ print "\n"; QUtil::read_file_into_memory was added. + + + A new version of + QPDF::checkLinearization() has been + added that indicates separately whether there were errors or + warnings. + + diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index cbda36a1..01dec0fc 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -3181,6 +3181,7 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) // continue to perform additional checks after finding // errors. bool okay = true; + bool warnings = false; std::cout << "checking " << o.infilename << std::endl; try { @@ -3196,11 +3197,18 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) if (pdf.isLinearized()) { std::cout << "File is linearized\n"; - if (! pdf.checkLinearization()) + bool lin_errors = false; + bool lin_warnings = false; + // any errors or warnings are reported by checkLinearization() + pdf.checkLinearization(lin_errors, lin_warnings); + if (lin_errors) { - // any errors are reported by checkLinearization() okay = false; } + else if (lin_warnings) + { + warnings = true; + } } else { @@ -3246,7 +3254,7 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) } if (okay) { - if (! pdf.getWarnings().empty()) + if ((! pdf.getWarnings().empty()) || warnings) { exit_code = EXIT_WARNING; } @@ -3775,14 +3783,21 @@ static void do_inspection(QPDF& pdf, Options& o) } if (o.check_linearization) { - if (pdf.checkLinearization()) + bool lin_errors = false; + bool lin_warnings = false; + pdf.checkLinearization(lin_errors, lin_warnings); + if (lin_errors) { - std::cout << o.infilename << ": no linearization errors" - << std::endl; + exit_code = EXIT_ERROR; + } + else if (lin_warnings && (exit_code != EXIT_ERROR)) + { + exit_code = EXIT_WARNING; } else { - exit_code = EXIT_ERROR; + std::cout << o.infilename << ": no linearization errors" + << std::endl; } } if (o.show_linearization) diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 0069fe4a..e1db8b89 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -2855,7 +2855,7 @@ my @to_linearize = ); $n_tests += @linearized_files + 6; -$n_tests += (3 * @to_linearize * 5) + 6; +$n_tests += (3 * @to_linearize * 5) + 8; foreach my $base (@linearized_files) { @@ -2939,6 +2939,17 @@ foreach my $base (@to_linearize) } } +# Verify that we get proper exit codes for files with only warnings +$td->runtest("linearization warnings check", + {$td->COMMAND => "qpdf --check lin3.pdf"}, + {$td->FILE => "lin3-check.out", $td->EXIT_STATUS => 3}, + $td->NORMALIZE_NEWLINES); +$td->runtest("linearization warnings check-linearization", + {$td->COMMAND => "qpdf --check-linearization lin3.pdf"}, + {$td->FILE => "lin3-check-linearization.out", + $td->EXIT_STATUS => 3}, + $td->NORMALIZE_NEWLINES); + show_ntests(); # ---------- $td->notify("--- Encryption Tests ---"); diff --git a/qpdf/qtest/qpdf/lin3-check-linearization.out b/qpdf/qtest/qpdf/lin3-check-linearization.out new file mode 100644 index 00000000..b8fda80a --- /dev/null +++ b/qpdf/qtest/qpdf/lin3-check-linearization.out @@ -0,0 +1,61 @@ +WARNING: end of first page section (/E) mismatch: /E = 3978; computed = 3785..3786 +WARNING: page 1: shared object 107: in computed list but not hint table +WARNING: page 1: shared object 109: in computed list but not hint table +WARNING: page 2: shared object 107: in computed list but not hint table +WARNING: page 2: shared object 109: in computed list but not hint table +WARNING: page 3: shared object 107: in computed list but not hint table +WARNING: page 3: shared object 109: in computed list but not hint table +WARNING: page 4: shared object 107: in computed list but not hint table +WARNING: page 4: shared object 109: in computed list but not hint table +WARNING: page 5: shared object 107: in computed list but not hint table +WARNING: page 5: shared object 109: in computed list but not hint table +WARNING: page 6: shared object 107: in computed list but not hint table +WARNING: page 6: shared object 109: in computed list but not hint table +WARNING: page 7: shared object 107: in computed list but not hint table +WARNING: page 7: shared object 109: in computed list but not hint table +WARNING: page 8: shared object 107: in computed list but not hint table +WARNING: page 8: shared object 109: in computed list but not hint table +WARNING: page 9: shared object 107: in computed list but not hint table +WARNING: page 9: shared object 109: in computed list but not hint table +WARNING: page 10: shared object 107: in computed list but not hint table +WARNING: page 10: shared object 109: in computed list but not hint table +WARNING: page 11: shared object 107: in computed list but not hint table +WARNING: page 11: shared object 109: in computed list but not hint table +WARNING: page 12: shared object 107: in computed list but not hint table +WARNING: page 12: shared object 109: in computed list but not hint table +WARNING: page 13: shared object 107: in computed list but not hint table +WARNING: page 13: shared object 109: in computed list but not hint table +WARNING: page 14: shared object 107: in computed list but not hint table +WARNING: page 14: shared object 109: in computed list but not hint table +WARNING: page 15: shared object 107: in computed list but not hint table +WARNING: page 15: shared object 109: in computed list but not hint table +WARNING: page 16: shared object 107: in computed list but not hint table +WARNING: page 16: shared object 109: in computed list but not hint table +WARNING: page 17: shared object 107: in computed list but not hint table +WARNING: page 17: shared object 109: in computed list but not hint table +WARNING: page 18: shared object 107: in computed list but not hint table +WARNING: page 18: shared object 109: in computed list but not hint table +WARNING: page 19: shared object 107: in computed list but not hint table +WARNING: page 19: shared object 109: in computed list but not hint table +WARNING: page 20: shared object 107: in computed list but not hint table +WARNING: page 20: shared object 109: in computed list but not hint table +WARNING: page 21: shared object 107: in computed list but not hint table +WARNING: page 21: shared object 109: in computed list but not hint table +WARNING: page 22: shared object 107: in computed list but not hint table +WARNING: page 22: shared object 109: in computed list but not hint table +WARNING: page 23: shared object 107: in computed list but not hint table +WARNING: page 23: shared object 109: in computed list but not hint table +WARNING: page 24: shared object 107: in computed list but not hint table +WARNING: page 24: shared object 109: in computed list but not hint table +WARNING: page 25: shared object 107: in computed list but not hint table +WARNING: page 25: shared object 109: in computed list but not hint table +WARNING: page 26: shared object 107: in computed list but not hint table +WARNING: page 26: shared object 109: in computed list but not hint table +WARNING: page 27: shared object 107: in computed list but not hint table +WARNING: page 27: shared object 109: in computed list but not hint table +WARNING: page 28: shared object 107: in computed list but not hint table +WARNING: page 28: shared object 109: in computed list but not hint table +WARNING: page 29: shared object 107: in computed list but not hint table +WARNING: page 29: shared object 109: in computed list but not hint table +WARNING: incorrect offset in outlines table: hint table = 1627; computed = 1547 +WARNING: incorrect length in outlines table: hint table = 1988; computed = 1936 diff --git a/qpdf/qtest/qpdf/lin3-check.out b/qpdf/qtest/qpdf/lin3-check.out new file mode 100644 index 00000000..ecebb687 --- /dev/null +++ b/qpdf/qtest/qpdf/lin3-check.out @@ -0,0 +1,65 @@ +checking lin3.pdf +PDF Version: 1.3 +File is not encrypted +File is linearized +WARNING: end of first page section (/E) mismatch: /E = 3978; computed = 3785..3786 +WARNING: page 1: shared object 107: in computed list but not hint table +WARNING: page 1: shared object 109: in computed list but not hint table +WARNING: page 2: shared object 107: in computed list but not hint table +WARNING: page 2: shared object 109: in computed list but not hint table +WARNING: page 3: shared object 107: in computed list but not hint table +WARNING: page 3: shared object 109: in computed list but not hint table +WARNING: page 4: shared object 107: in computed list but not hint table +WARNING: page 4: shared object 109: in computed list but not hint table +WARNING: page 5: shared object 107: in computed list but not hint table +WARNING: page 5: shared object 109: in computed list but not hint table +WARNING: page 6: shared object 107: in computed list but not hint table +WARNING: page 6: shared object 109: in computed list but not hint table +WARNING: page 7: shared object 107: in computed list but not hint table +WARNING: page 7: shared object 109: in computed list but not hint table +WARNING: page 8: shared object 107: in computed list but not hint table +WARNING: page 8: shared object 109: in computed list but not hint table +WARNING: page 9: shared object 107: in computed list but not hint table +WARNING: page 9: shared object 109: in computed list but not hint table +WARNING: page 10: shared object 107: in computed list but not hint table +WARNING: page 10: shared object 109: in computed list but not hint table +WARNING: page 11: shared object 107: in computed list but not hint table +WARNING: page 11: shared object 109: in computed list but not hint table +WARNING: page 12: shared object 107: in computed list but not hint table +WARNING: page 12: shared object 109: in computed list but not hint table +WARNING: page 13: shared object 107: in computed list but not hint table +WARNING: page 13: shared object 109: in computed list but not hint table +WARNING: page 14: shared object 107: in computed list but not hint table +WARNING: page 14: shared object 109: in computed list but not hint table +WARNING: page 15: shared object 107: in computed list but not hint table +WARNING: page 15: shared object 109: in computed list but not hint table +WARNING: page 16: shared object 107: in computed list but not hint table +WARNING: page 16: shared object 109: in computed list but not hint table +WARNING: page 17: shared object 107: in computed list but not hint table +WARNING: page 17: shared object 109: in computed list but not hint table +WARNING: page 18: shared object 107: in computed list but not hint table +WARNING: page 18: shared object 109: in computed list but not hint table +WARNING: page 19: shared object 107: in computed list but not hint table +WARNING: page 19: shared object 109: in computed list but not hint table +WARNING: page 20: shared object 107: in computed list but not hint table +WARNING: page 20: shared object 109: in computed list but not hint table +WARNING: page 21: shared object 107: in computed list but not hint table +WARNING: page 21: shared object 109: in computed list but not hint table +WARNING: page 22: shared object 107: in computed list but not hint table +WARNING: page 22: shared object 109: in computed list but not hint table +WARNING: page 23: shared object 107: in computed list but not hint table +WARNING: page 23: shared object 109: in computed list but not hint table +WARNING: page 24: shared object 107: in computed list but not hint table +WARNING: page 24: shared object 109: in computed list but not hint table +WARNING: page 25: shared object 107: in computed list but not hint table +WARNING: page 25: shared object 109: in computed list but not hint table +WARNING: page 26: shared object 107: in computed list but not hint table +WARNING: page 26: shared object 109: in computed list but not hint table +WARNING: page 27: shared object 107: in computed list but not hint table +WARNING: page 27: shared object 109: in computed list but not hint table +WARNING: page 28: shared object 107: in computed list but not hint table +WARNING: page 28: shared object 109: in computed list but not hint table +WARNING: page 29: shared object 107: in computed list but not hint table +WARNING: page 29: shared object 109: in computed list but not hint table +WARNING: incorrect offset in outlines table: hint table = 1627; computed = 1547 +WARNING: incorrect length in outlines table: hint table = 1988; computed = 1936