Commit 85a3f95a89ca392a3726f8d964024dfd10177e09

Authored by Jay Berkenbilt
1 parent 557bd3c2

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

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&amp; 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&amp; 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 &quot;\n&quot;;
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 &quot;\n&quot;;
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&amp; pdf, Options&amp; o, int&amp; 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&amp; pdf, Options&amp; o, int&amp; 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&amp; pdf, Options&amp; o, int&amp; 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&amp; pdf, Options&amp; 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
... ...