Commit 04c203ae060458ae39253263c7dd1c603b931bf0

Authored by Jay Berkenbilt
1 parent b4b8b28e

Eliminate flattenScalarReferences

ChangeLog
  1 +2012-12-27 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Removed public method QPDF::flattenScalarReferences. Instead,
  4 + just flatten the scalar references we actually need to flatten.
  5 + Flattening scalar references was a wrong decision years ago and
  6 + has occasionally caused other problems, among which were that it
  7 + caused qpdf to visit otherwise unreferenced and possibly erroneous
  8 + objects in the file when it didn't have to.
  9 +
  10 + * Removed public method QPDF::decodeStreams which was previously
  11 + used by qpdf --check but is no longer used. The decodeStreams
  12 + method could generate false positives since it would attempt to
  13 + access all objects in the file including those that were not
  14 + referenced.
  15 +
  16 + * Removed public method QPDF::trimTrailerForWrite, which was only
  17 + intended for use by QPDFWriter and which is no longer used.
  18 +
1 19 2012-12-25 Jay Berkenbilt <ejb@ql.org>
2 20  
3 21 * Allow PDF header to appear anywhere in the first 1024 bytes of
... ...
... ... @@ -41,38 +41,6 @@ General
41 41 outlines, page labels, thumbnails, zones. There are probably
42 42 others.
43 43  
44   - * See whether it's possible to remove the call to
45   - flattenScalarReferences. I can't easily figure out why I do it,
46   - but removing it causes strange test failures in linearization. I
47   - would have to study the optimization and linearization code to
48   - figure out why I added this to begin with and what in the code
49   - assumes it's the case. For enqueueObject and unparseChild in
50   - QPDFWriter, simply removing the checks for indirect scalars seems
51   - sufficient. Looking back at the branch in the apex epub
52   - repository, before flattening scalar references, there was special
53   - case code in QPDFWriter to avoid writing out indirect nulls. It's
54   - still not obvious to me why I did it though.
55   -
56   - To pursue this, remove the call to flattenScalarReferences in
57   - QPDFWriter.cc and disable the logic_error exceptions for indirect
58   - scalars. Just search for flattenScalarReferences in QPDFWriter.cc
59   - since the logic errors have comments that mention
60   - flattenScalarReferences. Then run the test suite. Several files
61   - that explicitly test flattening of scalar references fail, but the
62   - indirect scalars are properly preserved and written. But then
63   - there are some linearized files that have a bunch of unreferenced
64   - objects that contain scalars. Need to figure out what these are
65   - and why they're there. Maybe they're objects that used to be
66   - stream lengths. Probably we just need to make sure don't traverse
67   - through a stream's /Length stream when enqueueing stream
68   - dictionaries. This could potentially happen with any object that
69   - QPDFWriter replaces when writing out files. Such objects would be
70   - orphaned in the newly written file. This could be fixed, but it
71   - may not be worth fixing.
72   -
73   - If flattenScalarReferences is removed, a new method will be needed
74   - for checking PDF files.
75   -
76 44 * See if we can avoid preserving unreferenced objects in object
77 45 streams even when preserving the object streams.
78 46  
... ...
include/qpdf/QPDF.hh
... ... @@ -352,24 +352,8 @@ class QPDF
352 352 void optimize(std::map<int, int> const& object_stream_data,
353 353 bool allow_changes = true);
354 354  
355   - // Replace all references to indirect objects that are "scalars"
356   - // (i.e., things that don't have children: not arrays, streams, or
357   - // dictionaries) with direct objects.
358   - QPDF_DLL
359   - void flattenScalarReferences();
360   -
361   - // Decode all streams, discarding the output. Used to check
362   - // correctness of stream encoding.
363   - QPDF_DLL
364   - void decodeStreams();
365   -
366 355 // For QPDFWriter:
367 356  
368   - // Remove /ID, /Encrypt, and /Prev keys from the trailer
369   - // dictionary since these are regenerated during write.
370   - QPDF_DLL
371   - void trimTrailerForWrite();
372   -
373 357 // Get lists of all objects in order according to the part of a
374 358 // linearized file that they belong to.
375 359 QPDF_DLL
... ...
include/qpdf/QPDFWriter.hh
... ... @@ -299,6 +299,7 @@ class QPDFWriter
299 299 void setDataKey(int objid);
300 300 int openObject(int objid = 0);
301 301 void closeObject(int objid);
  302 + void prepareFileForWrite();
302 303 void writeStandard();
303 304 void writeLinearized();
304 305 void enqueuePart(std::vector<QPDFObjectHandle>& part);
... ...
ispell-words
... ... @@ -206,7 +206,6 @@ debian
206 206 declspec
207 207 DecodeParms
208 208 decodeRow
209   -decodeStreams
210 209 decrypt
211 210 decrypted
212 211 decrypter
... ... @@ -335,7 +334,6 @@ fl
335 334 flate
336 335 FlateDecode
337 336 flattenPagesTree
338   -flattenScalarReferences
339 337 fn
340 338 fname
341 339 fo
... ...
libqpdf/QPDF.cc
... ... @@ -1860,28 +1860,6 @@ QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
1860 1860 this->obj_cache[og2] = t;
1861 1861 }
1862 1862  
1863   -void
1864   -QPDF::trimTrailerForWrite()
1865   -{
1866   - // Note that removing the encryption dictionary does not interfere
1867   - // with reading encrypted files. QPDF loads all the information
1868   - // it needs from the encryption dictionary at the beginning and
1869   - // never looks at it again.
1870   - this->trailer.removeKey("/ID");
1871   - this->trailer.removeKey("/Encrypt");
1872   - this->trailer.removeKey("/Prev");
1873   -
1874   - // Remove all trailer keys that potentially come from a
1875   - // cross-reference stream
1876   - this->trailer.removeKey("/Index");
1877   - this->trailer.removeKey("/W");
1878   - this->trailer.removeKey("/Length");
1879   - this->trailer.removeKey("/Filter");
1880   - this->trailer.removeKey("/DecodeParms");
1881   - this->trailer.removeKey("/Type");
1882   - this->trailer.removeKey("/XRefStm");
1883   -}
1884   -
1885 1863 std::string
1886 1864 QPDF::getFilename() const
1887 1865 {
... ... @@ -2067,20 +2045,3 @@ QPDF::pipeStreamData(int objid, int generation,
2067 2045 }
2068 2046 pipeline->finish();
2069 2047 }
2070   -
2071   -void
2072   -QPDF::decodeStreams()
2073   -{
2074   - for (std::map<ObjGen, QPDFXRefEntry>::iterator iter =
2075   - this->xref_table.begin();
2076   - iter != this->xref_table.end(); ++iter)
2077   - {
2078   - ObjGen const& og = (*iter).first;
2079   - QPDFObjectHandle obj = getObjectByID(og.obj, og.gen);
2080   - if (obj.isStream())
2081   - {
2082   - Pl_Discard pl;
2083   - obj.pipeStreamData(&pl, true, false, false);
2084   - }
2085   - }
2086   -}
... ...
libqpdf/QPDFWriter.cc
... ... @@ -834,16 +834,6 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
834 834 {
835 835 // This is a place-holder object for an object stream
836 836 }
837   - else if (object.isScalar())
838   - {
839   - // flattenScalarReferences is supposed to have removed all
840   - // indirect scalars.
841   - throw std::logic_error(
842   - "INTERNAL ERROR: QPDFWriter::enqueueObject: indirect scalar: " +
843   - std::string(this->filename) + " " +
844   - QUtil::int_to_string(object.getObjectID()) + " " +
845   - QUtil::int_to_string(object.getGeneration()));
846   - }
847 837 int objid = object.getObjectID();
848 838  
849 839 if (obj_renumber.count(objid) == 0)
... ... @@ -916,15 +906,6 @@ QPDFWriter::unparseChild(QPDFObjectHandle child, int level, int flags)
916 906 }
917 907 if (child.isIndirect())
918 908 {
919   - if (child.isScalar())
920   - {
921   - // flattenScalarReferences is supposed to have removed all
922   - // indirect scalars.
923   - throw std::logic_error(
924   - "INTERNAL ERROR: QPDFWriter::unparseChild: indirect scalar: " +
925   - QUtil::int_to_string(child.getObjectID()) + " " +
926   - QUtil::int_to_string(child.getGeneration()));
927   - }
928 909 int old_id = child.getObjectID();
929 910 int new_id = obj_renumber[old_id];
930 911 writeString(QUtil::int_to_string(new_id));
... ... @@ -1648,6 +1629,117 @@ QPDFWriter::generateObjectStreams()
1648 1629 }
1649 1630  
1650 1631 void
  1632 +QPDFWriter::prepareFileForWrite()
  1633 +{
  1634 + // Remove keys from the trailer that necessarily have to be
  1635 + // replaced when writing the file.
  1636 +
  1637 + QPDFObjectHandle trailer = pdf.getTrailer();
  1638 +
  1639 + // Note that removing the encryption dictionary does not interfere
  1640 + // with reading encrypted files. QPDF loads all the information
  1641 + // it needs from the encryption dictionary at the beginning and
  1642 + // never looks at it again.
  1643 + trailer.removeKey("/ID");
  1644 + trailer.removeKey("/Encrypt");
  1645 + trailer.removeKey("/Prev");
  1646 +
  1647 + // Remove all trailer keys that potentially come from a
  1648 + // cross-reference stream
  1649 + trailer.removeKey("/Index");
  1650 + trailer.removeKey("/W");
  1651 + trailer.removeKey("/Length");
  1652 + trailer.removeKey("/Filter");
  1653 + trailer.removeKey("/DecodeParms");
  1654 + trailer.removeKey("/Type");
  1655 + trailer.removeKey("/XRefStm");
  1656 +
  1657 + // Do a traversal of the entire PDF file structure replacing all
  1658 + // indirect objects that QPDFWriter wants to be direct. This
  1659 + // includes stream lengths, stream filtering parameters, and
  1660 + // document extension level information. Also replace all
  1661 + // indirect null references with direct nulls. This way, the only
  1662 + // indirect nulls queued for output will be object stream place
  1663 + // holders.
  1664 +
  1665 + std::list<QPDFObjectHandle> queue;
  1666 + queue.push_back(pdf.getTrailer());
  1667 + std::set<int> visited;
  1668 +
  1669 + while (! queue.empty())
  1670 + {
  1671 + QPDFObjectHandle node = queue.front();
  1672 + queue.pop_front();
  1673 + if (node.isIndirect())
  1674 + {
  1675 + if (visited.count(node.getObjectID()) > 0)
  1676 + {
  1677 + continue;
  1678 + }
  1679 + visited.insert(node.getObjectID());
  1680 + }
  1681 +
  1682 + if (node.isArray())
  1683 + {
  1684 + int nitems = node.getArrayNItems();
  1685 + for (int i = 0; i < nitems; ++i)
  1686 + {
  1687 + QPDFObjectHandle oh = node.getArrayItem(i);
  1688 + if (oh.isIndirect() && oh.isNull())
  1689 + {
  1690 + QTC::TC("qpdf", "QPDFWriter flatten array null");
  1691 + oh.makeDirect();
  1692 + node.setArrayItem(i, oh);
  1693 + }
  1694 + else if (! oh.isScalar())
  1695 + {
  1696 + queue.push_back(oh);
  1697 + }
  1698 + }
  1699 + }
  1700 + else if (node.isDictionary() || node.isStream())
  1701 + {
  1702 + bool is_stream = false;
  1703 + QPDFObjectHandle dict = node;
  1704 + if (node.isStream())
  1705 + {
  1706 + is_stream = true;
  1707 + dict = node.getDict();
  1708 + }
  1709 +
  1710 + std::set<std::string> keys = dict.getKeys();
  1711 + for (std::set<std::string>::iterator iter = keys.begin();
  1712 + iter != keys.end(); ++iter)
  1713 + {
  1714 + std::string const& key = *iter;
  1715 + QPDFObjectHandle oh = dict.getKey(key);
  1716 + bool add_to_queue = true;
  1717 + if (oh.isIndirect())
  1718 + {
  1719 + if (is_stream)
  1720 + {
  1721 + if ((key == "/Length") ||
  1722 + (key == "/Filter") ||
  1723 + (key == "/DecodeParms"))
  1724 + {
  1725 + QTC::TC("qpdf", "QPDF make stream key direct");
  1726 + add_to_queue = false;
  1727 + oh.makeDirect();
  1728 + dict.replaceKey(key, oh);
  1729 + }
  1730 + }
  1731 + }
  1732 +
  1733 + if (add_to_queue)
  1734 + {
  1735 + queue.push_back(oh);
  1736 + }
  1737 + }
  1738 + }
  1739 + }
  1740 +}
  1741 +
  1742 +void
1651 1743 QPDFWriter::write()
1652 1744 {
1653 1745 // Do preliminary setup
... ... @@ -1785,8 +1877,7 @@ QPDFWriter::write()
1785 1877  
1786 1878 generateID();
1787 1879  
1788   - pdf.trimTrailerForWrite();
1789   - pdf.flattenScalarReferences();
  1880 + prepareFileForWrite();
1790 1881  
1791 1882 if (this->linearized)
1792 1883 {
... ...
libqpdf/QPDF_optimization.cc
... ... @@ -59,103 +59,6 @@ QPDF::ObjUser::operator&lt;(ObjUser const&amp; rhs) const
59 59 }
60 60  
61 61 void
62   -QPDF::flattenScalarReferences()
63   -{
64   - // Do a traversal of the entire PDF file structure replacing all
65   - // indirect objects that are not arrays, streams, or dictionaries
66   - // with direct objects.
67   -
68   - std::list<QPDFObjectHandle> queue;
69   - queue.push_back(this->trailer);
70   - std::set<ObjGen> visited;
71   -
72   - // Add every object in the xref table to the queue. This ensures
73   - // that we flatten scalar references in unreferenced objects.
74   - // This becomes important if we are preserving object streams in a
75   - // file that has unreferenced objects in its object streams. (See
76   - // QPDF bug 2974522 at SourceForge.)
77   - for (std::map<ObjGen, QPDFXRefEntry>::iterator iter =
78   - this->xref_table.begin();
79   - iter != this->xref_table.end(); ++iter)
80   - {
81   - ObjGen const& og = (*iter).first;
82   - queue.push_back(getObjectByID(og.obj, og.gen));
83   - }
84   -
85   - while (! queue.empty())
86   - {
87   - QPDFObjectHandle node = queue.front();
88   - queue.pop_front();
89   - if (node.isIndirect())
90   - {
91   - ObjGen og(node.getObjectID(), node.getGeneration());
92   - if (visited.count(og) > 0)
93   - {
94   - continue;
95   - }
96   - visited.insert(og);
97   - }
98   -
99   - if (node.isArray())
100   - {
101   - int nitems = node.getArrayNItems();
102   - for (int i = 0; i < nitems; ++i)
103   - {
104   - QPDFObjectHandle oh = node.getArrayItem(i);
105   - if (oh.isScalar())
106   - {
107   - if (oh.isIndirect())
108   - {
109   - QTC::TC("qpdf", "QPDF opt flatten array scalar");
110   - oh.makeDirect();
111   - node.setArrayItem(i, oh);
112   - }
113   - }
114   - else
115   - {
116   - queue.push_back(oh);
117   - }
118   - }
119   - }
120   - else if (node.isDictionary() || node.isStream())
121   - {
122   - QPDFObjectHandle dict = node;
123   - if (node.isStream())
124   - {
125   - dict = node.getDict();
126   - }
127   - std::set<std::string> keys = dict.getKeys();
128   - for (std::set<std::string>::iterator iter = keys.begin();
129   - iter != keys.end(); ++iter)
130   - {
131   - std::string const& key = *iter;
132   - QPDFObjectHandle oh = dict.getKey(key);
133   - if (oh.isNull())
134   - {
135   - // QPDF_Dictionary.getKeys() never returns null
136   - // keys.
137   - throw std::logic_error(
138   - "INTERNAL ERROR: dictionary with null key found");
139   - }
140   - else if (oh.isScalar())
141   - {
142   - if (oh.isIndirect())
143   - {
144   - QTC::TC("qpdf", "QPDF opt flatten dict scalar");
145   - oh.makeDirect();
146   - dict.replaceKey(key, oh);
147   - }
148   - }
149   - else
150   - {
151   - queue.push_back(oh);
152   - }
153   - }
154   - }
155   - }
156   -}
157   -
158   -void
159 62 QPDF::optimize(std::map<int, int> const& object_stream_data,
160 63 bool allow_changes)
161 64 {
... ... @@ -304,9 +207,7 @@ QPDF::pushInheritedAttributesToPageInternal(
304 207 }
305 208 else
306 209 {
307   - // Don't defeat flattenScalarReferences which
308   - // would have already been called by this
309   - // time.
  210 + // It's okay to copy scalars.
310 211 QTC::TC("qpdf", "QPDF opt inherited scalar");
311 212 }
312 213 }
... ...
qpdf/qpdf.cc
... ... @@ -8,6 +8,7 @@
8 8 #include <qpdf/QUtil.hh>
9 9 #include <qpdf/QTC.hh>
10 10 #include <qpdf/Pl_StdioFile.hh>
  11 +#include <qpdf/Pl_Discard.hh>
11 12 #include <qpdf/PointerHolder.hh>
12 13  
13 14 #include <qpdf/QPDF.hh>
... ... @@ -1381,12 +1382,14 @@ int main(int argc, char* argv[])
1381 1382 else
1382 1383 {
1383 1384 std::cout << "File is not linearized\n";
1384   - // calling flattenScalarReferences causes full
1385   - // traversal of file, so any structural errors
1386   - // would be exposed.
1387   - pdf.flattenScalarReferences();
1388   - // Also explicitly decode all streams.
1389   - pdf.decodeStreams();
  1385 + // Write the file no nowhere, uncompressing
  1386 + // streams. This causes full file traversal
  1387 + // and decoding of all streams we can decode.
  1388 + QPDFWriter w(pdf);
  1389 + Pl_Discard discard;
  1390 + w.setOutputPipeline(&discard);
  1391 + w.setStreamDataMode(qpdf_s_uncompress);
  1392 + w.write();
1390 1393 okay = true;
1391 1394 }
1392 1395 }
... ...
qpdf/qpdf.testcov
... ... @@ -29,8 +29,7 @@ QPDF lin outlines in part 1
29 29 QPDF lin nshared_total > nshared_first_page 1
30 30 QPDF lin part 8 empty 1
31 31 QPDF lin check shared past first page 0
32   -QPDF opt flatten array scalar 0
33   -QPDF opt flatten dict scalar 0
  32 +QPDFWriter flatten array null 0
34 33 main QTest implicit 0
35 34 main QTest indirect 1
36 35 main QTest null 0
... ... @@ -244,3 +243,4 @@ QPDFWriter extra header text no newline 0
244 243 QPDFWriter extra header text add newline 0
245 244 QPDF bogus 0 offset 0
246 245 QPDF global offset 0
  246 +QPDF make stream key direct 0
... ...
qpdf/qtest/qpdf/good13.qdf
... ... @@ -18,7 +18,7 @@ endobj
18 18 <01020300040560>
19 19 (AB)
20 20 ]
21   - /indirect (hello)
  21 + /indirect 4 0 R
22 22 /nesting <<
23 23 /a [
24 24 1
... ... @@ -58,17 +58,22 @@ endobj
58 58 <<
59 59 /Count 1
60 60 /Kids [
61   - 4 0 R
  61 + 5 0 R
62 62 ]
63 63 /Type /Pages
64 64 >>
65 65 endobj
66 66  
  67 +%% Original object ID: 8 0
  68 +4 0 obj
  69 +(hello)
  70 +endobj
  71 +
67 72 %% Page 1
68 73 %% Original object ID: 3 0
69   -4 0 obj
  74 +5 0 obj
70 75 <<
71   - /Contents 5 0 R
  76 + /Contents 6 0 R
72 77 /MediaBox [
73 78 0
74 79 0
... ... @@ -78,9 +83,9 @@ endobj
78 83 /Parent 3 0 R
79 84 /Resources <<
80 85 /Font <<
81   - /F1 7 0 R
  86 + /F1 8 0 R
82 87 >>
83   - /ProcSet 8 0 R
  88 + /ProcSet 9 0 R
84 89 >>
85 90 /Type /Page
86 91 >>
... ... @@ -88,9 +93,9 @@ endobj
88 93  
89 94 %% Contents for page 1
90 95 %% Original object ID: 4 0
91   -5 0 obj
  96 +6 0 obj
92 97 <<
93   - /Length 6 0 R
  98 + /Length 7 0 R
94 99 >>
95 100 stream
96 101 BT
... ... @@ -101,12 +106,12 @@ ET
101 106 endstream
102 107 endobj
103 108  
104   -6 0 obj
  109 +7 0 obj
105 110 44
106 111 endobj
107 112  
108 113 %% Original object ID: 6 0
109   -7 0 obj
  114 +8 0 obj
110 115 <<
111 116 /BaseFont /Helvetica
112 117 /Encoding /WinAnsiEncoding
... ... @@ -117,7 +122,7 @@ endobj
117 122 endobj
118 123  
119 124 %% Original object ID: 5 0
120   -8 0 obj
  125 +9 0 obj
121 126 [
122 127 /PDF
123 128 /Text
... ... @@ -125,22 +130,23 @@ endobj
125 130 endobj
126 131  
127 132 xref
128   -0 9
  133 +0 10
129 134 0000000000 65535 f
130 135 0000000052 00000 n
131 136 0000000133 00000 n
132   -0000000578 00000 n
133   -0000000687 00000 n
134   -0000000929 00000 n
135   -0000001028 00000 n
136   -0000001074 00000 n
137   -0000001219 00000 n
  137 +0000000576 00000 n
  138 +0000000675 00000 n
  139 +0000000736 00000 n
  140 +0000000978 00000 n
  141 +0000001077 00000 n
  142 +0000001123 00000 n
  143 +0000001268 00000 n
138 144 trailer <<
139 145 /QTest 2 0 R
140 146 /Root 1 0 R
141   - /Size 9
  147 + /Size 10
142 148 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
143 149 >>
144 150 startxref
145   -1254
  151 +1303
146 152 %%EOF
... ...
qpdf/qtest/qpdf/good5.qdf
... ... @@ -5,17 +5,22 @@
5 5 %% Original object ID: 1 0
6 6 1 0 obj
7 7 <<
8   - /Pages 2 0 R
  8 + /Pages 3 0 R
9 9 /Type /Catalog
10 10 >>
11 11 endobj
12 12  
13   -%% Original object ID: 2 0
  13 +%% Original object ID: 7 0
14 14 2 0 obj
  15 +true
  16 +endobj
  17 +
  18 +%% Original object ID: 2 0
  19 +3 0 obj
15 20 <<
16 21 /Count 1
17 22 /Kids [
18   - 3 0 R
  23 + 4 0 R
19 24 ]
20 25 /Type /Pages
21 26 >>
... ... @@ -23,21 +28,21 @@ endobj
23 28  
24 29 %% Page 1
25 30 %% Original object ID: 3 0
26   -3 0 obj
  31 +4 0 obj
27 32 <<
28   - /Contents 4 0 R
  33 + /Contents 5 0 R
29 34 /MediaBox [
30 35 0
31 36 0
32 37 612
33 38 792
34 39 ]
35   - /Parent 2 0 R
  40 + /Parent 3 0 R
36 41 /Resources <<
37 42 /Font <<
38   - /F1 6 0 R
  43 + /F1 7 0 R
39 44 >>
40   - /ProcSet 7 0 R
  45 + /ProcSet 8 0 R
41 46 >>
42 47 /Type /Page
43 48 >>
... ... @@ -45,9 +50,9 @@ endobj
45 50  
46 51 %% Contents for page 1
47 52 %% Original object ID: 4 0
48   -4 0 obj
  53 +5 0 obj
49 54 <<
50   - /Length 5 0 R
  55 + /Length 6 0 R
51 56 >>
52 57 stream
53 58 BT
... ... @@ -58,12 +63,12 @@ ET
58 63 endstream
59 64 endobj
60 65  
61   -5 0 obj
  66 +6 0 obj
62 67 44
63 68 endobj
64 69  
65 70 %% Original object ID: 6 0
66   -6 0 obj
  71 +7 0 obj
67 72 <<
68 73 /BaseFont /Helvetica
69 74 /Encoding /WinAnsiEncoding
... ... @@ -74,7 +79,7 @@ endobj
74 79 endobj
75 80  
76 81 %% Original object ID: 5 0
77   -7 0 obj
  82 +8 0 obj
78 83 [
79 84 /PDF
80 85 /Text
... ... @@ -82,21 +87,22 @@ endobj
82 87 endobj
83 88  
84 89 xref
85   -0 8
  90 +0 9
86 91 0000000000 65535 f
87 92 0000000052 00000 n
88 93 0000000133 00000 n
89   -0000000242 00000 n
90   -0000000484 00000 n
91   -0000000583 00000 n
92   -0000000629 00000 n
93   -0000000774 00000 n
  94 +0000000181 00000 n
  95 +0000000290 00000 n
  96 +0000000532 00000 n
  97 +0000000631 00000 n
  98 +0000000677 00000 n
  99 +0000000822 00000 n
94 100 trailer <<
95   - /QTest true
  101 + /QTest 2 0 R
96 102 /Root 1 0 R
97   - /Size 8
  103 + /Size 9
98 104 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
99 105 >>
100 106 startxref
101   -809
  107 +857
102 108 %%EOF
... ...
qpdf/qtest/qpdf/good8.qdf
... ... @@ -5,17 +5,22 @@
5 5 %% Original object ID: 1 0
6 6 1 0 obj
7 7 <<
8   - /Pages 2 0 R
  8 + /Pages 3 0 R
9 9 /Type /Catalog
10 10 >>
11 11 endobj
12 12  
13   -%% Original object ID: 2 0
  13 +%% Original object ID: 7 0
14 14 2 0 obj
  15 +3.14159
  16 +endobj
  17 +
  18 +%% Original object ID: 2 0
  19 +3 0 obj
15 20 <<
16 21 /Count 1
17 22 /Kids [
18   - 3 0 R
  23 + 4 0 R
19 24 ]
20 25 /Type /Pages
21 26 >>
... ... @@ -23,21 +28,21 @@ endobj
23 28  
24 29 %% Page 1
25 30 %% Original object ID: 3 0
26   -3 0 obj
  31 +4 0 obj
27 32 <<
28   - /Contents 4 0 R
  33 + /Contents 5 0 R
29 34 /MediaBox [
30 35 0
31 36 0
32 37 612
33 38 792
34 39 ]
35   - /Parent 2 0 R
  40 + /Parent 3 0 R
36 41 /Resources <<
37 42 /Font <<
38   - /F1 6 0 R
  43 + /F1 7 0 R
39 44 >>
40   - /ProcSet 7 0 R
  45 + /ProcSet 8 0 R
41 46 >>
42 47 /Type /Page
43 48 >>
... ... @@ -45,9 +50,9 @@ endobj
45 50  
46 51 %% Contents for page 1
47 52 %% Original object ID: 4 0
48   -4 0 obj
  53 +5 0 obj
49 54 <<
50   - /Length 5 0 R
  55 + /Length 6 0 R
51 56 >>
52 57 stream
53 58 BT
... ... @@ -58,12 +63,12 @@ ET
58 63 endstream
59 64 endobj
60 65  
61   -5 0 obj
  66 +6 0 obj
62 67 44
63 68 endobj
64 69  
65 70 %% Original object ID: 6 0
66   -6 0 obj
  71 +7 0 obj
67 72 <<
68 73 /BaseFont /Helvetica
69 74 /Encoding /WinAnsiEncoding
... ... @@ -74,7 +79,7 @@ endobj
74 79 endobj
75 80  
76 81 %% Original object ID: 5 0
77   -7 0 obj
  82 +8 0 obj
78 83 [
79 84 /PDF
80 85 /Text
... ... @@ -82,21 +87,22 @@ endobj
82 87 endobj
83 88  
84 89 xref
85   -0 8
  90 +0 9
86 91 0000000000 65535 f
87 92 0000000052 00000 n
88 93 0000000133 00000 n
89   -0000000242 00000 n
90   -0000000484 00000 n
91   -0000000583 00000 n
92   -0000000629 00000 n
93   -0000000774 00000 n
  94 +0000000184 00000 n
  95 +0000000293 00000 n
  96 +0000000535 00000 n
  97 +0000000634 00000 n
  98 +0000000680 00000 n
  99 +0000000825 00000 n
94 100 trailer <<
95   - /QTest 3.14159
  101 + /QTest 2 0 R
96 102 /Root 1 0 R
97   - /Size 8
  103 + /Size 9
98 104 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
99 105 >>
100 106 startxref
101   -809
  107 +860
102 108 %%EOF
... ...
qpdf/qtest/qpdf/lin-special.disable.exp
No preview for this file type
qpdf/qtest/qpdf/lin-special.generate.exp
No preview for this file type
qpdf/qtest/qpdf/lin-special.preserve.exp
No preview for this file type
qpdf/qtest/qpdf/test4-1.qdf
... ... @@ -39,8 +39,8 @@ endobj
39 39 <<
40 40 /A 5 0 R
41 41 /B 6 0 R
42   - /Subject (Subject)
43   - /Title (Some Title Is Here)
  42 + /Subject 7 0 R
  43 + /Title 8 0 R
44 44 >>
45 45 endobj
46 46  
... ... @@ -49,7 +49,7 @@ endobj
49 49 <<
50 50 /Count 1
51 51 /Kids [
52   - 7 0 R
  52 + 9 0 R
53 53 ]
54 54 /Type /Pages
55 55 >>
... ... @@ -72,11 +72,21 @@ endobj
72 72 >>
73 73 endobj
74 74  
  75 +%% Original object ID: 10 0
  76 +7 0 obj
  77 +(Subject)
  78 +endobj
  79 +
  80 +%% Original object ID: 9 0
  81 +8 0 obj
  82 +(Some Title Is Here)
  83 +endobj
  84 +
75 85 %% Page 1
76 86 %% Original object ID: 3 0
77   -7 0 obj
  87 +9 0 obj
78 88 <<
79   - /Contents 8 0 R
  89 + /Contents 10 0 R
80 90 /MediaBox [
81 91 0
82 92 0
... ... @@ -86,9 +96,9 @@ endobj
86 96 /Parent 4 0 R
87 97 /Resources <<
88 98 /Font <<
89   - /F1 10 0 R
  99 + /F1 12 0 R
90 100 >>
91   - /ProcSet 11 0 R
  101 + /ProcSet 13 0 R
92 102 >>
93 103 /Type /Page
94 104 >>
... ... @@ -96,9 +106,9 @@ endobj
96 106  
97 107 %% Contents for page 1
98 108 %% Original object ID: 4 0
99   -8 0 obj
  109 +10 0 obj
100 110 <<
101   - /Length 9 0 R
  111 + /Length 11 0 R
102 112 >>
103 113 stream
104 114 BT
... ... @@ -109,12 +119,12 @@ ET
109 119 endstream
110 120 endobj
111 121  
112   -9 0 obj
  122 +11 0 obj
113 123 44
114 124 endobj
115 125  
116 126 %% Original object ID: 6 0
117   -10 0 obj
  127 +12 0 obj
118 128 <<
119 129 /BaseFont /Helvetica
120 130 /Encoding /WinAnsiEncoding
... ... @@ -125,7 +135,7 @@ endobj
125 135 endobj
126 136  
127 137 %% Original object ID: 7 0
128   -11 0 obj
  138 +13 0 obj
129 139 [
130 140 /PDF
131 141 /Text
... ... @@ -133,26 +143,28 @@ endobj
133 143 endobj
134 144  
135 145 xref
136   -0 12
  146 +0 14
137 147 0000000000 65535 f
138 148 0000000052 00000 n
139 149 0000000134 00000 n
140 150 0000000353 00000 n
141   -0000000475 00000 n
142   -0000000575 00000 n
143   -0000000635 00000 n
144   -0000000714 00000 n
145   -0000000958 00000 n
146   -0000001057 00000 n
147   -0000001103 00000 n
148   -0000001249 00000 n
  151 +0000000456 00000 n
  152 +0000000556 00000 n
  153 +0000000616 00000 n
  154 +0000000686 00000 n
  155 +0000000739 00000 n
  156 +0000000813 00000 n
  157 +0000001058 00000 n
  158 +0000001159 00000 n
  159 +0000001206 00000 n
  160 +0000001352 00000 n
149 161 trailer <<
150 162 /Info 2 0 R
151 163 /QTest 3 0 R
152 164 /Root 1 0 R
153   - /Size 12
  165 + /Size 14
154 166 /ID [<c61bd35bada064f61e0a56aa9588064e><31415926535897932384626433832795>]
155 167 >>
156 168 startxref
157   -1285
  169 +1388
158 170 %%EOF
... ...
qpdf/qtest/qpdf/unreferenced-indirect-scalar.out
No preview for this file type