Commit 54ac92eb1de607fba7fb5d7a8aaa2fbcf80deeb0

Authored by m-holger
Committed by GitHub
2 parents 75091093 c02cb9a7

Merge pull request #1271 from m-holger/rsl

Fix QPDF::recoverStreamLength
.idea/codeStyles/Project.xml
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <RiderCodeStyleSettings> 3 <RiderCodeStyleSettings>
4 <option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" /> 4 <option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="true" type="bool" />
5 </RiderCodeStyleSettings> 5 </RiderCodeStyleSettings>
6 - <SqlCodeStyleSettings version="7"> 6 + <SqlCodeStyleSettings version="6">
7 <option name="KEYWORD_CASE" value="2" /> 7 <option name="KEYWORD_CASE" value="2" />
8 </SqlCodeStyleSettings> 8 </SqlCodeStyleSettings>
9 <clangFormatSettings> 9 <clangFormatSettings>
libqpdf/QPDF.cc
@@ -1649,26 +1649,28 @@ QPDF::recoverStreamLength( @@ -1649,26 +1649,28 @@ QPDF::recoverStreamLength(
1649 } 1649 }
1650 1650
1651 if (length) { 1651 if (length) {
1652 - qpdf_offset_t this_obj_offset = 0;  
1653 - QPDFObjGen this_og; 1652 + auto end = stream_offset + toO(length);
  1653 + qpdf_offset_t found_offset = 0;
  1654 + QPDFObjGen found_og;
1654 1655
1655 // Make sure this is inside this object 1656 // Make sure this is inside this object
1656 - for (auto const& iter: m->xref_table) {  
1657 - QPDFXRefEntry const& entry = iter.second; 1657 + for (auto const& [current_og, entry]: m->xref_table) {
1658 if (entry.getType() == 1) { 1658 if (entry.getType() == 1) {
1659 qpdf_offset_t obj_offset = entry.getOffset(); 1659 qpdf_offset_t obj_offset = entry.getOffset();
1660 - if ((obj_offset > stream_offset) &&  
1661 - ((this_obj_offset == 0) || (this_obj_offset > obj_offset))) {  
1662 - this_obj_offset = obj_offset;  
1663 - this_og = iter.first; 1660 + if (found_offset < obj_offset && obj_offset < end) {
  1661 + found_offset = obj_offset;
  1662 + found_og = current_og;
1664 } 1663 }
1665 } 1664 }
1666 } 1665 }
1667 - if (this_obj_offset && (this_og == og)) {  
1668 - // Well, we found endstream\nendobj within the space allowed for this object, so we're  
1669 - // probably in good shape. 1666 + if (!found_offset || found_og == og) {
  1667 + // If we are trying to recover an XRef stream the xref table will not contain and
  1668 + // won't contain any entries, therefore we cannot check the found length. Otherwise we
  1669 + // found endstream\nendobj within the space allowed for this object, so we're probably
  1670 + // in good shape.
1670 } else { 1671 } else {
1671 QTC::TC("qpdf", "QPDF found wrong endstream in recovery"); 1672 QTC::TC("qpdf", "QPDF found wrong endstream in recovery");
  1673 + length = 0;
1672 } 1674 }
1673 } 1675 }
1674 1676
qpdf/qtest/error-condition.test
@@ -55,6 +55,7 @@ my @badfiles = (&quot;not a PDF file&quot;, # 1 @@ -55,6 +55,7 @@ my @badfiles = (&quot;not a PDF file&quot;, # 1
55 "bad dictionary key", # 36 55 "bad dictionary key", # 36
56 "space before xref", # 37 56 "space before xref", # 37
57 "startxref to space then eof", # 38 57 "startxref to space then eof", # 38
  58 + "stream lenth revocery overlapping", # 39
58 ); 59 );
59 60
60 $n_tests += @badfiles + 8; 61 $n_tests += @badfiles + 8;
@@ -65,7 +66,7 @@ $n_tests += @badfiles + 8; @@ -65,7 +66,7 @@ $n_tests += @badfiles + 8;
65 # have error conditions that used to be fatal but are now considered 66 # have error conditions that used to be fatal but are now considered
66 # non-fatal. 67 # non-fatal.
67 my %badtest_overrides = (); 68 my %badtest_overrides = ();
68 -for(6, 12..15, 17, 18..32, 34..37) 69 +for(6, 12..15, 17, 18..32, 34..37, 39)
69 { 70 {
70 $badtest_overrides{$_} = 0; 71 $badtest_overrides{$_} = 0;
71 } 72 }
qpdf/qtest/parsing.test
@@ -17,7 +17,7 @@ my $td = new TestDriver(&#39;parsing&#39;); @@ -17,7 +17,7 @@ my $td = new TestDriver(&#39;parsing&#39;);
17 my $n_tests = 17; 17 my $n_tests = 17;
18 18
19 $td->runtest("parse objects from string", 19 $td->runtest("parse objects from string",
20 - {$td->COMMAND => "test_driver 31 bad39.qdf"}, 20 + {$td->COMMAND => "test_driver 31 bad-parse.qdf"},
21 {$td->FILE => "parse-object.out", $td->EXIT_STATUS => 0}, 21 {$td->FILE => "parse-object.out", $td->EXIT_STATUS => 0},
22 $td->NORMALIZE_NEWLINES); 22 $td->NORMALIZE_NEWLINES);
23 $td->runtest("EOF terminating literal tokens", 23 $td->runtest("EOF terminating literal tokens",
qpdf/qtest/qpdf/bad39.qdf renamed to qpdf/qtest/qpdf/bad-parse.qdf
qpdf/qtest/qpdf/bad39-recover.out 0 โ†’ 100644
  1 +WARNING: bad39.pdf (object 4 0, offset 385): expected endstream
  2 +WARNING: bad39.pdf (object 4 0, offset 341): attempting to recover stream length
  3 +WARNING: bad39.pdf (object 4 0, offset 341): unable to recover stream data; treating stream as empty
  4 +/QTest is indirect and has type stream (10)
  5 +/QTest is a stream. Dictionary: << /Length 44 >>
  6 +Raw stream data:
  7 +
  8 +Uncompressed stream data:
  9 +
  10 +End of stream data
  11 +unparse: 4 0 R
  12 +unparseResolved: 4 0 R
  13 +test 1 done
qpdf/qtest/qpdf/bad39.out 0 โ†’ 100644
  1 +WARNING: bad39.pdf (object 4 0, offset 385): expected endstream
  2 +/QTest is implicit
  3 +/QTest is indirect and has type null (2)
  4 +/QTest is null
  5 +unparse: 4 0 R
  6 +unparseResolved: null
  7 +test 0 done
qpdf/qtest/qpdf/bad39.pdf 0 โ†’ 100644
  1 +%PDF-1.3
  2 +1 0 obj
  3 +<<
  4 + /Type /Catalog
  5 + /Pages 2 0 R
  6 +>>
  7 +endobj
  8 +
  9 +2 0 obj
  10 +<<
  11 + /Type /Pages
  12 + /Kids [
  13 + 3 0 R
  14 + ]
  15 + /Count 1
  16 +>>
  17 +endobj
  18 +
  19 +3 0 obj
  20 +<<
  21 + /Type /Page
  22 + /Parent 2 0 R
  23 + /MediaBox [0 0 612 792]
  24 + /Contents 4 0 R
  25 + /Resources <<
  26 + /ProcSet 5 0 R
  27 + /Font <<
  28 + /F1 6 0 R
  29 + >>
  30 + >>
  31 +>>
  32 +endobj
  33 +
  34 +4 0 obj
  35 +<<
  36 + /Length 44
  37 +>>
  38 +stream
  39 +BT
  40 + /F1 24 Tf
  41 + 72 720 Td
  42 + (Potato) Tj
  43 +ET
  44 +enxstream
  45 +enxobj
  46 +
  47 +5 0 obj
  48 +[
  49 + /PDF
  50 + /Text
  51 +]
  52 +endobj
  53 +
  54 +6 0 obj
  55 +<<
  56 + /Type /Font
  57 + /Subtype /Type1
  58 + /Name /F1
  59 + /BaseFont /Helvetica
  60 + /Encoding /Winng
  61 +>>
  62 +endstream
  63 +endobj
  64 +
  65 +xref
  66 +0 7
  67 +0000000000 65535 f
  68 +0000000009 00000 n
  69 +0000000063 00000 n
  70 +0000000135 00000 n
  71 +0000000307 00000 n
  72 +0000000403 00000 n
  73 +0000000438 00000 n
  74 +trailer <<
  75 + /Size 7
  76 + /Root 1 0 R
  77 + /QTest 4 0 R
  78 +>>
  79 +startxref
  80 +556
  81 +%%EOF
qpdf/qtest/qpdf/parse-object.out
@@ -5,7 +5,7 @@ WARNING: parsed object (offset 9): unknown token while reading object; treating @@ -5,7 +5,7 @@ WARNING: parsed object (offset 9): unknown token while reading object; treating
5 WARNING: parsed object: treating unexpected brace token as null 5 WARNING: parsed object: treating unexpected brace token as null
6 WARNING: parsed object: treating unexpected brace token as null 6 WARNING: parsed object: treating unexpected brace token as null
7 WARNING: parsed object: unexpected dictionary close token 7 WARNING: parsed object: unexpected dictionary close token
8 -WARNING: bad39.qdf (object 7 0, offset 1121): unexpected EOF  
9 -WARNING: bad39.qdf (object 7 0, offset 1121): expected endobj  
10 -WARNING: bad39.qdf (object 7 0, offset 1121): EOF after endobj 8 +WARNING: bad-parse.qdf (object 7 0, offset 1121): unexpected EOF
  9 +WARNING: bad-parse.qdf (object 7 0, offset 1121): expected endobj
  10 +WARNING: bad-parse.qdf (object 7 0, offset 1121): EOF after endobj
11 test 31 done 11 test 31 done