Commit 6aa6c013034c012f7c843427ddf407925fbbf1c3

Authored by m-holger
Committed by GitHub
2 parents 77d1a0cf 08eb6844

Merge pull request #1171 from m-holger/unresolved

Refactor the creation of unresolved objects
fuzz/CMakeLists.txt
... ... @@ -133,6 +133,8 @@ set(CORPUS_OTHER
133 133 70055.fuzz
134 134 70245.fuzz
135 135 70306.fuzz
  136 + 70306a.fuzz
  137 + 70306b.fuzz
136 138 )
137 139  
138 140 set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus)
... ...
fuzz/qpdf_extra/70306a.fuzz 0 → 100644
No preview for this file type
fuzz/qpdf_extra/70306b.fuzz 0 → 100644
No preview for this file type
fuzz/qtest/fuzz.test
... ... @@ -21,7 +21,7 @@ my @fuzzers = (
21 21 ['pngpredictor' => 1],
22 22 ['runlength' => 6],
23 23 ['tiffpredictor' => 2],
24   - ['qpdf' => 75], # increment when adding new files
  24 + ['qpdf' => 77], # increment when adding new files
25 25 );
26 26  
27 27 my $n_tests = 0;
... ...
include/qpdf/QPDF.hh
... ... @@ -819,7 +819,8 @@ class QPDF
819 819 }
820 820 };
821 821  
822   - // The ParseGuard class allows QPDFParser to detect re-entrant parsing.
  822 + // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides
  823 + // special access to allow the parser to create unresolved objects and dangling references.
823 824 class ParseGuard
824 825 {
825 826 friend class QPDFParser;
... ... @@ -832,6 +833,13 @@ class QPDF
832 833 qpdf->inParse(true);
833 834 }
834 835 }
  836 +
  837 + static std::shared_ptr<QPDFObject>
  838 + getObject(QPDF* qpdf, int id, int gen, bool parse_pdf)
  839 + {
  840 + return qpdf->getObjectForParser(id, gen, parse_pdf);
  841 + }
  842 +
835 843 ~ParseGuard()
836 844 {
837 845 if (qpdf) {
... ... @@ -900,8 +908,8 @@ class QPDF
900 908 }
901 909 ObjCache(
902 910 std::shared_ptr<QPDFObject> object,
903   - qpdf_offset_t end_before_space,
904   - qpdf_offset_t end_after_space) :
  911 + qpdf_offset_t end_before_space = 0,
  912 + qpdf_offset_t end_after_space = 0) :
905 913 object(object),
906 914 end_before_space(end_before_space),
907 915 end_after_space(end_after_space)
... ... @@ -1065,13 +1073,14 @@ class QPDF
1065 1073 QPDFObject* resolve(QPDFObjGen og);
1066 1074 void resolveObjectsInStream(int obj_stream_number);
1067 1075 void stopOnError(std::string const& message);
1068   - QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og);
1069 1076 QPDFObjectHandle reserveStream(QPDFObjGen const& og);
1070 1077 QPDFObjGen nextObjGen();
1071 1078 QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr<QPDFObject> const&);
1072 1079 QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr<QPDFObject> const& obj);
1073 1080 bool isCached(QPDFObjGen const& og);
1074 1081 bool isUnresolved(QPDFObjGen const& og);
  1082 + std::shared_ptr<QPDFObject> getObjectForParser(int id, int gen, bool parse_pdf);
  1083 + std::shared_ptr<QPDFObject> getObjectForJSON(int id, int gen);
1075 1084 void removeObject(QPDFObjGen og);
1076 1085 void updateCache(
1077 1086 QPDFObjGen const& og,
... ...
libqpdf/QPDF.cc
... ... @@ -654,9 +654,11 @@ QPDF::reconstruct_xref(QPDFExc&amp; e)
654 654 }
655 655 check_warnings();
656 656 if (!m->parsed) {
  657 + m->parsed = true;
657 658 getAllPages();
658 659 check_warnings();
659 660 if (m->all_pages.empty()) {
  661 + m->parsed = false;
660 662 throw damagedPDF("", 0, "unable to find any pages while recovering damaged file");
661 663 }
662 664 }
... ... @@ -1462,7 +1464,8 @@ QPDF::readTrailer()
1462 1464 {
1463 1465 qpdf_offset_t offset = m->file->tell();
1464 1466 bool empty = false;
1465   - auto object = QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this).parse(empty, false);
  1467 + auto object =
  1468 + QPDFParser(m->file, "trailer", m->tokenizer, nullptr, this, true).parse(empty, false);
1466 1469 if (empty) {
1467 1470 // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
1468 1471 // actual PDF files and Adobe Reader appears to ignore them.
... ... @@ -1484,8 +1487,9 @@ QPDF::readObject(std::string const&amp; description, QPDFObjGen og)
1484 1487  
1485 1488 StringDecrypter decrypter{this, og};
1486 1489 StringDecrypter* decrypter_ptr = m->encp->encrypted ? &decrypter : nullptr;
1487   - auto object = QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this)
1488   - .parse(empty, false);
  1490 + auto object =
  1491 + QPDFParser(m->file, m->last_object_description, m->tokenizer, decrypter_ptr, this, true)
  1492 + .parse(empty, false);
1489 1493 if (empty) {
1490 1494 // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
1491 1495 // actual PDF files and Adobe Reader appears to ignore them.
... ... @@ -1604,7 +1608,7 @@ QPDF::readObjectInStream(std::shared_ptr&lt;InputSource&gt;&amp; input, int obj)
1604 1608 m->last_object_description += " 0";
1605 1609  
1606 1610 bool empty = false;
1607   - auto object = QPDFParser(input, m->last_object_description, m->tokenizer, nullptr, this)
  1611 + auto object = QPDFParser(input, m->last_object_description, m->tokenizer, nullptr, this, true)
1608 1612 .parse(empty, false);
1609 1613 if (empty) {
1610 1614 // Nothing in the PDF spec appears to allow empty objects, but they have been encountered in
... ... @@ -2094,30 +2098,52 @@ QPDF::newStream(std::string const&amp; data)
2094 2098 }
2095 2099  
2096 2100 QPDFObjectHandle
2097   -QPDF::reserveObjectIfNotExists(QPDFObjGen const& og)
  2101 +QPDF::reserveStream(QPDFObjGen const& og)
2098 2102 {
2099   - if (!isCached(og) && m->xref_table.count(og) == 0) {
2100   - updateCache(og, QPDF_Reserved::create(), -1, -1);
2101   - return newIndirect(og, m->obj_cache[og].object);
2102   - } else {
2103   - return getObject(og);
  2103 + return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
  2104 +}
  2105 +
  2106 +std::shared_ptr<QPDFObject>
  2107 +QPDF::getObjectForParser(int id, int gen, bool parse_pdf)
  2108 +{
  2109 + // This method is called by the parser and therefore must not resolve any objects.
  2110 + auto og = QPDFObjGen(id, gen);
  2111 + if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) {
  2112 + return iter->second.object;
2104 2113 }
  2114 + if (m->xref_table.count(og) || !m->parsed) {
  2115 + return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object;
  2116 + }
  2117 + if (parse_pdf) {
  2118 + return QPDF_Null::create();
  2119 + }
  2120 + return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object;
2105 2121 }
2106 2122  
2107   -QPDFObjectHandle
2108   -QPDF::reserveStream(QPDFObjGen const& og)
  2123 +std::shared_ptr<QPDFObject>
  2124 +QPDF::getObjectForJSON(int id, int gen)
2109 2125 {
2110   - return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)};
  2126 + auto og = QPDFObjGen(id, gen);
  2127 + auto [it, inserted] = m->obj_cache.try_emplace(og);
  2128 + auto& obj = it->second.object;
  2129 + if (inserted) {
  2130 + obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og)
  2131 + : QPDF_Unresolved::create(this, og);
  2132 + }
  2133 + return obj;
2111 2134 }
2112 2135  
2113 2136 QPDFObjectHandle
2114 2137 QPDF::getObject(QPDFObjGen const& og)
2115 2138 {
2116   - // This method is called by the parser and therefore must not resolve any objects.
2117   - if (!isCached(og)) {
2118   - m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1);
  2139 + if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) {
  2140 + return {it->second.object};
  2141 + } else if (m->parsed && !m->xref_table.count(og)) {
  2142 + return QPDF_Null::create();
  2143 + } else {
  2144 + auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1);
  2145 + return {result.first->second.object};
2119 2146 }
2120   - return newIndirect(og, m->obj_cache[og].object);
2121 2147 }
2122 2148  
2123 2149 QPDFObjectHandle
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -2146,7 +2146,8 @@ QPDFObjectHandle::parseContentStream_data(
2146 2146 tokenizer.readToken(input, "content", true);
2147 2147 qpdf_offset_t offset = input->getLastOffset();
2148 2148 input->seek(offset, SEEK_SET);
2149   - auto obj = QPDFParser(input, "content", tokenizer, nullptr, context).parse(empty, true);
  2149 + auto obj =
  2150 + QPDFParser(input, "content", tokenizer, nullptr, context, false).parse(empty, true);
2150 2151 if (!obj.isInitialized()) {
2151 2152 // EOF
2152 2153 break;
... ... @@ -2205,7 +2206,8 @@ QPDFObjectHandle::parse(
2205 2206 StringDecrypter* decrypter,
2206 2207 QPDF* context)
2207 2208 {
2208   - return QPDFParser(input, object_description, tokenizer, decrypter, context).parse(empty, false);
  2209 + return QPDFParser(input, object_description, tokenizer, decrypter, context, false)
  2210 + .parse(empty, false);
2209 2211 }
2210 2212  
2211 2213 #ifndef QPDF_FUTURE
... ...
libqpdf/QPDFOutlineDocumentHelper.cc
... ... @@ -71,7 +71,7 @@ QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
71 71 m->dest_dict = qpdf.getRoot().getKey("/Dests");
72 72 }
73 73 QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
74   - result= m->dest_dict.getKeyIfDict(name.getName());
  74 + result = m->dest_dict.getKeyIfDict(name.getName());
75 75 } else if (name.isString()) {
76 76 if (!m->names_dest) {
77 77 auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests");
... ...
libqpdf/QPDFParser.cc
... ... @@ -166,10 +166,7 @@ QPDFParser::parseRemainder(bool content_stream)
166 166 auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]);
167 167 auto gen = QIntC::to_int(int_buffer[(int_count) % 2]);
168 168 if (!(id < 1 || gen < 0 || gen >= 65535)) {
169   - // This action has the desirable side effect of causing dangling references
170   - // (references to indirect objects that don't appear in the PDF) in any parsed
171   - // object to appear in the object cache.
172   - add(std::move(context->getObject(id, gen).obj));
  169 + add(QPDF::ParseGuard::getObject(context, id, gen, parse_pdf));
173 170 } else {
174 171 QTC::TC("qpdf", "QPDFParser invalid objgen");
175 172 addNull();
... ...
libqpdf/QPDFWriter.cc
... ... @@ -1237,7 +1237,7 @@ bool
1237 1237 QPDFWriter::willFilterStream(
1238 1238 QPDFObjectHandle stream,
1239 1239 bool& compress_stream, // out only
1240   - bool& is_metadata, // out only
  1240 + bool& is_metadata, // out only
1241 1241 std::shared_ptr<Buffer>* stream_data)
1242 1242 {
1243 1243 compress_stream = false;
... ...
libqpdf/QPDF_Null.cc
... ... @@ -3,15 +3,15 @@
3 3 #include <qpdf/JSON_writer.hh>
4 4 #include <qpdf/QPDFObject_private.hh>
5 5  
6   -QPDF_Null::QPDF_Null() :
7   - QPDFValue(::ot_null, "null")
  6 +QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) :
  7 + QPDFValue(::ot_null, "null", qpdf, og)
8 8 {
9 9 }
10 10  
11 11 std::shared_ptr<QPDFObject>
12   -QPDF_Null::create()
  12 +QPDF_Null::create(QPDF* qpdf, QPDFObjGen og)
13 13 {
14   - return do_create(new QPDF_Null());
  14 + return do_create(new QPDF_Null(qpdf, og));
15 15 }
16 16  
17 17 std::shared_ptr<QPDFObject>
... ...
libqpdf/QPDF_json.cc
... ... @@ -240,11 +240,6 @@ class QPDF::JSONReactor: public JSON::Reactor
240 240 descr(std::make_shared<QPDFValue::Description>(
241 241 QPDFValue::JSON_Descr(std::make_shared<std::string>(is->getName()), "")))
242 242 {
243   - for (auto& oc: pdf.m->obj_cache) {
244   - if (oc.second.object->getTypeCode() == ::ot_reserved) {
245   - reserved.insert(oc.first);
246   - }
247   - }
248 243 }
249 244 ~JSONReactor() override = default;
250 245 void dictionaryStart() override;
... ... @@ -272,10 +267,10 @@ class QPDF::JSONReactor: public JSON::Reactor
272 267 struct StackFrame
273 268 {
274 269 StackFrame(state_e state) :
275   - state(state){};
  270 + state(state) {};
276 271 StackFrame(state_e state, QPDFObjectHandle&& object) :
277 272 state(state),
278   - object(object){};
  273 + object(object) {};
279 274 state_e state;
280 275 QPDFObjectHandle object;
281 276 };
... ... @@ -305,7 +300,6 @@ class QPDF::JSONReactor: public JSON::Reactor
305 300 bool saw_data{false};
306 301 bool saw_datafile{false};
307 302 bool this_stream_needs_data{false};
308   - std::set<QPDFObjGen> reserved;
309 303 std::vector<StackFrame> stack;
310 304 QPDFObjectHandle next_obj;
311 305 state_e next_state{st_top};
... ... @@ -416,16 +410,6 @@ QPDF::JSONReactor::containerEnd(JSON const&amp; value)
416 410 }
417 411 }
418 412 }
419   - } else if (from_state == st_qpdf) {
420   - // Handle dangling indirect object references which the PDF spec says to treat as nulls.
421   - // It's tempting to make this an error, but that would be wrong since valid input files may
422   - // have these.
423   - for (auto& oc: pdf.m->obj_cache) {
424   - if (oc.second.object->getTypeCode() == ::ot_reserved && reserved.count(oc.first) == 0) {
425   - QTC::TC("qpdf", "QPDF_json non-trivial null reserved");
426   - pdf.updateCache(oc.first, QPDF_Null::create(), -1, -1);
427   - }
428   - }
429 413 }
430 414 if (!stack.empty()) {
431 415 auto state = stack.back().state;
... ... @@ -565,7 +549,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const&amp; key, JSON const&amp; value)
565 549 } else if (is_obj_key(key, obj, gen)) {
566 550 this->cur_object = key;
567 551 if (setNextStateIfDictionary(key, value, st_object_top)) {
568   - next_obj = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen));
  552 + next_obj = pdf.getObjectForJSON(obj, gen);
569 553 }
570 554 } else {
571 555 QTC::TC("qpdf", "QPDF_json bad object key");
... ... @@ -767,7 +751,7 @@ QPDF::JSONReactor::makeObject(JSON const&amp; value)
767 751 int gen = 0;
768 752 std::string str;
769 753 if (is_indirect_object(str_v, obj, gen)) {
770   - result = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen));
  754 + result = pdf.getObjectForJSON(obj, gen);
771 755 } else if (is_unicode_string(str_v, str)) {
772 756 result = QPDFObjectHandle::newUnicodeString(str);
773 757 } else if (is_binary_string(str_v, str)) {
... ...
libqpdf/qpdf/QPDFParser.hh
... ... @@ -16,14 +16,16 @@ class QPDFParser
16 16 std::string const& object_description,
17 17 QPDFTokenizer& tokenizer,
18 18 QPDFObjectHandle::StringDecrypter* decrypter,
19   - QPDF* context) :
  19 + QPDF* context,
  20 + bool parse_pdf) :
20 21 input(input),
21 22 object_description(object_description),
22 23 tokenizer(tokenizer),
23 24 decrypter(decrypter),
24 25 context(context),
25 26 description(std::make_shared<QPDFValue::Description>(
26   - std::string(input->getName() + ", " + object_description + " at offset $PO")))
  27 + std::string(input->getName() + ", " + object_description + " at offset $PO"))),
  28 + parse_pdf(parse_pdf)
27 29 {
28 30 }
29 31 virtual ~QPDFParser() = default;
... ... @@ -76,6 +78,8 @@ class QPDFParser
76 78 QPDFObjectHandle::StringDecrypter* decrypter;
77 79 QPDF* context;
78 80 std::shared_ptr<QPDFValue::Description> description;
  81 + bool parse_pdf;
  82 +
79 83 std::vector<StackFrame> stack;
80 84 StackFrame* frame;
81 85 // Number of recent bad tokens.
... ...
libqpdf/qpdf/QPDF_Null.hh
... ... @@ -7,7 +7,7 @@ class QPDF_Null: public QPDFValue
7 7 {
8 8 public:
9 9 ~QPDF_Null() override = default;
10   - static std::shared_ptr<QPDFObject> create();
  10 + static std::shared_ptr<QPDFObject> create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
11 11 static std::shared_ptr<QPDFObject> create(
12 12 std::shared_ptr<QPDFObject> parent,
13 13 std::string_view const& static_descr,
... ... @@ -21,7 +21,7 @@ class QPDF_Null: public QPDFValue
21 21 void writeJSON(int json_version, JSON::Writer& p) override;
22 22  
23 23 private:
24   - QPDF_Null();
  24 + QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen());
25 25 };
26 26  
27 27 #endif // QPDF_NULL_HH
... ...
libqpdf/qpdf/qpdf-c_impl.hh
... ... @@ -16,7 +16,7 @@ struct _qpdf_data
16 16 _qpdf_data() = default;
17 17  
18 18 _qpdf_data(std::unique_ptr<QPDF>&& qpdf) :
19   - qpdf(std::move(qpdf)){};
  19 + qpdf(std::move(qpdf)) {};
20 20  
21 21 ~_qpdf_data() = default;
22 22  
... ...
libtests/sparse_array.cc
... ... @@ -90,17 +90,17 @@ main()
90 90  
91 91 obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true);
92 92 QPDF_Array& b = *obj->as<QPDF_Array>();
93   - b.setAt(5, pdf.getObject(5, 0));
  93 + b.setAt(5, pdf.newIndirectNull());
94 94 b.setAt(7, "[0 1 2 3]"_qpdf);
95 95 assert(b.at(3).isNull());
96 96 assert(b.at(8).isNull());
97 97 assert(b.at(5).isIndirect());
98   - assert(b.unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]");
  98 + assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
99 99 auto c = b.copy(true);
100 100 auto d = b.copy(false);
101 101 b.at(7).setArrayItem(2, "42"_qpdf);
102   - assert(c->unparse() == "[ null null null null null 5 0 R null [ 0 1 42 3 ] null null ]");
103   - assert(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]");
  102 + assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]");
  103 + assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]");
104 104  
105 105 try {
106 106 b.setAt(3, {});
... ...
qpdf/qpdf.testcov
... ... @@ -675,7 +675,6 @@ QPDF_json ignore second-level key 0
675 675 QPDF_json ignore unknown key in object_top 0
676 676 QPDF_json ignore unknown key in trailer 0
677 677 QPDF_json ignore unknown key in stream 0
678   -QPDF_json non-trivial null reserved 0
679 678 QPDF_json data and datafile 0
680 679 QPDF_json no stream data in update mode 0
681 680 QPDF_json updating existing stream 0
... ...
qpdf/qtest/qpdf/dangling-bad-xref-dangling-out.pdf
No preview for this file type
qpdf/qtest/qpdf/dangling-bad-xref-dangling.out
1 1 WARNING: dangling-bad-xref.pdf: file is damaged
2 2 WARNING: dangling-bad-xref.pdf (object 7 0, offset 10000): expected n n obj
3 3 WARNING: dangling-bad-xref.pdf: Attempting to reconstruct cross-reference table
4   -new object: 13 0 R
  4 +new object: 12 0 R
5 5 all objects
6 6 1 0 R
7 7 2 0 R
... ... @@ -10,10 +10,6 @@ all objects
10 10 5 0 R
11 11 6 0 R
12 12 7 0 R
13   -8 0 R
14   -9 0 R
15   -10 0 R
16 13 11 0 R
17 14 12 0 R
18   -13 0 R
19 15 test 53 done
... ...
qpdf/qtest/qpdf/dangling-refs-dangling-out.pdf
No preview for this file type
qpdf/qtest/qpdf/dangling-refs-dangling.out
1   -new object: 11 0 R
  1 +new object: 8 0 R
2 2 all objects
3 3 1 0 R
4 4 2 0 R
... ... @@ -8,7 +8,4 @@ all objects
8 8 6 0 R
9 9 7 0 R
10 10 8 0 R
11   -9 0 R
12   -10 0 R
13   -11 0 R
14 11 test 53 done
... ...
qpdf/qtest/qpdf/good13.out
... ... @@ -7,5 +7,5 @@
7 7 /nesting is direct
8 8 /strings is direct
9 9 unparse: 7 0 R
10   -unparseResolved: << /dangling-ref-for-json-test [ 9 0 R ] /hex#20strings [ (Potato) <01020300040560> (AB) ] /indirect 8 0 R /names [ /nesting /hex#20strings /text#2fplain ] /nesting << /a [ 1 2 << /x (y) >> [ (z) ] ] /b << / (legal) /a [ 1 2 ] >> >> /strings [ (one) <24a2> () (\(\)) (\() (\)) (a\f\b\t\r\nb) (") ("") ("\("\)") <410042> (a\nb) (a b) <efbbbfcf80> <efbbbff09fa594> ] >>
  10 +unparseResolved: << /dangling-ref-for-json-test [ null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] /indirect 8 0 R /names [ /nesting /hex#20strings /text#2fplain ] /nesting << /a [ 1 2 << /x (y) >> [ (z) ] ] /b << / (legal) /a [ 1 2 ] >> >> /strings [ (one) <24a2> () (\(\)) (\() (\)) (a\f\b\t\r\nb) (") ("") ("\("\)") <410042> (a\nb) (a b) <efbbbfcf80> <efbbbff09fa594> ] >>
11 11 test 1 done
... ...
qpdf/qtest/qpdf/good13.qdf
... ... @@ -14,14 +14,14 @@ endobj
14 14 2 0 obj
15 15 <<
16 16 /dangling-ref-for-json-test [
17   - 4 0 R
  17 + null
18 18 ]
19 19 /hex#20strings [
20 20 (Potato)
21 21 <01020300040560>
22 22 (AB)
23 23 ]
24   - /indirect 5 0 R
  24 + /indirect 4 0 R
25 25 /names [
26 26 /nesting
27 27 /hex#20strings
... ... @@ -71,27 +71,22 @@ endobj
71 71 <<
72 72 /Count 1
73 73 /Kids [
74   - 6 0 R
  74 + 5 0 R
75 75 ]
76 76 /Type /Pages
77 77 >>
78 78 endobj
79 79  
80   -%% Original object ID: 9 0
81   -4 0 obj
82   -null
83   -endobj
84   -
85 80 %% Original object ID: 8 0
86   -5 0 obj
  81 +4 0 obj
87 82 (hello)
88 83 endobj
89 84  
90 85 %% Page 1
91 86 %% Original object ID: 3 0
92   -6 0 obj
  87 +5 0 obj
93 88 <<
94   - /Contents 7 0 R
  89 + /Contents 6 0 R
95 90 /MediaBox [
96 91 0
97 92 0
... ... @@ -101,9 +96,9 @@ endobj
101 96 /Parent 3 0 R
102 97 /Resources <<
103 98 /Font <<
104   - /F1 9 0 R
  99 + /F1 8 0 R
105 100 >>
106   - /ProcSet 10 0 R
  101 + /ProcSet 9 0 R
107 102 >>
108 103 /Type /Page
109 104 >>
... ... @@ -111,9 +106,9 @@ endobj
111 106  
112 107 %% Contents for page 1
113 108 %% Original object ID: 4 0
114   -7 0 obj
  109 +6 0 obj
115 110 <<
116   - /Length 8 0 R
  111 + /Length 7 0 R
117 112 >>
118 113 stream
119 114 BT
... ... @@ -124,12 +119,12 @@ ET
124 119 endstream
125 120 endobj
126 121  
127   -8 0 obj
  122 +7 0 obj
128 123 44
129 124 endobj
130 125  
131 126 %% Original object ID: 6 0
132   -9 0 obj
  127 +8 0 obj
133 128 <<
134 129 /BaseFont /Helvetica
135 130 /Encoding /WinAnsiEncoding
... ... @@ -140,7 +135,7 @@ endobj
140 135 endobj
141 136  
142 137 %% Original object ID: 5 0
143   -10 0 obj
  138 +9 0 obj
144 139 [
145 140 /PDF
146 141 /Text
... ... @@ -148,24 +143,23 @@ endobj
148 143 endobj
149 144  
150 145 xref
151   -0 11
  146 +0 10
152 147 0000000000 65535 f
153 148 0000000052 00000 n
154 149 0000000133 00000 n
155   -0000000756 00000 n
156   -0000000855 00000 n
157   -0000000903 00000 n
158   -0000000964 00000 n
159   -0000001207 00000 n
160   -0000001306 00000 n
161   -0000001352 00000 n
162   -0000001497 00000 n
  150 +0000000755 00000 n
  151 +0000000854 00000 n
  152 +0000000915 00000 n
  153 +0000001157 00000 n
  154 +0000001256 00000 n
  155 +0000001302 00000 n
  156 +0000001447 00000 n
163 157 trailer <<
164 158 /QTest 2 0 R
165 159 /Root 1 0 R
166   - /Size 11
  160 + /Size 10
167 161 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
168 162 >>
169 163 startxref
170   -1533
  164 +1482
171 165 %%EOF
... ...
qpdf/qtest/qpdf/good21.out
... ... @@ -5,7 +5,7 @@
5 5 item 2 is direct
6 6 item 3 is indirect
7 7 item 4 is direct
8   - item 5 is indirect
  8 + item 5 is direct
9 9 unparse: 9 0 R
10   -unparseResolved: [ /literal null /indirect 8 0 R /undefined 10 0 R ]
  10 +unparseResolved: [ /literal null /indirect 8 0 R /undefined null ]
11 11 test 1 done
... ...
qpdf/qtest/qpdf/good21.qdf
... ... @@ -18,7 +18,7 @@ endobj
18 18 /indirect
19 19 4 0 R
20 20 /undefined
21   - 5 0 R
  21 + null
22 22 ]
23 23 endobj
24 24  
... ... @@ -27,7 +27,7 @@ endobj
27 27 <<
28 28 /Count 1
29 29 /Kids [
30   - 6 0 R
  30 + 5 0 R
31 31 ]
32 32 /Type /Pages
33 33 >>
... ... @@ -38,16 +38,11 @@ endobj
38 38 null
39 39 endobj
40 40  
41   -%% Original object ID: 10 0
42   -5 0 obj
43   -null
44   -endobj
45   -
46 41 %% Page 1
47 42 %% Original object ID: 3 0
48   -6 0 obj
  43 +5 0 obj
49 44 <<
50   - /Contents 7 0 R
  45 + /Contents 6 0 R
51 46 /MediaBox [
52 47 0
53 48 0
... ... @@ -57,9 +52,9 @@ endobj
57 52 /Parent 3 0 R
58 53 /Resources <<
59 54 /Font <<
60   - /F1 9 0 R
  55 + /F1 8 0 R
61 56 >>
62   - /ProcSet 10 0 R
  57 + /ProcSet 9 0 R
63 58 >>
64 59 /Type /Page
65 60 >>
... ... @@ -67,9 +62,9 @@ endobj
67 62  
68 63 %% Contents for page 1
69 64 %% Original object ID: 4 0
70   -7 0 obj
  65 +6 0 obj
71 66 <<
72   - /Length 8 0 R
  67 + /Length 7 0 R
73 68 >>
74 69 stream
75 70 BT
... ... @@ -80,12 +75,12 @@ ET
80 75 endstream
81 76 endobj
82 77  
83   -8 0 obj
  78 +7 0 obj
84 79 44
85 80 endobj
86 81  
87 82 %% Original object ID: 6 0
88   -9 0 obj
  83 +8 0 obj
89 84 <<
90 85 /BaseFont /Helvetica
91 86 /Encoding /WinAnsiEncoding
... ... @@ -96,7 +91,7 @@ endobj
96 91 endobj
97 92  
98 93 %% Original object ID: 7 0
99   -10 0 obj
  94 +9 0 obj
100 95 [
101 96 /PDF
102 97 /Text
... ... @@ -104,24 +99,23 @@ endobj
104 99 endobj
105 100  
106 101 xref
107   -0 11
  102 +0 10
108 103 0000000000 65535 f
109 104 0000000052 00000 n
110 105 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
  106 +0000000238 00000 n
  107 +0000000337 00000 n
  108 +0000000395 00000 n
  109 +0000000637 00000 n
  110 +0000000736 00000 n
  111 +0000000782 00000 n
  112 +0000000927 00000 n
119 113 trailer <<
120 114 /QTest 2 0 R
121 115 /Root 1 0 R
122   - /Size 11
  116 + /Size 10
123 117 /ID [<06c2c8fc54c5f9cc9246898e1e1a7146><31415926535897932384626433832795>]
124 118 >>
125 119 startxref
126   -1014
  120 +962
127 121 %%EOF
... ...
qpdf/qtest/qpdf/json-changed-good13.pdf
... ... @@ -14,14 +14,14 @@ endobj
14 14 2 0 obj
15 15 <<
16 16 /dangling-ref-for-json-test [
17   - 4 0 R
  17 + null
18 18 ]
19 19 /hex#20strings [
20 20 (Potato)
21 21 <01020300040560>
22 22 (AB)
23 23 ]
24   - /indirect 5 0 R
  24 + /indirect 4 0 R
25 25 /names [
26 26 /nesting
27 27 /hex#20strings
... ... @@ -71,27 +71,22 @@ endobj
71 71 <<
72 72 /Count 1
73 73 /Kids [
74   - 6 0 R
  74 + 5 0 R
75 75 ]
76 76 /Type /Pages
77 77 >>
78 78 endobj
79 79  
80   -%% Original object ID: 9 0
81   -4 0 obj
82   -null
83   -endobj
84   -
85 80 %% Original object ID: 8 0
86   -5 0 obj
  81 +4 0 obj
87 82 (hello)
88 83 endobj
89 84  
90 85 %% Page 1
91 86 %% Original object ID: 3 0
92   -6 0 obj
  87 +5 0 obj
93 88 <<
94   - /Contents 7 0 R
  89 + /Contents 6 0 R
95 90 /MediaBox [
96 91 0
97 92 0
... ... @@ -101,9 +96,9 @@ endobj
101 96 /Parent 3 0 R
102 97 /Resources <<
103 98 /Font <<
104   - /F1 9 0 R
  99 + /F1 8 0 R
105 100 >>
106   - /ProcSet 10 0 R
  101 + /ProcSet 9 0 R
107 102 >>
108 103 /Type /Page
109 104 >>
... ... @@ -111,9 +106,9 @@ endobj
111 106  
112 107 %% Contents for page 1
113 108 %% Original object ID: 4 0
114   -7 0 obj
  109 +6 0 obj
115 110 <<
116   - /Length 8 0 R
  111 + /Length 7 0 R
117 112 >>
118 113 stream
119 114 BT
... ... @@ -124,12 +119,12 @@ ET
124 119 endstream
125 120 endobj
126 121  
127   -8 0 obj
  122 +7 0 obj
128 123 44
129 124 endobj
130 125  
131 126 %% Original object ID: 6 0
132   -9 0 obj
  127 +8 0 obj
133 128 <<
134 129 /BaseFont /Helvetica
135 130 /Encoding /WinAnsiEncoding
... ... @@ -140,7 +135,7 @@ endobj
140 135 endobj
141 136  
142 137 %% Original object ID: 5 0
143   -10 0 obj
  138 +9 0 obj
144 139 [
145 140 /PDF
146 141 /Text
... ... @@ -148,24 +143,23 @@ endobj
148 143 endobj
149 144  
150 145 xref
151   -0 11
  146 +0 10
152 147 0000000000 65535 f
153 148 0000000052 00000 n
154 149 0000000133 00000 n
155   -0000000752 00000 n
156   -0000000851 00000 n
157   -0000000899 00000 n
158   -0000000960 00000 n
159   -0000001203 00000 n
160   -0000001302 00000 n
161   -0000001348 00000 n
162   -0000001493 00000 n
  150 +0000000751 00000 n
  151 +0000000850 00000 n
  152 +0000000911 00000 n
  153 +0000001153 00000 n
  154 +0000001252 00000 n
  155 +0000001298 00000 n
  156 +0000001443 00000 n
163 157 trailer <<
164 158 /QTest 2 0 R
165 159 /Root 1 0 R
166   - /Size 11
  160 + /Size 10
167 161 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
168 162 >>
169 163 startxref
170   -1529
  164 +1478
171 165 %%EOF
... ...
qpdf/qtest/qpdf/replace-with-stream-updated.pdf
... ... @@ -14,14 +14,14 @@ endobj
14 14 2 0 obj
15 15 <<
16 16 /dangling-ref-for-json-test [
17   - 4 0 R
  17 + null
18 18 ]
19 19 /hex#20strings [
20 20 (Potato)
21 21 <01020300040560>
22 22 (AB)
23 23 ]
24   - /indirect 5 0 R
  24 + /indirect 4 0 R
25 25 /names [
26 26 /nesting
27 27 /hex#20strings
... ... @@ -71,37 +71,32 @@ endobj
71 71 <<
72 72 /Count 1
73 73 /Kids [
74   - 7 0 R
  74 + 6 0 R
75 75 ]
76 76 /Type /Pages
77 77 >>
78 78 endobj
79 79  
80   -%% Original object ID: 9 0
81   -4 0 obj
82   -null
83   -endobj
84   -
85 80 %% Original object ID: 8 0
86   -5 0 obj
  81 +4 0 obj
87 82 <<
88 83 /K /V
89   - /Length 6 0 R
  84 + /Length 5 0 R
90 85 >>
91 86 stream
92 87 new-stream-here
93 88 endstream
94 89 endobj
95 90  
96   -6 0 obj
  91 +5 0 obj
97 92 16
98 93 endobj
99 94  
100 95 %% Page 1
101 96 %% Original object ID: 3 0
102   -7 0 obj
  97 +6 0 obj
103 98 <<
104   - /Contents 8 0 R
  99 + /Contents 7 0 R
105 100 /MediaBox [
106 101 0
107 102 0
... ... @@ -111,9 +106,9 @@ endobj
111 106 /Parent 3 0 R
112 107 /Resources <<
113 108 /Font <<
114   - /F1 10 0 R
  109 + /F1 9 0 R
115 110 >>
116   - /ProcSet 11 0 R
  111 + /ProcSet 10 0 R
117 112 >>
118 113 /Type /Page
119 114 >>
... ... @@ -121,9 +116,9 @@ endobj
121 116  
122 117 %% Contents for page 1
123 118 %% Original object ID: 4 0
124   -8 0 obj
  119 +7 0 obj
125 120 <<
126   - /Length 9 0 R
  121 + /Length 8 0 R
127 122 >>
128 123 stream
129 124 BT
... ... @@ -134,12 +129,12 @@ ET
134 129 endstream
135 130 endobj
136 131  
137   -9 0 obj
  132 +8 0 obj
138 133 44
139 134 endobj
140 135  
141 136 %% Original object ID: 6 0
142   -10 0 obj
  137 +9 0 obj
143 138 <<
144 139 /BaseFont /Helvetica
145 140 /Encoding /WinAnsiEncoding
... ... @@ -150,7 +145,7 @@ endobj
150 145 endobj
151 146  
152 147 %% Original object ID: 5 0
153   -11 0 obj
  148 +10 0 obj
154 149 [
155 150 /PDF
156 151 /Text
... ... @@ -158,25 +153,24 @@ endobj
158 153 endobj
159 154  
160 155 xref
161   -0 12
  156 +0 11
162 157 0000000000 65535 f
163 158 0000000052 00000 n
164 159 0000000133 00000 n
165   -0000000756 00000 n
166   -0000000855 00000 n
167   -0000000903 00000 n
168   -0000000982 00000 n
169   -0000001038 00000 n
170   -0000001282 00000 n
171   -0000001381 00000 n
172   -0000001427 00000 n
173   -0000001573 00000 n
  160 +0000000755 00000 n
  161 +0000000854 00000 n
  162 +0000000933 00000 n
  163 +0000000989 00000 n
  164 +0000001232 00000 n
  165 +0000001331 00000 n
  166 +0000001377 00000 n
  167 +0000001522 00000 n
174 168 trailer <<
175 169 /QTest 2 0 R
176 170 /Root 1 0 R
177   - /Size 12
  171 + /Size 11
178 172 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
179 173 >>
180 174 startxref
181   -1609
  175 +1558
182 176 %%EOF
... ...
qpdf/qtest/qpdf/update-stream-data-updated.pdf
... ... @@ -14,14 +14,14 @@ endobj
14 14 2 0 obj
15 15 <<
16 16 /dangling-ref-for-json-test [
17   - 4 0 R
  17 + null
18 18 ]
19 19 /hex#20strings [
20 20 (Potato)
21 21 <01020300040560>
22 22 (AB)
23 23 ]
24   - /indirect 5 0 R
  24 + /indirect 4 0 R
25 25 /names [
26 26 /nesting
27 27 /hex#20strings
... ... @@ -71,27 +71,22 @@ endobj
71 71 <<
72 72 /Count 1
73 73 /Kids [
74   - 6 0 R
  74 + 5 0 R
75 75 ]
76 76 /Type /Pages
77 77 >>
78 78 endobj
79 79  
80   -%% Original object ID: 9 0
81   -4 0 obj
82   -null
83   -endobj
84   -
85 80 %% Original object ID: 8 0
86   -5 0 obj
  81 +4 0 obj
87 82 (hello)
88 83 endobj
89 84  
90 85 %% Page 1
91 86 %% Original object ID: 3 0
92   -6 0 obj
  87 +5 0 obj
93 88 <<
94   - /Contents 7 0 R
  89 + /Contents 6 0 R
95 90 /MediaBox [
96 91 0
97 92 0
... ... @@ -101,9 +96,9 @@ endobj
101 96 /Parent 3 0 R
102 97 /Resources <<
103 98 /Font <<
104   - /F1 9 0 R
  99 + /F1 8 0 R
105 100 >>
106   - /ProcSet 10 0 R
  101 + /ProcSet 9 0 R
107 102 >>
108 103 /Type /Page
109 104 >>
... ... @@ -111,9 +106,9 @@ endobj
111 106  
112 107 %% Contents for page 1
113 108 %% Original object ID: 4 0
114   -7 0 obj
  109 +6 0 obj
115 110 <<
116   - /Length 8 0 R
  111 + /Length 7 0 R
117 112 >>
118 113 stream
119 114 BT
... ... @@ -124,12 +119,12 @@ ET
124 119 endstream
125 120 endobj
126 121  
127   -8 0 obj
  122 +7 0 obj
128 123 43
129 124 endobj
130 125  
131 126 %% Original object ID: 6 0
132   -9 0 obj
  127 +8 0 obj
133 128 <<
134 129 /BaseFont /Helvetica
135 130 /Encoding /WinAnsiEncoding
... ... @@ -140,7 +135,7 @@ endobj
140 135 endobj
141 136  
142 137 %% Original object ID: 5 0
143   -10 0 obj
  138 +9 0 obj
144 139 [
145 140 /PDF
146 141 /Text
... ... @@ -148,24 +143,23 @@ endobj
148 143 endobj
149 144  
150 145 xref
151   -0 11
  146 +0 10
152 147 0000000000 65535 f
153 148 0000000052 00000 n
154 149 0000000133 00000 n
155   -0000000756 00000 n
156   -0000000855 00000 n
157   -0000000903 00000 n
158   -0000000964 00000 n
159   -0000001207 00000 n
160   -0000001305 00000 n
161   -0000001351 00000 n
162   -0000001496 00000 n
  150 +0000000755 00000 n
  151 +0000000854 00000 n
  152 +0000000915 00000 n
  153 +0000001157 00000 n
  154 +0000001255 00000 n
  155 +0000001301 00000 n
  156 +0000001446 00000 n
163 157 trailer <<
164 158 /QTest 2 0 R
165 159 /Root 1 0 R
166   - /Size 11
  160 + /Size 10
167 161 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
168 162 >>
169 163 startxref
170   -1532
  164 +1481
171 165 %%EOF
... ...
qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf
... ... @@ -14,14 +14,14 @@ endobj
14 14 2 0 obj
15 15 <<
16 16 /dangling-ref-for-json-test [
17   - 4 0 R
  17 + null
18 18 ]
19 19 /hex#20strings [
20 20 (Potato)
21 21 <01020300040560>
22 22 (AB)
23 23 ]
24   - /indirect 5 0 R
  24 + /indirect 4 0 R
25 25 /names [
26 26 /nesting
27 27 /hex#20strings
... ... @@ -71,27 +71,22 @@ endobj
71 71 <<
72 72 /Count 1
73 73 /Kids [
74   - 6 0 R
  74 + 5 0 R
75 75 ]
76 76 /Type /Pages
77 77 >>
78 78 endobj
79 79  
80   -%% Original object ID: 9 0
81   -4 0 obj
82   -null
83   -endobj
84   -
85 80 %% Original object ID: 8 0
86   -5 0 obj
  81 +4 0 obj
87 82 (hello)
88 83 endobj
89 84  
90 85 %% Page 1
91 86 %% Original object ID: 3 0
92   -6 0 obj
  87 +5 0 obj
93 88 <<
94   - /Contents 7 0 R
  89 + /Contents 6 0 R
95 90 /MediaBox [
96 91 0
97 92 0
... ... @@ -101,9 +96,9 @@ endobj
101 96 /Parent 3 0 R
102 97 /Resources <<
103 98 /Font <<
104   - /F1 9 0 R
  99 + /F1 8 0 R
105 100 >>
106   - /ProcSet 10 0 R
  101 + /ProcSet 9 0 R
107 102 >>
108 103 /Type /Page
109 104 >>
... ... @@ -111,10 +106,10 @@ endobj
111 106  
112 107 %% Contents for page 1
113 108 %% Original object ID: 4 0
114   -7 0 obj
  109 +6 0 obj
115 110 <<
116 111 /Potato (salad)
117   - /Length 8 0 R
  112 + /Length 7 0 R
118 113 >>
119 114 stream
120 115 BT
... ... @@ -125,12 +120,12 @@ ET
125 120 endstream
126 121 endobj
127 122  
128   -8 0 obj
  123 +7 0 obj
129 124 44
130 125 endobj
131 126  
132 127 %% Original object ID: 6 0
133   -9 0 obj
  128 +8 0 obj
134 129 <<
135 130 /BaseFont /Helvetica
136 131 /Encoding /WinAnsiEncoding
... ... @@ -141,7 +136,7 @@ endobj
141 136 endobj
142 137  
143 138 %% Original object ID: 5 0
144   -10 0 obj
  139 +9 0 obj
145 140 [
146 141 /PDF
147 142 /Text
... ... @@ -149,24 +144,23 @@ endobj
149 144 endobj
150 145  
151 146 xref
152   -0 11
  147 +0 10
153 148 0000000000 65535 f
154 149 0000000052 00000 n
155 150 0000000133 00000 n
156   -0000000756 00000 n
157   -0000000855 00000 n
158   -0000000903 00000 n
159   -0000000964 00000 n
160   -0000001207 00000 n
161   -0000001324 00000 n
162   -0000001370 00000 n
163   -0000001515 00000 n
  151 +0000000755 00000 n
  152 +0000000854 00000 n
  153 +0000000915 00000 n
  154 +0000001157 00000 n
  155 +0000001274 00000 n
  156 +0000001320 00000 n
  157 +0000001465 00000 n
164 158 trailer <<
165 159 /QTest 2 0 R
166 160 /Root 1 0 R
167   - /Size 11
  161 + /Size 10
168 162 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>]
169 163 >>
170 164 startxref
171   -1551
  165 +1500
172 166 %%EOF
... ...