Commit 9f8aba1db7f101e424cbc2c742abe92868cc4bff

Authored by Jay Berkenbilt
1 parent b0a96ce6

Handle indirect stream filter/decode parameters

QPDFWriter was trying to make /Filter and /DecodeParms direct in all
cases, but there are some cases where /DecodeParms may refer to a
stream, which can't be direct. QPDFWriter doesn't actually need
/DecodeParms to be direct in that case because it won't be able to
filter the stream. Until we can handle this type of stream, just don't
make /Filter and /DecodeParms direct if we can't filter the stream
anyway.

Fixes #34
ChangeLog
  1 +2014-06-07 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Bug fix: don't fail on files that contain streams where /Filter
  4 + or /DecodeParms references a stream. Before, qpdf would try to
  5 + convert these to direct objects, which would fail because of the
  6 + stream.
  7 +
1 2014-02-22 Jay Berkenbilt <ejb@ql.org> 8 2014-02-22 Jay Berkenbilt <ejb@ql.org>
2 9
3 * Bug fix: if the last object in the first part of a linearized 10 * Bug fix: if the last object in the first part of a linearized
libqpdf/QPDFWriter.cc
@@ -2051,11 +2051,14 @@ QPDFWriter::prepareFileForWrite() @@ -2051,11 +2051,14 @@ QPDFWriter::prepareFileForWrite()
2051 { 2051 {
2052 bool is_stream = false; 2052 bool is_stream = false;
2053 bool is_root = false; 2053 bool is_root = false;
  2054 + bool filterable = false;
2054 QPDFObjectHandle dict = node; 2055 QPDFObjectHandle dict = node;
2055 if (node.isStream()) 2056 if (node.isStream())
2056 { 2057 {
2057 is_stream = true; 2058 is_stream = true;
2058 dict = node.getDict(); 2059 dict = node.getDict();
  2060 + // See whether we are able to filter this stream.
  2061 + filterable = node.pipeStreamData(0, true, false, false);
2059 } 2062 }
2060 else if (pdf.getRoot().getObjectID() == node.getObjectID()) 2063 else if (pdf.getRoot().getObjectID() == node.getObjectID())
2061 { 2064 {
@@ -2073,8 +2076,9 @@ QPDFWriter::prepareFileForWrite() @@ -2073,8 +2076,9 @@ QPDFWriter::prepareFileForWrite()
2073 { 2076 {
2074 if (oh.isIndirect() && 2077 if (oh.isIndirect() &&
2075 ((key == "/Length") || 2078 ((key == "/Length") ||
2076 - (key == "/Filter") ||  
2077 - (key == "/DecodeParms"))) 2079 + (filterable &&
  2080 + ((key == "/Filter") ||
  2081 + (key == "/DecodeParms")))))
2078 { 2082 {
2079 QTC::TC("qpdf", "QPDFWriter make stream key direct"); 2083 QTC::TC("qpdf", "QPDFWriter make stream key direct");
2080 add_to_queue = false; 2084 add_to_queue = false;
qpdf/qtest/qpdf.test
@@ -199,7 +199,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;, @@ -199,7 +199,7 @@ $td-&gt;runtest(&quot;remove page we don&#39;t have&quot;,
199 show_ntests(); 199 show_ntests();
200 # ---------- 200 # ----------
201 $td->notify("--- Miscellaneous Tests ---"); 201 $td->notify("--- Miscellaneous Tests ---");
202 -$n_tests += 70; 202 +$n_tests += 72;
203 203
204 $td->runtest("qpdf version", 204 $td->runtest("qpdf version",
205 {$td->COMMAND => "qpdf --version"}, 205 {$td->COMMAND => "qpdf --version"},
@@ -546,6 +546,14 @@ $td-&gt;runtest(&quot;sanity check array size&quot;, @@ -546,6 +546,14 @@ $td-&gt;runtest(&quot;sanity check array size&quot;,
546 $td->EXIT_STATUS => 2}, 546 $td->EXIT_STATUS => 2},
547 $td->NORMALIZE_NEWLINES); 547 $td->NORMALIZE_NEWLINES);
548 548
  549 +$td->runtest("stream with indirect decode parms",
  550 + {$td->COMMAND =>
  551 + "qpdf --static-id indirect-decode-parms.pdf a.pdf"},
  552 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  553 +$td->runtest("check file",
  554 + {$td->FILE => "a.pdf"},
  555 + {$td->FILE => "indirect-decode-parms-out.pdf"});
  556 +
549 show_ntests(); 557 show_ntests();
550 # ---------- 558 # ----------
551 $td->notify("--- Numeric range parsing tests ---"); 559 $td->notify("--- Numeric range parsing tests ---");
qpdf/qtest/qpdf/indirect-decode-parms-out.pdf 0 → 100644
No preview for this file type
qpdf/qtest/qpdf/indirect-decode-parms.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +1 0 obj
  6 +<<
  7 + /Pages 2 0 R
  8 + /Type /Catalog
  9 +>>
  10 +endobj
  11 +
  12 +2 0 obj
  13 +<<
  14 + /Count 1
  15 + /Kids [
  16 + 3 0 R
  17 + ]
  18 + /Type /Pages
  19 +>>
  20 +endobj
  21 +
  22 +%% Page 1
  23 +3 0 obj
  24 +<<
  25 + /Contents 4 0 R
  26 + /MediaBox [
  27 + 0
  28 + 0
  29 + 612
  30 + 792
  31 + ]
  32 + /Parent 2 0 R
  33 + /Resources <<
  34 + /Font <<
  35 + /F1 6 0 R
  36 + >>
  37 + /ProcSet 7 0 R
  38 + >>
  39 + /Type /Page
  40 +>>
  41 +endobj
  42 +
  43 +%% Contents for page 1
  44 +4 0 obj
  45 +<<
  46 + /Length 5 0 R
  47 +>>
  48 +stream
  49 +BT
  50 + /F1 24 Tf
  51 + 72 720 Td
  52 + (Potato) Tj
  53 +ET
  54 +endstream
  55 +endobj
  56 +
  57 +5 0 obj
  58 +44
  59 +endobj
  60 +
  61 +6 0 obj
  62 +<<
  63 + /BaseFont /Helvetica
  64 + /Encoding /WinAnsiEncoding
  65 + /Name /F1
  66 + /Subtype /Type1
  67 + /Type /Font
  68 +>>
  69 +endobj
  70 +
  71 +7 0 obj
  72 +[
  73 + /PDF
  74 + /Text
  75 +]
  76 +endobj
  77 +
  78 +8 0 obj
  79 +<<
  80 + /Length 9 0 R
  81 + /Filter /Something
  82 + /DecodeParms 10 0 R
  83 +>>
  84 +stream
  85 +here is some stream data
  86 +endstream
  87 +endobj
  88 +
  89 +9 0 obj
  90 +25
  91 +endobj
  92 +
  93 +10 0 obj
  94 +<<
  95 + /Length 11 0 R
  96 +>>
  97 +stream
  98 +here is some stream data
  99 +endstream
  100 +endobj
  101 +
  102 +11 0 obj
  103 +25
  104 +endobj
  105 +
  106 +xref
  107 +0 12
  108 +0000000000 65535 f
  109 +0000000025 00000 n
  110 +0000000079 00000 n
  111 +0000000161 00000 n
  112 +0000000376 00000 n
  113 +0000000475 00000 n
  114 +0000000494 00000 n
  115 +0000000612 00000 n
  116 +0000000647 00000 n
  117 +0000000770 00000 n
  118 +0000000789 00000 n
  119 +0000000871 00000 n
  120 +trailer <<
  121 + /Root 1 0 R
  122 + /Size 12
  123 + /QTest 8 0 R
  124 + /ID [<3e1b045415cfe83fea12b9817e205ef6><3e1b045415cfe83fea12b9817e205ef6>]
  125 +>>
  126 +startxref
  127 +891
  128 +%%EOF