Commit 85a3f95a89ca392a3726f8d964024dfd10177e09

Authored by Jay Berkenbilt
1 parent 557bd3c2

qpdf: exit 3 for linearization warnings without errors (fixes #50)

ChangeLog
1 2019-06-22 Jay Berkenbilt <ejb@ql.org> 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 * Add new function QUtil::read_file_into_memory. 7 * Add new function QUtil::read_file_into_memory.
4 8
5 2019-06-21 Jay Berkenbilt <ejb@ql.org> 9 2019-06-21 Jay Berkenbilt <ejb@ql.org>
include/qpdf/QPDF.hh
@@ -483,6 +483,9 @@ class QPDF @@ -483,6 +483,9 @@ class QPDF
483 // specified in a call to setOutputStreams. 483 // specified in a call to setOutputStreams.
484 QPDF_DLL 484 QPDF_DLL
485 bool checkLinearization(); 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 // Calls checkLinearization() and, if possible, prints normalized 490 // Calls checkLinearization() and, if possible, prints normalized
488 // contents of some of the hints tables to std::cout or the output 491 // contents of some of the hints tables to std::cout or the output
@@ -1226,7 +1229,7 @@ class QPDF @@ -1226,7 +1229,7 @@ class QPDF
1226 // methods to support linearization checking -- implemented in 1229 // methods to support linearization checking -- implemented in
1227 // QPDF_linearization.cc 1230 // QPDF_linearization.cc
1228 void readLinearizationData(); 1231 void readLinearizationData();
1229 - bool checkLinearizationInternal(); 1232 + void checkLinearizationInternal(bool& errors, bool& warnings);
1230 void dumpLinearizationDataInternal(); 1233 void dumpLinearizationDataInternal();
1231 QPDFObjectHandle readHintStream( 1234 QPDFObjectHandle readHintStream(
1232 Pipeline&, qpdf_offset_t offset, size_t length); 1235 Pipeline&, qpdf_offset_t offset, size_t length);
libqpdf/QPDF_linearization.cc
@@ -65,17 +65,25 @@ load_vector_vector(BitStream&amp; bit_stream, @@ -65,17 +65,25 @@ load_vector_vector(BitStream&amp; bit_stream,
65 bool 65 bool
66 QPDF::checkLinearization() 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 try 77 try
70 { 78 {
71 readLinearizationData(); 79 readLinearizationData();
72 - result = checkLinearizationInternal(); 80 + checkLinearizationInternal(errors, warnings);
73 } 81 }
74 catch (QPDFExc& e) 82 catch (QPDFExc& e)
75 { 83 {
76 *this->m->out_stream << e.what() << std::endl; 84 *this->m->out_stream << e.what() << std::endl;
  85 + errors = true;
77 } 86 }
78 - return result;  
79 } 87 }
80 88
81 bool 89 bool
@@ -499,8 +507,8 @@ QPDF::readHGeneric(BitStream h, HGeneric&amp; t) @@ -499,8 +507,8 @@ QPDF::readHGeneric(BitStream h, HGeneric&amp; t)
499 t.group_length = h.getBitsInt(32); // 4 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 // All comments referring to the PDF spec refer to the spec for 513 // All comments referring to the PDF spec refer to the spec for
506 // version 1.4. 514 // version 1.4.
@@ -648,11 +656,11 @@ QPDF::checkLinearizationInternal() @@ -648,11 +656,11 @@ QPDF::checkLinearizationInternal()
648 656
649 // Report errors 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 for (std::list<std::string>::iterator iter = errors.begin(); 664 for (std::list<std::string>::iterator iter = errors.begin();
657 iter != errors.end(); ++iter) 665 iter != errors.end(); ++iter)
658 { 666 {
@@ -660,17 +668,14 @@ QPDF::checkLinearizationInternal() @@ -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 for (std::list<std::string>::iterator iter = warnings.begin(); 673 for (std::list<std::string>::iterator iter = warnings.begin();
667 iter != warnings.end(); ++iter) 674 iter != warnings.end(); ++iter)
668 { 675 {
669 *this->m->out_stream << "WARNING: " << (*iter) << std::endl; 676 *this->m->out_stream << "WARNING: " << (*iter) << std::endl;
670 } 677 }
671 } 678 }
672 -  
673 - return result;  
674 } 679 }
675 680
676 qpdf_offset_t 681 qpdf_offset_t
@@ -1084,7 +1089,9 @@ QPDF::showLinearizationData() @@ -1084,7 +1089,9 @@ QPDF::showLinearizationData()
1084 try 1089 try
1085 { 1090 {
1086 readLinearizationData(); 1091 readLinearizationData();
1087 - checkLinearizationInternal(); 1092 + bool errors = false;
  1093 + bool warnings = false;
  1094 + checkLinearizationInternal(errors, warnings);
1088 dumpLinearizationDataInternal(); 1095 dumpLinearizationDataInternal();
1089 } 1096 }
1090 catch (QPDFExc& e) 1097 catch (QPDFExc& e)
manual/qpdf-manual.xml
@@ -4329,6 +4329,14 @@ print &quot;\n&quot;; @@ -4329,6 +4329,14 @@ print &quot;\n&quot;;
4329 Google's OSS-Fuzz project. 4329 Google's OSS-Fuzz project.
4330 </para> 4330 </para>
4331 </listitem> 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 </itemizedlist> 4340 </itemizedlist>
4333 </listitem> 4341 </listitem>
4334 <listitem> 4342 <listitem>
@@ -4412,6 +4420,14 @@ print &quot;\n&quot;; @@ -4412,6 +4420,14 @@ print &quot;\n&quot;;
4412 <function>QUtil::read_file_into_memory</function> was added. 4420 <function>QUtil::read_file_into_memory</function> was added.
4413 </para> 4421 </para>
4414 </listitem> 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 </itemizedlist> 4431 </itemizedlist>
4416 </listitem> 4432 </listitem>
4417 <listitem> 4433 <listitem>
qpdf/qpdf.cc
@@ -3181,6 +3181,7 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code) @@ -3181,6 +3181,7 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code)
3181 // continue to perform additional checks after finding 3181 // continue to perform additional checks after finding
3182 // errors. 3182 // errors.
3183 bool okay = true; 3183 bool okay = true;
  3184 + bool warnings = false;
3184 std::cout << "checking " << o.infilename << std::endl; 3185 std::cout << "checking " << o.infilename << std::endl;
3185 try 3186 try
3186 { 3187 {
@@ -3196,11 +3197,18 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code) @@ -3196,11 +3197,18 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code)
3196 if (pdf.isLinearized()) 3197 if (pdf.isLinearized())
3197 { 3198 {
3198 std::cout << "File is linearized\n"; 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 okay = false; 3206 okay = false;
3203 } 3207 }
  3208 + else if (lin_warnings)
  3209 + {
  3210 + warnings = true;
  3211 + }
3204 } 3212 }
3205 else 3213 else
3206 { 3214 {
@@ -3246,7 +3254,7 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code) @@ -3246,7 +3254,7 @@ static void do_check(QPDF&amp; pdf, Options&amp; o, int&amp; exit_code)
3246 } 3254 }
3247 if (okay) 3255 if (okay)
3248 { 3256 {
3249 - if (! pdf.getWarnings().empty()) 3257 + if ((! pdf.getWarnings().empty()) || warnings)
3250 { 3258 {
3251 exit_code = EXIT_WARNING; 3259 exit_code = EXIT_WARNING;
3252 } 3260 }
@@ -3775,14 +3783,21 @@ static void do_inspection(QPDF&amp; pdf, Options&amp; o) @@ -3775,14 +3783,21 @@ static void do_inspection(QPDF&amp; pdf, Options&amp; o)
3775 } 3783 }
3776 if (o.check_linearization) 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 else 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 if (o.show_linearization) 3803 if (o.show_linearization)
qpdf/qtest/qpdf.test
@@ -2855,7 +2855,7 @@ my @to_linearize = @@ -2855,7 +2855,7 @@ my @to_linearize =
2855 ); 2855 );
2856 2856
2857 $n_tests += @linearized_files + 6; 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 foreach my $base (@linearized_files) 2860 foreach my $base (@linearized_files)
2861 { 2861 {
@@ -2939,6 +2939,17 @@ foreach my $base (@to_linearize) @@ -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 show_ntests(); 2953 show_ntests();
2943 # ---------- 2954 # ----------
2944 $td->notify("--- Encryption Tests ---"); 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