Commit 4b2e72c4cd7dc9bc17ad78ca983ff884c1e1ee69

Authored by Jay Berkenbilt
1 parent 3f3dbe22

Test for direct, rather than resolved nulls in parser

Just because we know an indirect reference is null, doesn't mean we
shouldn't keep it indirect.
ChangeLog
1 2019-08-22 Jay Berkenbilt <ejb@ql.org> 1 2019-08-22 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Add QPDFObjectHandle::isDirectNull() -- a const method that
  4 + allows determining whether an object is a literal null without
  5 + attempting to resolve it.
  6 +
3 * Stop replacing indirect references to null with literal null in 7 * Stop replacing indirect references to null with literal null in
4 arrays when writing output with QPDFWriter. 8 arrays when writing output with QPDFWriter.
5 9
include/qpdf/QPDFObjectHandle.hh
@@ -281,13 +281,12 @@ class QPDFObjectHandle @@ -281,13 +281,12 @@ class QPDFObjectHandle
281 QPDF_DLL 281 QPDF_DLL
282 bool isReserved(); 282 bool isReserved();
283 283
284 - // True for objects that are direct nulls or have previously been  
285 - // resolved to be nulls. Does not attempt to resolve objects. This  
286 - // is intended for internal use, but it can be used as an  
287 - // efficient way to check for nulls if you don't mind unresolved  
288 - // indirect nulls being false negatives. 284 + // True for objects that are direct nulls. Does not attempt to
  285 + // resolve objects. This is intended for internal use, but it can
  286 + // be used as an efficient way to check for nulls that are not
  287 + // indirect objects.
289 QPDF_DLL 288 QPDF_DLL
290 - bool isResolvedNull() const; 289 + bool isDirectNull() const;
291 290
292 // This returns true in addition to the query for the specific 291 // This returns true in addition to the query for the specific
293 // type for indirect objects. 292 // type for indirect objects.
libqpdf/QPDFObjectHandle.cc
@@ -263,9 +263,10 @@ QPDFObjectHandle::isBool() @@ -263,9 +263,10 @@ QPDFObjectHandle::isBool()
263 } 263 }
264 264
265 bool 265 bool
266 -QPDFObjectHandle::isResolvedNull() const 266 +QPDFObjectHandle::isDirectNull() const
267 { 267 {
268 - return QPDFObjectTypeAccessor<QPDF_Null>::check(m->obj.getPointer()); 268 + return (this->m->initialized && (this->m->objid == 0) &&
  269 + QPDFObjectTypeAccessor<QPDF_Null>::check(m->obj.getPointer()));
269 } 270 }
270 271
271 bool 272 bool
libqpdf/SparseOHArray.cc
@@ -15,7 +15,7 @@ SparseOHArray::size() const @@ -15,7 +15,7 @@ SparseOHArray::size() const
15 void 15 void
16 SparseOHArray::append(QPDFObjectHandle oh) 16 SparseOHArray::append(QPDFObjectHandle oh)
17 { 17 {
18 - if (! oh.isResolvedNull()) 18 + if (! oh.isDirectNull())
19 { 19 {
20 this->elements[this->n_elements] = oh; 20 this->elements[this->n_elements] = oh;
21 } 21 }
@@ -73,7 +73,7 @@ SparseOHArray::setAt(size_t idx, QPDFObjectHandle oh) @@ -73,7 +73,7 @@ SparseOHArray::setAt(size_t idx, QPDFObjectHandle oh)
73 { 73 {
74 throw std::logic_error("bounds error setting item in SparseOHArray"); 74 throw std::logic_error("bounds error setting item in SparseOHArray");
75 } 75 }
76 - if (oh.isResolvedNull()) 76 + if (oh.isDirectNull())
77 { 77 {
78 this->elements.erase(idx); 78 this->elements.erase(idx);
79 } 79 }
qpdf/qtest/qpdf.test
@@ -2456,6 +2456,7 @@ my @goodfiles = (&quot;implicit null&quot;, # 1 @@ -2456,6 +2456,7 @@ my @goodfiles = (&quot;implicit null&quot;, # 1
2456 "hybrid xref old mode", # 18 2456 "hybrid xref old mode", # 18
2457 "xref with prev", # 19 2457 "xref with prev", # 19
2458 "lots of compressible objects", # 20 2458 "lots of compressible objects", # 20
  2459 + "array with indirect nulls", # 21
2459 ); 2460 );
2460 2461
2461 $n_tests += (3 * @goodfiles) + 6; 2462 $n_tests += (3 * @goodfiles) + 6;
qpdf/qtest/qpdf/good21.out 0 → 100644
  1 +/QTest is indirect and has type array (8)
  2 +/QTest is an array with 6 items
  3 + item 0 is direct
  4 + item 1 is direct
  5 + item 2 is direct
  6 + item 3 is indirect
  7 + item 4 is direct
  8 + item 5 is indirect
  9 +unparse: 9 0 R
  10 +unparseResolved: [ /literal null /indirect 8 0 R /undefined 10 0 R ]
  11 +test 1 done
qpdf/qtest/qpdf/good21.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 +null
  80 +endobj
  81 +
  82 +9 0 obj
  83 +[ /literal null /indirect 8 0 R /undefined 10 0 R ]
  84 +endobj
  85 +
  86 +xref
  87 +0 10
  88 +0000000000 65535 f
  89 +0000000025 00000 n
  90 +0000000079 00000 n
  91 +0000000161 00000 n
  92 +0000000376 00000 n
  93 +0000000475 00000 n
  94 +0000000494 00000 n
  95 +0000000612 00000 n
  96 +0000000647 00000 n
  97 +0000000668 00000 n
  98 +trailer <<
  99 + /Root 1 0 R
  100 + /Size 10
  101 + /QTest 9 0 R
  102 + /ID [<06c2c8fc54c5f9cc9246898e1e1a7146><06c2c8fc54c5f9cc9246898e1e1a7146>]
  103 +>>
  104 +startxref
  105 +736
  106 +%%EOF
qpdf/qtest/qpdf/good21.qdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +%% Original object ID: 1 0
  6 +1 0 obj
  7 +<<
  8 + /Pages 3 0 R
  9 + /Type /Catalog
  10 +>>
  11 +endobj
  12 +
  13 +%% Original object ID: 9 0
  14 +2 0 obj
  15 +[
  16 + /literal
  17 + null
  18 + /indirect
  19 + 4 0 R
  20 + /undefined
  21 + 5 0 R
  22 +]
  23 +endobj
  24 +
  25 +%% Original object ID: 2 0
  26 +3 0 obj
  27 +<<
  28 + /Count 1
  29 + /Kids [
  30 + 6 0 R
  31 + ]
  32 + /Type /Pages
  33 +>>
  34 +endobj
  35 +
  36 +%% Original object ID: 8 0
  37 +4 0 obj
  38 +null
  39 +endobj
  40 +
  41 +%% Original object ID: 10 0
  42 +5 0 obj
  43 +null
  44 +endobj
  45 +
  46 +%% Page 1
  47 +%% Original object ID: 3 0
  48 +6 0 obj
  49 +<<
  50 + /Contents 7 0 R
  51 + /MediaBox [
  52 + 0
  53 + 0
  54 + 612
  55 + 792
  56 + ]
  57 + /Parent 3 0 R
  58 + /Resources <<
  59 + /Font <<
  60 + /F1 9 0 R
  61 + >>
  62 + /ProcSet 10 0 R
  63 + >>
  64 + /Type /Page
  65 +>>
  66 +endobj
  67 +
  68 +%% Contents for page 1
  69 +%% Original object ID: 4 0
  70 +7 0 obj
  71 +<<
  72 + /Length 8 0 R
  73 +>>
  74 +stream
  75 +BT
  76 + /F1 24 Tf
  77 + 72 720 Td
  78 + (Potato) Tj
  79 +ET
  80 +endstream
  81 +endobj
  82 +
  83 +8 0 obj
  84 +44
  85 +endobj
  86 +
  87 +%% Original object ID: 6 0
  88 +9 0 obj
  89 +<<
  90 + /BaseFont /Helvetica
  91 + /Encoding /WinAnsiEncoding
  92 + /Name /F1
  93 + /Subtype /Type1
  94 + /Type /Font
  95 +>>
  96 +endobj
  97 +
  98 +%% Original object ID: 7 0
  99 +10 0 obj
  100 +[
  101 + /PDF
  102 + /Text
  103 +]
  104 +endobj
  105 +
  106 +xref
  107 +0 11
  108 +0000000000 65535 f
  109 +0000000052 00000 n
  110 +0000000133 00000 n
  111 +0000000239 00000 n
  112 +0000000338 00000 n
  113 +0000000387 00000 n
  114 +0000000445 00000 n
  115 +0000000688 00000 n
  116 +0000000787 00000 n
  117 +0000000833 00000 n
  118 +0000000978 00000 n
  119 +trailer <<
  120 + /QTest 2 0 R
  121 + /Root 1 0 R
  122 + /Size 11
  123 + /ID [<06c2c8fc54c5f9cc9246898e1e1a7146><31415926535897932384626433832795>]
  124 +>>
  125 +startxref
  126 +1014
  127 +%%EOF