Commit 85a3f95a89ca392a3726f8d964024dfd10177e09
1 parent
557bd3c2
qpdf: exit 3 for linearization warnings without errors (fixes #50)
Showing
8 changed files
with
204 additions
and
22 deletions
ChangeLog
| 1 | 1 | 2019-06-22 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | |
| 3 | + * When a file has linearization warnings but no errors, qpdf | |
| 4 | + --check and --check-linearization now exit with code 3 instead | |
| 5 | + of 2. Fixes #50. | |
| 6 | + | |
| 3 | 7 | * Add new function QUtil::read_file_into_memory. |
| 4 | 8 | |
| 5 | 9 | 2019-06-21 Jay Berkenbilt <ejb@ql.org> | ... | ... |
include/qpdf/QPDF.hh
| ... | ... | @@ -483,6 +483,9 @@ class QPDF |
| 483 | 483 | // specified in a call to setOutputStreams. |
| 484 | 484 | QPDF_DLL |
| 485 | 485 | bool checkLinearization(); |
| 486 | + // Separately indicate whether there were errors or warnings. | |
| 487 | + QPDF_DLL | |
| 488 | + void checkLinearization(bool& errors, bool& warnings); | |
| 486 | 489 | |
| 487 | 490 | // Calls checkLinearization() and, if possible, prints normalized |
| 488 | 491 | // contents of some of the hints tables to std::cout or the output |
| ... | ... | @@ -1226,7 +1229,7 @@ class QPDF |
| 1226 | 1229 | // methods to support linearization checking -- implemented in |
| 1227 | 1230 | // QPDF_linearization.cc |
| 1228 | 1231 | void readLinearizationData(); |
| 1229 | - bool checkLinearizationInternal(); | |
| 1232 | + void checkLinearizationInternal(bool& errors, bool& warnings); | |
| 1230 | 1233 | void dumpLinearizationDataInternal(); |
| 1231 | 1234 | QPDFObjectHandle readHintStream( |
| 1232 | 1235 | Pipeline&, qpdf_offset_t offset, size_t length); | ... | ... |
libqpdf/QPDF_linearization.cc
| ... | ... | @@ -65,17 +65,25 @@ load_vector_vector(BitStream& bit_stream, |
| 65 | 65 | bool |
| 66 | 66 | QPDF::checkLinearization() |
| 67 | 67 | { |
| 68 | - bool result = false; | |
| 68 | + bool errors = false; | |
| 69 | + bool warnings = false; | |
| 70 | + checkLinearization(errors, warnings); | |
| 71 | + return (! (errors || warnings)); | |
| 72 | +} | |
| 73 | + | |
| 74 | +void | |
| 75 | +QPDF::checkLinearization(bool& errors, bool& warnings) | |
| 76 | +{ | |
| 69 | 77 | try |
| 70 | 78 | { |
| 71 | 79 | readLinearizationData(); |
| 72 | - result = checkLinearizationInternal(); | |
| 80 | + checkLinearizationInternal(errors, warnings); | |
| 73 | 81 | } |
| 74 | 82 | catch (QPDFExc& e) |
| 75 | 83 | { |
| 76 | 84 | *this->m->out_stream << e.what() << std::endl; |
| 85 | + errors = true; | |
| 77 | 86 | } |
| 78 | - return result; | |
| 79 | 87 | } |
| 80 | 88 | |
| 81 | 89 | bool |
| ... | ... | @@ -499,8 +507,8 @@ QPDF::readHGeneric(BitStream h, HGeneric& t) |
| 499 | 507 | t.group_length = h.getBitsInt(32); // 4 |
| 500 | 508 | } |
| 501 | 509 | |
| 502 | -bool | |
| 503 | -QPDF::checkLinearizationInternal() | |
| 510 | +void | |
| 511 | +QPDF::checkLinearizationInternal(bool& any_errors, bool& any_warnings) | |
| 504 | 512 | { |
| 505 | 513 | // All comments referring to the PDF spec refer to the spec for |
| 506 | 514 | // version 1.4. |
| ... | ... | @@ -648,11 +656,11 @@ QPDF::checkLinearizationInternal() |
| 648 | 656 | |
| 649 | 657 | // Report errors |
| 650 | 658 | |
| 651 | - bool result = true; | |
| 659 | + any_errors = (! errors.empty()); | |
| 660 | + any_warnings = (! warnings.empty()); | |
| 652 | 661 | |
| 653 | - if (! errors.empty()) | |
| 662 | + if (any_errors) | |
| 654 | 663 | { |
| 655 | - result = false; | |
| 656 | 664 | for (std::list<std::string>::iterator iter = errors.begin(); |
| 657 | 665 | iter != errors.end(); ++iter) |
| 658 | 666 | { |
| ... | ... | @@ -660,17 +668,14 @@ QPDF::checkLinearizationInternal() |
| 660 | 668 | } |
| 661 | 669 | } |
| 662 | 670 | |
| 663 | - if (! warnings.empty()) | |
| 671 | + if (any_warnings) | |
| 664 | 672 | { |
| 665 | - result = false; | |
| 666 | 673 | for (std::list<std::string>::iterator iter = warnings.begin(); |
| 667 | 674 | iter != warnings.end(); ++iter) |
| 668 | 675 | { |
| 669 | 676 | *this->m->out_stream << "WARNING: " << (*iter) << std::endl; |
| 670 | 677 | } |
| 671 | 678 | } |
| 672 | - | |
| 673 | - return result; | |
| 674 | 679 | } |
| 675 | 680 | |
| 676 | 681 | qpdf_offset_t |
| ... | ... | @@ -1084,7 +1089,9 @@ QPDF::showLinearizationData() |
| 1084 | 1089 | try |
| 1085 | 1090 | { |
| 1086 | 1091 | readLinearizationData(); |
| 1087 | - checkLinearizationInternal(); | |
| 1092 | + bool errors = false; | |
| 1093 | + bool warnings = false; | |
| 1094 | + checkLinearizationInternal(errors, warnings); | |
| 1088 | 1095 | dumpLinearizationDataInternal(); |
| 1089 | 1096 | } |
| 1090 | 1097 | catch (QPDFExc& e) | ... | ... |
manual/qpdf-manual.xml
| ... | ... | @@ -4329,6 +4329,14 @@ print "\n"; |
| 4329 | 4329 | Google's OSS-Fuzz project. |
| 4330 | 4330 | </para> |
| 4331 | 4331 | </listitem> |
| 4332 | + <listitem> | |
| 4333 | + <para> | |
| 4334 | + When <command>qpdf --check</command> or <command>qpdf | |
| 4335 | + --check-linearization</command> encounters a file with | |
| 4336 | + linearization warnings but not errors, it now properly exits | |
| 4337 | + with exit code 3 instead of 2. | |
| 4338 | + </para> | |
| 4339 | + </listitem> | |
| 4332 | 4340 | </itemizedlist> |
| 4333 | 4341 | </listitem> |
| 4334 | 4342 | <listitem> |
| ... | ... | @@ -4412,6 +4420,14 @@ print "\n"; |
| 4412 | 4420 | <function>QUtil::read_file_into_memory</function> was added. |
| 4413 | 4421 | </para> |
| 4414 | 4422 | </listitem> |
| 4423 | + <listitem> | |
| 4424 | + <para> | |
| 4425 | + A new version of | |
| 4426 | + <function>QPDF::checkLinearization()</function> has been | |
| 4427 | + added that indicates separately whether there were errors or | |
| 4428 | + warnings. | |
| 4429 | + </para> | |
| 4430 | + </listitem> | |
| 4415 | 4431 | </itemizedlist> |
| 4416 | 4432 | </listitem> |
| 4417 | 4433 | <listitem> | ... | ... |
qpdf/qpdf.cc
| ... | ... | @@ -3181,6 +3181,7 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) |
| 3181 | 3181 | // continue to perform additional checks after finding |
| 3182 | 3182 | // errors. |
| 3183 | 3183 | bool okay = true; |
| 3184 | + bool warnings = false; | |
| 3184 | 3185 | std::cout << "checking " << o.infilename << std::endl; |
| 3185 | 3186 | try |
| 3186 | 3187 | { |
| ... | ... | @@ -3196,11 +3197,18 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) |
| 3196 | 3197 | if (pdf.isLinearized()) |
| 3197 | 3198 | { |
| 3198 | 3199 | std::cout << "File is linearized\n"; |
| 3199 | - if (! pdf.checkLinearization()) | |
| 3200 | + bool lin_errors = false; | |
| 3201 | + bool lin_warnings = false; | |
| 3202 | + // any errors or warnings are reported by checkLinearization() | |
| 3203 | + pdf.checkLinearization(lin_errors, lin_warnings); | |
| 3204 | + if (lin_errors) | |
| 3200 | 3205 | { |
| 3201 | - // any errors are reported by checkLinearization() | |
| 3202 | 3206 | okay = false; |
| 3203 | 3207 | } |
| 3208 | + else if (lin_warnings) | |
| 3209 | + { | |
| 3210 | + warnings = true; | |
| 3211 | + } | |
| 3204 | 3212 | } |
| 3205 | 3213 | else |
| 3206 | 3214 | { |
| ... | ... | @@ -3246,7 +3254,7 @@ static void do_check(QPDF& pdf, Options& o, int& exit_code) |
| 3246 | 3254 | } |
| 3247 | 3255 | if (okay) |
| 3248 | 3256 | { |
| 3249 | - if (! pdf.getWarnings().empty()) | |
| 3257 | + if ((! pdf.getWarnings().empty()) || warnings) | |
| 3250 | 3258 | { |
| 3251 | 3259 | exit_code = EXIT_WARNING; |
| 3252 | 3260 | } |
| ... | ... | @@ -3775,14 +3783,21 @@ static void do_inspection(QPDF& pdf, Options& o) |
| 3775 | 3783 | } |
| 3776 | 3784 | if (o.check_linearization) |
| 3777 | 3785 | { |
| 3778 | - if (pdf.checkLinearization()) | |
| 3786 | + bool lin_errors = false; | |
| 3787 | + bool lin_warnings = false; | |
| 3788 | + pdf.checkLinearization(lin_errors, lin_warnings); | |
| 3789 | + if (lin_errors) | |
| 3779 | 3790 | { |
| 3780 | - std::cout << o.infilename << ": no linearization errors" | |
| 3781 | - << std::endl; | |
| 3791 | + exit_code = EXIT_ERROR; | |
| 3792 | + } | |
| 3793 | + else if (lin_warnings && (exit_code != EXIT_ERROR)) | |
| 3794 | + { | |
| 3795 | + exit_code = EXIT_WARNING; | |
| 3782 | 3796 | } |
| 3783 | 3797 | else |
| 3784 | 3798 | { |
| 3785 | - exit_code = EXIT_ERROR; | |
| 3799 | + std::cout << o.infilename << ": no linearization errors" | |
| 3800 | + << std::endl; | |
| 3786 | 3801 | } |
| 3787 | 3802 | } |
| 3788 | 3803 | if (o.show_linearization) | ... | ... |
qpdf/qtest/qpdf.test
| ... | ... | @@ -2855,7 +2855,7 @@ my @to_linearize = |
| 2855 | 2855 | ); |
| 2856 | 2856 | |
| 2857 | 2857 | $n_tests += @linearized_files + 6; |
| 2858 | -$n_tests += (3 * @to_linearize * 5) + 6; | |
| 2858 | +$n_tests += (3 * @to_linearize * 5) + 8; | |
| 2859 | 2859 | |
| 2860 | 2860 | foreach my $base (@linearized_files) |
| 2861 | 2861 | { |
| ... | ... | @@ -2939,6 +2939,17 @@ foreach my $base (@to_linearize) |
| 2939 | 2939 | } |
| 2940 | 2940 | } |
| 2941 | 2941 | |
| 2942 | +# Verify that we get proper exit codes for files with only warnings | |
| 2943 | +$td->runtest("linearization warnings check", | |
| 2944 | + {$td->COMMAND => "qpdf --check lin3.pdf"}, | |
| 2945 | + {$td->FILE => "lin3-check.out", $td->EXIT_STATUS => 3}, | |
| 2946 | + $td->NORMALIZE_NEWLINES); | |
| 2947 | +$td->runtest("linearization warnings check-linearization", | |
| 2948 | + {$td->COMMAND => "qpdf --check-linearization lin3.pdf"}, | |
| 2949 | + {$td->FILE => "lin3-check-linearization.out", | |
| 2950 | + $td->EXIT_STATUS => 3}, | |
| 2951 | + $td->NORMALIZE_NEWLINES); | |
| 2952 | + | |
| 2942 | 2953 | show_ntests(); |
| 2943 | 2954 | # ---------- |
| 2944 | 2955 | $td->notify("--- Encryption Tests ---"); | ... | ... |
qpdf/qtest/qpdf/lin3-check-linearization.out
0 → 100644
| 1 | +WARNING: end of first page section (/E) mismatch: /E = 3978; computed = 3785..3786 | |
| 2 | +WARNING: page 1: shared object 107: in computed list but not hint table | |
| 3 | +WARNING: page 1: shared object 109: in computed list but not hint table | |
| 4 | +WARNING: page 2: shared object 107: in computed list but not hint table | |
| 5 | +WARNING: page 2: shared object 109: in computed list but not hint table | |
| 6 | +WARNING: page 3: shared object 107: in computed list but not hint table | |
| 7 | +WARNING: page 3: shared object 109: in computed list but not hint table | |
| 8 | +WARNING: page 4: shared object 107: in computed list but not hint table | |
| 9 | +WARNING: page 4: shared object 109: in computed list but not hint table | |
| 10 | +WARNING: page 5: shared object 107: in computed list but not hint table | |
| 11 | +WARNING: page 5: shared object 109: in computed list but not hint table | |
| 12 | +WARNING: page 6: shared object 107: in computed list but not hint table | |
| 13 | +WARNING: page 6: shared object 109: in computed list but not hint table | |
| 14 | +WARNING: page 7: shared object 107: in computed list but not hint table | |
| 15 | +WARNING: page 7: shared object 109: in computed list but not hint table | |
| 16 | +WARNING: page 8: shared object 107: in computed list but not hint table | |
| 17 | +WARNING: page 8: shared object 109: in computed list but not hint table | |
| 18 | +WARNING: page 9: shared object 107: in computed list but not hint table | |
| 19 | +WARNING: page 9: shared object 109: in computed list but not hint table | |
| 20 | +WARNING: page 10: shared object 107: in computed list but not hint table | |
| 21 | +WARNING: page 10: shared object 109: in computed list but not hint table | |
| 22 | +WARNING: page 11: shared object 107: in computed list but not hint table | |
| 23 | +WARNING: page 11: shared object 109: in computed list but not hint table | |
| 24 | +WARNING: page 12: shared object 107: in computed list but not hint table | |
| 25 | +WARNING: page 12: shared object 109: in computed list but not hint table | |
| 26 | +WARNING: page 13: shared object 107: in computed list but not hint table | |
| 27 | +WARNING: page 13: shared object 109: in computed list but not hint table | |
| 28 | +WARNING: page 14: shared object 107: in computed list but not hint table | |
| 29 | +WARNING: page 14: shared object 109: in computed list but not hint table | |
| 30 | +WARNING: page 15: shared object 107: in computed list but not hint table | |
| 31 | +WARNING: page 15: shared object 109: in computed list but not hint table | |
| 32 | +WARNING: page 16: shared object 107: in computed list but not hint table | |
| 33 | +WARNING: page 16: shared object 109: in computed list but not hint table | |
| 34 | +WARNING: page 17: shared object 107: in computed list but not hint table | |
| 35 | +WARNING: page 17: shared object 109: in computed list but not hint table | |
| 36 | +WARNING: page 18: shared object 107: in computed list but not hint table | |
| 37 | +WARNING: page 18: shared object 109: in computed list but not hint table | |
| 38 | +WARNING: page 19: shared object 107: in computed list but not hint table | |
| 39 | +WARNING: page 19: shared object 109: in computed list but not hint table | |
| 40 | +WARNING: page 20: shared object 107: in computed list but not hint table | |
| 41 | +WARNING: page 20: shared object 109: in computed list but not hint table | |
| 42 | +WARNING: page 21: shared object 107: in computed list but not hint table | |
| 43 | +WARNING: page 21: shared object 109: in computed list but not hint table | |
| 44 | +WARNING: page 22: shared object 107: in computed list but not hint table | |
| 45 | +WARNING: page 22: shared object 109: in computed list but not hint table | |
| 46 | +WARNING: page 23: shared object 107: in computed list but not hint table | |
| 47 | +WARNING: page 23: shared object 109: in computed list but not hint table | |
| 48 | +WARNING: page 24: shared object 107: in computed list but not hint table | |
| 49 | +WARNING: page 24: shared object 109: in computed list but not hint table | |
| 50 | +WARNING: page 25: shared object 107: in computed list but not hint table | |
| 51 | +WARNING: page 25: shared object 109: in computed list but not hint table | |
| 52 | +WARNING: page 26: shared object 107: in computed list but not hint table | |
| 53 | +WARNING: page 26: shared object 109: in computed list but not hint table | |
| 54 | +WARNING: page 27: shared object 107: in computed list but not hint table | |
| 55 | +WARNING: page 27: shared object 109: in computed list but not hint table | |
| 56 | +WARNING: page 28: shared object 107: in computed list but not hint table | |
| 57 | +WARNING: page 28: shared object 109: in computed list but not hint table | |
| 58 | +WARNING: page 29: shared object 107: in computed list but not hint table | |
| 59 | +WARNING: page 29: shared object 109: in computed list but not hint table | |
| 60 | +WARNING: incorrect offset in outlines table: hint table = 1627; computed = 1547 | |
| 61 | +WARNING: incorrect length in outlines table: hint table = 1988; computed = 1936 | ... | ... |
qpdf/qtest/qpdf/lin3-check.out
0 → 100644
| 1 | +checking lin3.pdf | |
| 2 | +PDF Version: 1.3 | |
| 3 | +File is not encrypted | |
| 4 | +File is linearized | |
| 5 | +WARNING: end of first page section (/E) mismatch: /E = 3978; computed = 3785..3786 | |
| 6 | +WARNING: page 1: shared object 107: in computed list but not hint table | |
| 7 | +WARNING: page 1: shared object 109: in computed list but not hint table | |
| 8 | +WARNING: page 2: shared object 107: in computed list but not hint table | |
| 9 | +WARNING: page 2: shared object 109: in computed list but not hint table | |
| 10 | +WARNING: page 3: shared object 107: in computed list but not hint table | |
| 11 | +WARNING: page 3: shared object 109: in computed list but not hint table | |
| 12 | +WARNING: page 4: shared object 107: in computed list but not hint table | |
| 13 | +WARNING: page 4: shared object 109: in computed list but not hint table | |
| 14 | +WARNING: page 5: shared object 107: in computed list but not hint table | |
| 15 | +WARNING: page 5: shared object 109: in computed list but not hint table | |
| 16 | +WARNING: page 6: shared object 107: in computed list but not hint table | |
| 17 | +WARNING: page 6: shared object 109: in computed list but not hint table | |
| 18 | +WARNING: page 7: shared object 107: in computed list but not hint table | |
| 19 | +WARNING: page 7: shared object 109: in computed list but not hint table | |
| 20 | +WARNING: page 8: shared object 107: in computed list but not hint table | |
| 21 | +WARNING: page 8: shared object 109: in computed list but not hint table | |
| 22 | +WARNING: page 9: shared object 107: in computed list but not hint table | |
| 23 | +WARNING: page 9: shared object 109: in computed list but not hint table | |
| 24 | +WARNING: page 10: shared object 107: in computed list but not hint table | |
| 25 | +WARNING: page 10: shared object 109: in computed list but not hint table | |
| 26 | +WARNING: page 11: shared object 107: in computed list but not hint table | |
| 27 | +WARNING: page 11: shared object 109: in computed list but not hint table | |
| 28 | +WARNING: page 12: shared object 107: in computed list but not hint table | |
| 29 | +WARNING: page 12: shared object 109: in computed list but not hint table | |
| 30 | +WARNING: page 13: shared object 107: in computed list but not hint table | |
| 31 | +WARNING: page 13: shared object 109: in computed list but not hint table | |
| 32 | +WARNING: page 14: shared object 107: in computed list but not hint table | |
| 33 | +WARNING: page 14: shared object 109: in computed list but not hint table | |
| 34 | +WARNING: page 15: shared object 107: in computed list but not hint table | |
| 35 | +WARNING: page 15: shared object 109: in computed list but not hint table | |
| 36 | +WARNING: page 16: shared object 107: in computed list but not hint table | |
| 37 | +WARNING: page 16: shared object 109: in computed list but not hint table | |
| 38 | +WARNING: page 17: shared object 107: in computed list but not hint table | |
| 39 | +WARNING: page 17: shared object 109: in computed list but not hint table | |
| 40 | +WARNING: page 18: shared object 107: in computed list but not hint table | |
| 41 | +WARNING: page 18: shared object 109: in computed list but not hint table | |
| 42 | +WARNING: page 19: shared object 107: in computed list but not hint table | |
| 43 | +WARNING: page 19: shared object 109: in computed list but not hint table | |
| 44 | +WARNING: page 20: shared object 107: in computed list but not hint table | |
| 45 | +WARNING: page 20: shared object 109: in computed list but not hint table | |
| 46 | +WARNING: page 21: shared object 107: in computed list but not hint table | |
| 47 | +WARNING: page 21: shared object 109: in computed list but not hint table | |
| 48 | +WARNING: page 22: shared object 107: in computed list but not hint table | |
| 49 | +WARNING: page 22: shared object 109: in computed list but not hint table | |
| 50 | +WARNING: page 23: shared object 107: in computed list but not hint table | |
| 51 | +WARNING: page 23: shared object 109: in computed list but not hint table | |
| 52 | +WARNING: page 24: shared object 107: in computed list but not hint table | |
| 53 | +WARNING: page 24: shared object 109: in computed list but not hint table | |
| 54 | +WARNING: page 25: shared object 107: in computed list but not hint table | |
| 55 | +WARNING: page 25: shared object 109: in computed list but not hint table | |
| 56 | +WARNING: page 26: shared object 107: in computed list but not hint table | |
| 57 | +WARNING: page 26: shared object 109: in computed list but not hint table | |
| 58 | +WARNING: page 27: shared object 107: in computed list but not hint table | |
| 59 | +WARNING: page 27: shared object 109: in computed list but not hint table | |
| 60 | +WARNING: page 28: shared object 107: in computed list but not hint table | |
| 61 | +WARNING: page 28: shared object 109: in computed list but not hint table | |
| 62 | +WARNING: page 29: shared object 107: in computed list but not hint table | |
| 63 | +WARNING: page 29: shared object 109: in computed list but not hint table | |
| 64 | +WARNING: incorrect offset in outlines table: hint table = 1627; computed = 1547 | |
| 65 | +WARNING: incorrect length in outlines table: hint table = 1988; computed = 1936 | ... | ... |