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 2012-12-25 Jay Berkenbilt <ejb@ql.org> 19 2012-12-25 Jay Berkenbilt <ejb@ql.org>
2 20
3 * Allow PDF header to appear anywhere in the first 1024 bytes of 21 * Allow PDF header to appear anywhere in the first 1024 bytes of
@@ -41,38 +41,6 @@ General @@ -41,38 +41,6 @@ General
41 outlines, page labels, thumbnails, zones. There are probably 41 outlines, page labels, thumbnails, zones. There are probably
42 others. 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 * See if we can avoid preserving unreferenced objects in object 44 * See if we can avoid preserving unreferenced objects in object
77 streams even when preserving the object streams. 45 streams even when preserving the object streams.
78 46
include/qpdf/QPDF.hh
@@ -352,24 +352,8 @@ class QPDF @@ -352,24 +352,8 @@ class QPDF
352 void optimize(std::map<int, int> const& object_stream_data, 352 void optimize(std::map<int, int> const& object_stream_data,
353 bool allow_changes = true); 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 // For QPDFWriter: 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 // Get lists of all objects in order according to the part of a 357 // Get lists of all objects in order according to the part of a
374 // linearized file that they belong to. 358 // linearized file that they belong to.
375 QPDF_DLL 359 QPDF_DLL
include/qpdf/QPDFWriter.hh
@@ -299,6 +299,7 @@ class QPDFWriter @@ -299,6 +299,7 @@ class QPDFWriter
299 void setDataKey(int objid); 299 void setDataKey(int objid);
300 int openObject(int objid = 0); 300 int openObject(int objid = 0);
301 void closeObject(int objid); 301 void closeObject(int objid);
  302 + void prepareFileForWrite();
302 void writeStandard(); 303 void writeStandard();
303 void writeLinearized(); 304 void writeLinearized();
304 void enqueuePart(std::vector<QPDFObjectHandle>& part); 305 void enqueuePart(std::vector<QPDFObjectHandle>& part);
ispell-words
@@ -206,7 +206,6 @@ debian @@ -206,7 +206,6 @@ debian
206 declspec 206 declspec
207 DecodeParms 207 DecodeParms
208 decodeRow 208 decodeRow
209 -decodeStreams  
210 decrypt 209 decrypt
211 decrypted 210 decrypted
212 decrypter 211 decrypter
@@ -335,7 +334,6 @@ fl @@ -335,7 +334,6 @@ fl
335 flate 334 flate
336 FlateDecode 335 FlateDecode
337 flattenPagesTree 336 flattenPagesTree
338 -flattenScalarReferences  
339 fn 337 fn
340 fname 338 fname
341 fo 339 fo
libqpdf/QPDF.cc
@@ -1860,28 +1860,6 @@ QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2) @@ -1860,28 +1860,6 @@ QPDF::swapObjects(int objid1, int generation1, int objid2, int generation2)
1860 this->obj_cache[og2] = t; 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 std::string 1863 std::string
1886 QPDF::getFilename() const 1864 QPDF::getFilename() const
1887 { 1865 {
@@ -2067,20 +2045,3 @@ QPDF::pipeStreamData(int objid, int generation, @@ -2067,20 +2045,3 @@ QPDF::pipeStreamData(int objid, int generation,
2067 } 2045 }
2068 pipeline->finish(); 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,16 +834,6 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
834 { 834 {
835 // This is a place-holder object for an object stream 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 int objid = object.getObjectID(); 837 int objid = object.getObjectID();
848 838
849 if (obj_renumber.count(objid) == 0) 839 if (obj_renumber.count(objid) == 0)
@@ -916,15 +906,6 @@ QPDFWriter::unparseChild(QPDFObjectHandle child, int level, int flags) @@ -916,15 +906,6 @@ QPDFWriter::unparseChild(QPDFObjectHandle child, int level, int flags)
916 } 906 }
917 if (child.isIndirect()) 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 int old_id = child.getObjectID(); 909 int old_id = child.getObjectID();
929 int new_id = obj_renumber[old_id]; 910 int new_id = obj_renumber[old_id];
930 writeString(QUtil::int_to_string(new_id)); 911 writeString(QUtil::int_to_string(new_id));
@@ -1648,6 +1629,117 @@ QPDFWriter::generateObjectStreams() @@ -1648,6 +1629,117 @@ QPDFWriter::generateObjectStreams()
1648 } 1629 }
1649 1630
1650 void 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 QPDFWriter::write() 1743 QPDFWriter::write()
1652 { 1744 {
1653 // Do preliminary setup 1745 // Do preliminary setup
@@ -1785,8 +1877,7 @@ QPDFWriter::write() @@ -1785,8 +1877,7 @@ QPDFWriter::write()
1785 1877
1786 generateID(); 1878 generateID();
1787 1879
1788 - pdf.trimTrailerForWrite();  
1789 - pdf.flattenScalarReferences(); 1880 + prepareFileForWrite();
1790 1881
1791 if (this->linearized) 1882 if (this->linearized)
1792 { 1883 {
libqpdf/QPDF_optimization.cc
@@ -59,103 +59,6 @@ QPDF::ObjUser::operator&lt;(ObjUser const&amp; rhs) const @@ -59,103 +59,6 @@ QPDF::ObjUser::operator&lt;(ObjUser const&amp; rhs) const
59 } 59 }
60 60
61 void 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 QPDF::optimize(std::map<int, int> const& object_stream_data, 62 QPDF::optimize(std::map<int, int> const& object_stream_data,
160 bool allow_changes) 63 bool allow_changes)
161 { 64 {
@@ -304,9 +207,7 @@ QPDF::pushInheritedAttributesToPageInternal( @@ -304,9 +207,7 @@ QPDF::pushInheritedAttributesToPageInternal(
304 } 207 }
305 else 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 QTC::TC("qpdf", "QPDF opt inherited scalar"); 211 QTC::TC("qpdf", "QPDF opt inherited scalar");
311 } 212 }
312 } 213 }
qpdf/qpdf.cc
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 #include <qpdf/QUtil.hh> 8 #include <qpdf/QUtil.hh>
9 #include <qpdf/QTC.hh> 9 #include <qpdf/QTC.hh>
10 #include <qpdf/Pl_StdioFile.hh> 10 #include <qpdf/Pl_StdioFile.hh>
  11 +#include <qpdf/Pl_Discard.hh>
11 #include <qpdf/PointerHolder.hh> 12 #include <qpdf/PointerHolder.hh>
12 13
13 #include <qpdf/QPDF.hh> 14 #include <qpdf/QPDF.hh>
@@ -1381,12 +1382,14 @@ int main(int argc, char* argv[]) @@ -1381,12 +1382,14 @@ int main(int argc, char* argv[])
1381 else 1382 else
1382 { 1383 {
1383 std::cout << "File is not linearized\n"; 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 okay = true; 1393 okay = true;
1391 } 1394 }
1392 } 1395 }
qpdf/qpdf.testcov
@@ -29,8 +29,7 @@ QPDF lin outlines in part 1 @@ -29,8 +29,7 @@ QPDF lin outlines in part 1
29 QPDF lin nshared_total > nshared_first_page 1 29 QPDF lin nshared_total > nshared_first_page 1
30 QPDF lin part 8 empty 1 30 QPDF lin part 8 empty 1
31 QPDF lin check shared past first page 0 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 main QTest implicit 0 33 main QTest implicit 0
35 main QTest indirect 1 34 main QTest indirect 1
36 main QTest null 0 35 main QTest null 0
@@ -244,3 +243,4 @@ QPDFWriter extra header text no newline 0 @@ -244,3 +243,4 @@ QPDFWriter extra header text no newline 0
244 QPDFWriter extra header text add newline 0 243 QPDFWriter extra header text add newline 0
245 QPDF bogus 0 offset 0 244 QPDF bogus 0 offset 0
246 QPDF global offset 0 245 QPDF global offset 0
  246 +QPDF make stream key direct 0
qpdf/qtest/qpdf/good13.qdf
@@ -18,7 +18,7 @@ endobj @@ -18,7 +18,7 @@ endobj
18 <01020300040560> 18 <01020300040560>
19 (AB) 19 (AB)
20 ] 20 ]
21 - /indirect (hello) 21 + /indirect 4 0 R
22 /nesting << 22 /nesting <<
23 /a [ 23 /a [
24 1 24 1
@@ -58,17 +58,22 @@ endobj @@ -58,17 +58,22 @@ endobj
58 << 58 <<
59 /Count 1 59 /Count 1
60 /Kids [ 60 /Kids [
61 - 4 0 R 61 + 5 0 R
62 ] 62 ]
63 /Type /Pages 63 /Type /Pages
64 >> 64 >>
65 endobj 65 endobj
66 66
  67 +%% Original object ID: 8 0
  68 +4 0 obj
  69 +(hello)
  70 +endobj
  71 +
67 %% Page 1 72 %% Page 1
68 %% Original object ID: 3 0 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 /MediaBox [ 77 /MediaBox [
73 0 78 0
74 0 79 0
@@ -78,9 +83,9 @@ endobj @@ -78,9 +83,9 @@ endobj
78 /Parent 3 0 R 83 /Parent 3 0 R
79 /Resources << 84 /Resources <<
80 /Font << 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 /Type /Page 90 /Type /Page
86 >> 91 >>
@@ -88,9 +93,9 @@ endobj @@ -88,9 +93,9 @@ endobj
88 93
89 %% Contents for page 1 94 %% Contents for page 1
90 %% Original object ID: 4 0 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 stream 100 stream
96 BT 101 BT
@@ -101,12 +106,12 @@ ET @@ -101,12 +106,12 @@ ET
101 endstream 106 endstream
102 endobj 107 endobj
103 108
104 -6 0 obj 109 +7 0 obj
105 44 110 44
106 endobj 111 endobj
107 112
108 %% Original object ID: 6 0 113 %% Original object ID: 6 0
109 -7 0 obj 114 +8 0 obj
110 << 115 <<
111 /BaseFont /Helvetica 116 /BaseFont /Helvetica
112 /Encoding /WinAnsiEncoding 117 /Encoding /WinAnsiEncoding
@@ -117,7 +122,7 @@ endobj @@ -117,7 +122,7 @@ endobj
117 endobj 122 endobj
118 123
119 %% Original object ID: 5 0 124 %% Original object ID: 5 0
120 -8 0 obj 125 +9 0 obj
121 [ 126 [
122 /PDF 127 /PDF
123 /Text 128 /Text
@@ -125,22 +130,23 @@ endobj @@ -125,22 +130,23 @@ endobj
125 endobj 130 endobj
126 131
127 xref 132 xref
128 -0 9 133 +0 10
129 0000000000 65535 f 134 0000000000 65535 f
130 0000000052 00000 n 135 0000000052 00000 n
131 0000000133 00000 n 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 trailer << 144 trailer <<
139 /QTest 2 0 R 145 /QTest 2 0 R
140 /Root 1 0 R 146 /Root 1 0 R
141 - /Size 9 147 + /Size 10
142 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] 148 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
143 >> 149 >>
144 startxref 150 startxref
145 -1254 151 +1303
146 %%EOF 152 %%EOF
qpdf/qtest/qpdf/good5.qdf
@@ -5,17 +5,22 @@ @@ -5,17 +5,22 @@
5 %% Original object ID: 1 0 5 %% Original object ID: 1 0
6 1 0 obj 6 1 0 obj
7 << 7 <<
8 - /Pages 2 0 R 8 + /Pages 3 0 R
9 /Type /Catalog 9 /Type /Catalog
10 >> 10 >>
11 endobj 11 endobj
12 12
13 -%% Original object ID: 2 0 13 +%% Original object ID: 7 0
14 2 0 obj 14 2 0 obj
  15 +true
  16 +endobj
  17 +
  18 +%% Original object ID: 2 0
  19 +3 0 obj
15 << 20 <<
16 /Count 1 21 /Count 1
17 /Kids [ 22 /Kids [
18 - 3 0 R 23 + 4 0 R
19 ] 24 ]
20 /Type /Pages 25 /Type /Pages
21 >> 26 >>
@@ -23,21 +28,21 @@ endobj @@ -23,21 +28,21 @@ endobj
23 28
24 %% Page 1 29 %% Page 1
25 %% Original object ID: 3 0 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 /MediaBox [ 34 /MediaBox [
30 0 35 0
31 0 36 0
32 612 37 612
33 792 38 792
34 ] 39 ]
35 - /Parent 2 0 R 40 + /Parent 3 0 R
36 /Resources << 41 /Resources <<
37 /Font << 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 /Type /Page 47 /Type /Page
43 >> 48 >>
@@ -45,9 +50,9 @@ endobj @@ -45,9 +50,9 @@ endobj
45 50
46 %% Contents for page 1 51 %% Contents for page 1
47 %% Original object ID: 4 0 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 stream 57 stream
53 BT 58 BT
@@ -58,12 +63,12 @@ ET @@ -58,12 +63,12 @@ ET
58 endstream 63 endstream
59 endobj 64 endobj
60 65
61 -5 0 obj 66 +6 0 obj
62 44 67 44
63 endobj 68 endobj
64 69
65 %% Original object ID: 6 0 70 %% Original object ID: 6 0
66 -6 0 obj 71 +7 0 obj
67 << 72 <<
68 /BaseFont /Helvetica 73 /BaseFont /Helvetica
69 /Encoding /WinAnsiEncoding 74 /Encoding /WinAnsiEncoding
@@ -74,7 +79,7 @@ endobj @@ -74,7 +79,7 @@ endobj
74 endobj 79 endobj
75 80
76 %% Original object ID: 5 0 81 %% Original object ID: 5 0
77 -7 0 obj 82 +8 0 obj
78 [ 83 [
79 /PDF 84 /PDF
80 /Text 85 /Text
@@ -82,21 +87,22 @@ endobj @@ -82,21 +87,22 @@ endobj
82 endobj 87 endobj
83 88
84 xref 89 xref
85 -0 8 90 +0 9
86 0000000000 65535 f 91 0000000000 65535 f
87 0000000052 00000 n 92 0000000052 00000 n
88 0000000133 00000 n 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 trailer << 100 trailer <<
95 - /QTest true 101 + /QTest 2 0 R
96 /Root 1 0 R 102 /Root 1 0 R
97 - /Size 8 103 + /Size 9
98 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] 104 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
99 >> 105 >>
100 startxref 106 startxref
101 -809 107 +857
102 %%EOF 108 %%EOF
qpdf/qtest/qpdf/good8.qdf
@@ -5,17 +5,22 @@ @@ -5,17 +5,22 @@
5 %% Original object ID: 1 0 5 %% Original object ID: 1 0
6 1 0 obj 6 1 0 obj
7 << 7 <<
8 - /Pages 2 0 R 8 + /Pages 3 0 R
9 /Type /Catalog 9 /Type /Catalog
10 >> 10 >>
11 endobj 11 endobj
12 12
13 -%% Original object ID: 2 0 13 +%% Original object ID: 7 0
14 2 0 obj 14 2 0 obj
  15 +3.14159
  16 +endobj
  17 +
  18 +%% Original object ID: 2 0
  19 +3 0 obj
15 << 20 <<
16 /Count 1 21 /Count 1
17 /Kids [ 22 /Kids [
18 - 3 0 R 23 + 4 0 R
19 ] 24 ]
20 /Type /Pages 25 /Type /Pages
21 >> 26 >>
@@ -23,21 +28,21 @@ endobj @@ -23,21 +28,21 @@ endobj
23 28
24 %% Page 1 29 %% Page 1
25 %% Original object ID: 3 0 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 /MediaBox [ 34 /MediaBox [
30 0 35 0
31 0 36 0
32 612 37 612
33 792 38 792
34 ] 39 ]
35 - /Parent 2 0 R 40 + /Parent 3 0 R
36 /Resources << 41 /Resources <<
37 /Font << 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 /Type /Page 47 /Type /Page
43 >> 48 >>
@@ -45,9 +50,9 @@ endobj @@ -45,9 +50,9 @@ endobj
45 50
46 %% Contents for page 1 51 %% Contents for page 1
47 %% Original object ID: 4 0 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 stream 57 stream
53 BT 58 BT
@@ -58,12 +63,12 @@ ET @@ -58,12 +63,12 @@ ET
58 endstream 63 endstream
59 endobj 64 endobj
60 65
61 -5 0 obj 66 +6 0 obj
62 44 67 44
63 endobj 68 endobj
64 69
65 %% Original object ID: 6 0 70 %% Original object ID: 6 0
66 -6 0 obj 71 +7 0 obj
67 << 72 <<
68 /BaseFont /Helvetica 73 /BaseFont /Helvetica
69 /Encoding /WinAnsiEncoding 74 /Encoding /WinAnsiEncoding
@@ -74,7 +79,7 @@ endobj @@ -74,7 +79,7 @@ endobj
74 endobj 79 endobj
75 80
76 %% Original object ID: 5 0 81 %% Original object ID: 5 0
77 -7 0 obj 82 +8 0 obj
78 [ 83 [
79 /PDF 84 /PDF
80 /Text 85 /Text
@@ -82,21 +87,22 @@ endobj @@ -82,21 +87,22 @@ endobj
82 endobj 87 endobj
83 88
84 xref 89 xref
85 -0 8 90 +0 9
86 0000000000 65535 f 91 0000000000 65535 f
87 0000000052 00000 n 92 0000000052 00000 n
88 0000000133 00000 n 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 trailer << 100 trailer <<
95 - /QTest 3.14159 101 + /QTest 2 0 R
96 /Root 1 0 R 102 /Root 1 0 R
97 - /Size 8 103 + /Size 9
98 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] 104 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
99 >> 105 >>
100 startxref 106 startxref
101 -809 107 +860
102 %%EOF 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,8 +39,8 @@ endobj
39 << 39 <<
40 /A 5 0 R 40 /A 5 0 R
41 /B 6 0 R 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 endobj 45 endobj
46 46
@@ -49,7 +49,7 @@ endobj @@ -49,7 +49,7 @@ endobj
49 << 49 <<
50 /Count 1 50 /Count 1
51 /Kids [ 51 /Kids [
52 - 7 0 R 52 + 9 0 R
53 ] 53 ]
54 /Type /Pages 54 /Type /Pages
55 >> 55 >>
@@ -72,11 +72,21 @@ endobj @@ -72,11 +72,21 @@ endobj
72 >> 72 >>
73 endobj 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 %% Page 1 85 %% Page 1
76 %% Original object ID: 3 0 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 /MediaBox [ 90 /MediaBox [
81 0 91 0
82 0 92 0
@@ -86,9 +96,9 @@ endobj @@ -86,9 +96,9 @@ endobj
86 /Parent 4 0 R 96 /Parent 4 0 R
87 /Resources << 97 /Resources <<
88 /Font << 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 /Type /Page 103 /Type /Page
94 >> 104 >>
@@ -96,9 +106,9 @@ endobj @@ -96,9 +106,9 @@ endobj
96 106
97 %% Contents for page 1 107 %% Contents for page 1
98 %% Original object ID: 4 0 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 stream 113 stream
104 BT 114 BT
@@ -109,12 +119,12 @@ ET @@ -109,12 +119,12 @@ ET
109 endstream 119 endstream
110 endobj 120 endobj
111 121
112 -9 0 obj 122 +11 0 obj
113 44 123 44
114 endobj 124 endobj
115 125
116 %% Original object ID: 6 0 126 %% Original object ID: 6 0
117 -10 0 obj 127 +12 0 obj
118 << 128 <<
119 /BaseFont /Helvetica 129 /BaseFont /Helvetica
120 /Encoding /WinAnsiEncoding 130 /Encoding /WinAnsiEncoding
@@ -125,7 +135,7 @@ endobj @@ -125,7 +135,7 @@ endobj
125 endobj 135 endobj
126 136
127 %% Original object ID: 7 0 137 %% Original object ID: 7 0
128 -11 0 obj 138 +13 0 obj
129 [ 139 [
130 /PDF 140 /PDF
131 /Text 141 /Text
@@ -133,26 +143,28 @@ endobj @@ -133,26 +143,28 @@ endobj
133 endobj 143 endobj
134 144
135 xref 145 xref
136 -0 12 146 +0 14
137 0000000000 65535 f 147 0000000000 65535 f
138 0000000052 00000 n 148 0000000052 00000 n
139 0000000134 00000 n 149 0000000134 00000 n
140 0000000353 00000 n 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 trailer << 161 trailer <<
150 /Info 2 0 R 162 /Info 2 0 R
151 /QTest 3 0 R 163 /QTest 3 0 R
152 /Root 1 0 R 164 /Root 1 0 R
153 - /Size 12 165 + /Size 14
154 /ID [<c61bd35bada064f61e0a56aa9588064e><31415926535897932384626433832795>] 166 /ID [<c61bd35bada064f61e0a56aa9588064e><31415926535897932384626433832795>]
155 >> 167 >>
156 startxref 168 startxref
157 -1285 169 +1388
158 %%EOF 170 %%EOF
qpdf/qtest/qpdf/unreferenced-indirect-scalar.out
No preview for this file type