From 06001ed25b1f005a91d92104f2d7c47617809cd4 Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 8 Mar 2024 16:57:56 +0000 Subject: [PATCH] Refactor the creation of unresolved objects Create unresolved objects only for objects in the xref table (except during parsing of the xref table). Do not add indirect nulls into the the object cache as the result of a cache miss during a call to getObject except during parsing or creation/updating from JSON. To support this behaviour, add new private methods getObjectForParser and getObjectForJSON. As a result of this change, dangling references are treated as direct nulls rather than indirect nulls. --- include/qpdf/QPDF.hh | 17 +++-- libqpdf/QPDF.cc | 54 +++++++++++----- libqpdf/QPDFParser.cc | 5 +- libqpdf/QPDFWriter.cc | 2 +- libqpdf/QPDF_Null.cc | 8 +-- libqpdf/QPDF_json.cc | 20 +----- libqpdf/qpdf/QPDFParser.hh | 5 +- libqpdf/qpdf/QPDF_Null.hh | 4 +- libtests/sparse_array.cc | 8 +-- qpdf/qpdf.testcov | 1 - .../qpdf/dangling-bad-xref-dangling-out.pdf | Bin 1145 -> 977 bytes .../qtest/qpdf/dangling-bad-xref-dangling.out | 6 +- .../qtest/qpdf/dangling-refs-dangling-out.pdf | Bin 1057 -> 931 bytes qpdf/qtest/qpdf/dangling-refs-dangling.out | 5 +- qpdf/qtest/qpdf/good13.out | 2 +- qpdf/qtest/qpdf/good13.qdf | 52 +++++++--------- qpdf/qtest/qpdf/good21.out | 4 +- qpdf/qtest/qpdf/good21.qdf | 48 +++++++-------- qpdf/qtest/qpdf/json-changed-good13.pdf | 52 +++++++--------- .../qpdf/replace-with-stream-updated.pdf | 58 ++++++++---------- .../qtest/qpdf/update-stream-data-updated.pdf | 52 +++++++--------- .../qpdf/update-stream-dict-only-updated.pdf | 52 +++++++--------- 22 files changed, 214 insertions(+), 241 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index e3238fd4..6e567569 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -819,7 +819,8 @@ class QPDF } }; - // The ParseGuard class allows QPDFParser to detect re-entrant parsing. + // The ParseGuard class allows QPDFParser to detect re-entrant parsing. It also provides + // special access to allow the parser to create unresolved objects and dangling references. class ParseGuard { friend class QPDFParser; @@ -832,6 +833,13 @@ class QPDF qpdf->inParse(true); } } + + static std::shared_ptr + getObject(QPDF* qpdf, int id, int gen, bool parse_pdf) + { + return qpdf->getObjectForParser(id, gen, parse_pdf); + } + ~ParseGuard() { if (qpdf) { @@ -900,8 +908,8 @@ class QPDF } ObjCache( std::shared_ptr object, - qpdf_offset_t end_before_space, - qpdf_offset_t end_after_space) : + qpdf_offset_t end_before_space = 0, + qpdf_offset_t end_after_space = 0) : object(object), end_before_space(end_before_space), end_after_space(end_after_space) @@ -1065,13 +1073,14 @@ class QPDF QPDFObject* resolve(QPDFObjGen og); void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); - QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); QPDFObjectHandle reserveStream(QPDFObjGen const& og); QPDFObjGen nextObjGen(); QPDFObjectHandle newIndirect(QPDFObjGen const&, std::shared_ptr const&); QPDFObjectHandle makeIndirectFromQPDFObject(std::shared_ptr const& obj); bool isCached(QPDFObjGen const& og); bool isUnresolved(QPDFObjGen const& og); + std::shared_ptr getObjectForParser(int id, int gen, bool parse_pdf); + std::shared_ptr getObjectForJSON(int id, int gen); void removeObject(QPDFObjGen og); void updateCache( QPDFObjGen const& og, diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 93d50829..c5f8ee74 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -654,9 +654,11 @@ QPDF::reconstruct_xref(QPDFExc& e) } check_warnings(); if (!m->parsed) { + m->parsed = true; getAllPages(); check_warnings(); if (m->all_pages.empty()) { + m->parsed = false; throw damagedPDF("", 0, "unable to find any pages while recovering damaged file"); } } @@ -2095,31 +2097,53 @@ QPDF::newStream(std::string const& data) return result; } -QPDFObjectHandle -QPDF::reserveObjectIfNotExists(QPDFObjGen const& og) -{ - if (!isCached(og) && m->xref_table.count(og) == 0) { - updateCache(og, QPDF_Reserved::create(), -1, -1); - return newIndirect(og, m->obj_cache[og].object); - } else { - return getObject(og); - } -} - QPDFObjectHandle QPDF::reserveStream(QPDFObjGen const& og) { return {QPDF_Stream::create(this, og, QPDFObjectHandle::newDictionary(), 0, 0)}; } +std::shared_ptr +QPDF::getObjectForParser(int id, int gen, bool parse_pdf) +{ + // This method is called by the parser and therefore must not resolve any objects. + auto og = QPDFObjGen(id, gen); + if (auto iter = m->obj_cache.find(og); iter != m->obj_cache.end()) { + return iter->second.object; + } + if (m->xref_table.count(og) || !m->parsed) { + return m->obj_cache.insert({og, QPDF_Unresolved::create(this, og)}).first->second.object; + } + if (parse_pdf) { + return QPDF_Null::create(); + } + return m->obj_cache.insert({og, QPDF_Null::create(this, og)}).first->second.object; +} + +std::shared_ptr +QPDF::getObjectForJSON(int id, int gen) +{ + auto og = QPDFObjGen(id, gen); + auto [it, inserted] = m->obj_cache.try_emplace(og); + auto& obj = it->second.object; + if (inserted) { + obj = (m->parsed && !m->xref_table.count(og)) ? QPDF_Null::create(this, og) + : QPDF_Unresolved::create(this, og); + } + return obj; +} + QPDFObjectHandle QPDF::getObject(QPDFObjGen const& og) { - // This method is called by the parser and therefore must not resolve any objects. - if (!isCached(og)) { - m->obj_cache[og] = ObjCache(QPDF_Unresolved::create(this, og), -1, -1); + if (auto it = m->obj_cache.find(og); it != m->obj_cache.end()) { + return {it->second.object}; + } else if (m->parsed && !m->xref_table.count(og)) { + return QPDF_Null::create(); + } else { + auto result = m->obj_cache.try_emplace(og, QPDF_Unresolved::create(this, og), -1, -1); + return {result.first->second.object}; } - return newIndirect(og, m->obj_cache[og].object); } QPDFObjectHandle diff --git a/libqpdf/QPDFParser.cc b/libqpdf/QPDFParser.cc index 56448364..08f94c64 100644 --- a/libqpdf/QPDFParser.cc +++ b/libqpdf/QPDFParser.cc @@ -166,10 +166,7 @@ QPDFParser::parseRemainder(bool content_stream) auto id = QIntC::to_int(int_buffer[(int_count - 1) % 2]); auto gen = QIntC::to_int(int_buffer[(int_count) % 2]); if (!(id < 1 || gen < 0 || gen >= 65535)) { - // This action has the desirable side effect of causing dangling references - // (references to indirect objects that don't appear in the PDF) in any parsed - // object to appear in the object cache. - add(std::move(context->getObject(id, gen).obj)); + add(QPDF::ParseGuard::getObject(context, id, gen, parse_pdf)); } else { QTC::TC("qpdf", "QPDFParser invalid objgen"); addNull(); diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index b8b25fa0..d7ac7134 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1237,7 +1237,7 @@ bool QPDFWriter::willFilterStream( QPDFObjectHandle stream, bool& compress_stream, // out only - bool& is_metadata, // out only + bool& is_metadata, // out only std::shared_ptr* stream_data) { compress_stream = false; diff --git a/libqpdf/QPDF_Null.cc b/libqpdf/QPDF_Null.cc index fa4b6cab..9b92c911 100644 --- a/libqpdf/QPDF_Null.cc +++ b/libqpdf/QPDF_Null.cc @@ -3,15 +3,15 @@ #include #include -QPDF_Null::QPDF_Null() : - QPDFValue(::ot_null, "null") +QPDF_Null::QPDF_Null(QPDF* qpdf, QPDFObjGen og) : + QPDFValue(::ot_null, "null", qpdf, og) { } std::shared_ptr -QPDF_Null::create() +QPDF_Null::create(QPDF* qpdf, QPDFObjGen og) { - return do_create(new QPDF_Null()); + return do_create(new QPDF_Null(qpdf, og)); } std::shared_ptr diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index dd4672fe..26814f5d 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -240,11 +240,6 @@ class QPDF::JSONReactor: public JSON::Reactor descr(std::make_shared( QPDFValue::JSON_Descr(std::make_shared(is->getName()), ""))) { - for (auto& oc: pdf.m->obj_cache) { - if (oc.second.object->getTypeCode() == ::ot_reserved) { - reserved.insert(oc.first); - } - } } ~JSONReactor() override = default; void dictionaryStart() override; @@ -305,7 +300,6 @@ class QPDF::JSONReactor: public JSON::Reactor bool saw_data{false}; bool saw_datafile{false}; bool this_stream_needs_data{false}; - std::set reserved; std::vector stack; QPDFObjectHandle next_obj; state_e next_state{st_top}; @@ -416,16 +410,6 @@ QPDF::JSONReactor::containerEnd(JSON const& value) } } } - } else if (from_state == st_qpdf) { - // Handle dangling indirect object references which the PDF spec says to treat as nulls. - // It's tempting to make this an error, but that would be wrong since valid input files may - // have these. - for (auto& oc: pdf.m->obj_cache) { - if (oc.second.object->getTypeCode() == ::ot_reserved && reserved.count(oc.first) == 0) { - QTC::TC("qpdf", "QPDF_json non-trivial null reserved"); - pdf.updateCache(oc.first, QPDF_Null::create(), -1, -1); - } - } } if (!stack.empty()) { auto state = stack.back().state; @@ -565,7 +549,7 @@ QPDF::JSONReactor::dictionaryItem(std::string const& key, JSON const& value) } else if (is_obj_key(key, obj, gen)) { this->cur_object = key; if (setNextStateIfDictionary(key, value, st_object_top)) { - next_obj = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); + next_obj = pdf.getObjectForJSON(obj, gen); } } else { QTC::TC("qpdf", "QPDF_json bad object key"); @@ -767,7 +751,7 @@ QPDF::JSONReactor::makeObject(JSON const& value) int gen = 0; std::string str; if (is_indirect_object(str_v, obj, gen)) { - result = pdf.reserveObjectIfNotExists(QPDFObjGen(obj, gen)); + result = pdf.getObjectForJSON(obj, gen); } else if (is_unicode_string(str_v, str)) { result = QPDFObjectHandle::newUnicodeString(str); } else if (is_binary_string(str_v, str)) { diff --git a/libqpdf/qpdf/QPDFParser.hh b/libqpdf/qpdf/QPDFParser.hh index d6b76a21..e036b022 100644 --- a/libqpdf/qpdf/QPDFParser.hh +++ b/libqpdf/qpdf/QPDFParser.hh @@ -24,7 +24,8 @@ class QPDFParser decrypter(decrypter), context(context), description(std::make_shared( - std::string(input->getName() + ", " + object_description + " at offset $PO"))) + std::string(input->getName() + ", " + object_description + " at offset $PO"))), + parse_pdf(parse_pdf) { } virtual ~QPDFParser() = default; @@ -77,6 +78,8 @@ class QPDFParser QPDFObjectHandle::StringDecrypter* decrypter; QPDF* context; std::shared_ptr description; + bool parse_pdf; + std::vector stack; StackFrame* frame; // Number of recent bad tokens. diff --git a/libqpdf/qpdf/QPDF_Null.hh b/libqpdf/qpdf/QPDF_Null.hh index fc6e0b5f..231ea669 100644 --- a/libqpdf/qpdf/QPDF_Null.hh +++ b/libqpdf/qpdf/QPDF_Null.hh @@ -7,7 +7,7 @@ class QPDF_Null: public QPDFValue { public: ~QPDF_Null() override = default; - static std::shared_ptr create(); + static std::shared_ptr create(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); static std::shared_ptr create( std::shared_ptr parent, std::string_view const& static_descr, @@ -21,7 +21,7 @@ class QPDF_Null: public QPDFValue void writeJSON(int json_version, JSON::Writer& p) override; private: - QPDF_Null(); + QPDF_Null(QPDF* qpdf = nullptr, QPDFObjGen og = QPDFObjGen()); }; #endif // QPDF_NULL_HH diff --git a/libtests/sparse_array.cc b/libtests/sparse_array.cc index 47fe8c26..9405a89b 100644 --- a/libtests/sparse_array.cc +++ b/libtests/sparse_array.cc @@ -90,17 +90,17 @@ main() obj = QPDF_Array::create({10, "null"_qpdf.getObj()}, true); QPDF_Array& b = *obj->as(); - b.setAt(5, pdf.getObject(5, 0)); + b.setAt(5, pdf.newIndirectNull()); b.setAt(7, "[0 1 2 3]"_qpdf); assert(b.at(3).isNull()); assert(b.at(8).isNull()); assert(b.at(5).isIndirect()); - assert(b.unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]"); + assert(b.unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); auto c = b.copy(true); auto d = b.copy(false); b.at(7).setArrayItem(2, "42"_qpdf); - assert(c->unparse() == "[ null null null null null 5 0 R null [ 0 1 42 3 ] null null ]"); - assert(d->unparse() == "[ null null null null null 5 0 R null [ 0 1 2 3 ] null null ]"); + assert(c->unparse() == "[ null null null null null 3 0 R null [ 0 1 42 3 ] null null ]"); + assert(d->unparse() == "[ null null null null null 3 0 R null [ 0 1 2 3 ] null null ]"); try { b.setAt(3, {}); diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index 3ed710d0..733a0169 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -675,7 +675,6 @@ QPDF_json ignore second-level key 0 QPDF_json ignore unknown key in object_top 0 QPDF_json ignore unknown key in trailer 0 QPDF_json ignore unknown key in stream 0 -QPDF_json non-trivial null reserved 0 QPDF_json data and datafile 0 QPDF_json no stream data in update mode 0 QPDF_json updating existing stream 0 diff --git a/qpdf/qtest/qpdf/dangling-bad-xref-dangling-out.pdf b/qpdf/qtest/qpdf/dangling-bad-xref-dangling-out.pdf index db2f38d1f8497410dfda0b7da71818c7344359e5..6f34f1047205e16881eb53cf48d743bd4e7af16f 100644 GIT binary patch delta 203 zcmey#aglw37E4}fPR>MqRYuE=VT??I(F!2GLM&HmUP^va7MJDZeN6I<29xhG88Mnn z7GxH#H&!qJ0fjsTE-=Huz}V0XL(Ih31XIk^2t&-&)Dlz70#nS)5Nhw_&&*0d_lU7X Qa+w*MbE&Gj`nz!f0H+2l{{R30 delta 375 zcmcb}{*z;Z7OSO#fkMzkJyj+{XMnQf_VoAOxOm)TNIwp2TlgVvNMw(^{1|Xo2r@#ef7#J9u zn_`F=8(K_$$RuowsoKQU1Vgo{8PKI@rkYwBPBvr~4#bo(GsYrj3iKeF31;TNkU|qP bH!zs&%B%tOOCED1m${KCm#V6(zZ(|-tSDGx diff --git a/qpdf/qtest/qpdf/dangling-bad-xref-dangling.out b/qpdf/qtest/qpdf/dangling-bad-xref-dangling.out index 05221c72..6b96e2a1 100644 --- a/qpdf/qtest/qpdf/dangling-bad-xref-dangling.out +++ b/qpdf/qtest/qpdf/dangling-bad-xref-dangling.out @@ -1,7 +1,7 @@ WARNING: dangling-bad-xref.pdf: file is damaged WARNING: dangling-bad-xref.pdf (object 7 0, offset 10000): expected n n obj WARNING: dangling-bad-xref.pdf: Attempting to reconstruct cross-reference table -new object: 13 0 R +new object: 12 0 R all objects 1 0 R 2 0 R @@ -10,10 +10,6 @@ all objects 5 0 R 6 0 R 7 0 R -8 0 R -9 0 R -10 0 R 11 0 R 12 0 R -13 0 R test 53 done diff --git a/qpdf/qtest/qpdf/dangling-refs-dangling-out.pdf b/qpdf/qtest/qpdf/dangling-refs-dangling-out.pdf index 75c5e4db60b5b78836877174816e19ca34fe2685..5b64f777947d8dade9191c5ea24823a61211d34c 100644 GIT binary patch delta 184 zcmZ3;v6y{=7E4}fPR>MqRYr@AVT??Zr!t8%T25ZaWW;DP`5}{Vy|ID;2q@$!aDf>H z2F8YF7-A;ICYWNTMi^qIrk0pu7D!?xMTwa?sYMDlHVXPd`S~T2*E911-LsE5iqp`T LOI6j?-;E0ZcZVtq delta 293 zcmZ3?zK~;r7OSO#fkMzkJyj+{!;K+~Oy+r|IXPUZc`5lxSzI7F5REKmXn;-7aIznh z9Fw8Z (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) ] >> +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) ] >> test 1 done diff --git a/qpdf/qtest/qpdf/good13.qdf b/qpdf/qtest/qpdf/good13.qdf index 236ee585..b6c1507c 100644 --- a/qpdf/qtest/qpdf/good13.qdf +++ b/qpdf/qtest/qpdf/good13.qdf @@ -14,14 +14,14 @@ endobj 2 0 obj << /dangling-ref-for-json-test [ - 4 0 R + null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] - /indirect 5 0 R + /indirect 4 0 R /names [ /nesting /hex#20strings @@ -71,27 +71,22 @@ endobj << /Count 1 /Kids [ - 6 0 R + 5 0 R ] /Type /Pages >> endobj -%% Original object ID: 9 0 -4 0 obj -null -endobj - %% Original object ID: 8 0 -5 0 obj +4 0 obj (hello) endobj %% Page 1 %% Original object ID: 3 0 -6 0 obj +5 0 obj << - /Contents 7 0 R + /Contents 6 0 R /MediaBox [ 0 0 @@ -101,9 +96,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 9 0 R + /F1 8 0 R >> - /ProcSet 10 0 R + /ProcSet 9 0 R >> /Type /Page >> @@ -111,9 +106,9 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -7 0 obj +6 0 obj << - /Length 8 0 R + /Length 7 0 R >> stream BT @@ -124,12 +119,12 @@ ET endstream endobj -8 0 obj +7 0 obj 44 endobj %% Original object ID: 6 0 -9 0 obj +8 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -140,7 +135,7 @@ endobj endobj %% Original object ID: 5 0 -10 0 obj +9 0 obj [ /PDF /Text @@ -148,24 +143,23 @@ endobj endobj xref -0 11 +0 10 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000756 00000 n -0000000855 00000 n -0000000903 00000 n -0000000964 00000 n -0000001207 00000 n -0000001306 00000 n -0000001352 00000 n -0000001497 00000 n +0000000755 00000 n +0000000854 00000 n +0000000915 00000 n +0000001157 00000 n +0000001256 00000 n +0000001302 00000 n +0000001447 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 11 + /Size 10 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> startxref -1533 +1482 %%EOF diff --git a/qpdf/qtest/qpdf/good21.out b/qpdf/qtest/qpdf/good21.out index ffcdf2a7..39e1271c 100644 --- a/qpdf/qtest/qpdf/good21.out +++ b/qpdf/qtest/qpdf/good21.out @@ -5,7 +5,7 @@ item 2 is direct item 3 is indirect item 4 is direct - item 5 is indirect + item 5 is direct unparse: 9 0 R -unparseResolved: [ /literal null /indirect 8 0 R /undefined 10 0 R ] +unparseResolved: [ /literal null /indirect 8 0 R /undefined null ] test 1 done diff --git a/qpdf/qtest/qpdf/good21.qdf b/qpdf/qtest/qpdf/good21.qdf index 49bff240..55a65eb4 100644 --- a/qpdf/qtest/qpdf/good21.qdf +++ b/qpdf/qtest/qpdf/good21.qdf @@ -18,7 +18,7 @@ endobj /indirect 4 0 R /undefined - 5 0 R + null ] endobj @@ -27,7 +27,7 @@ endobj << /Count 1 /Kids [ - 6 0 R + 5 0 R ] /Type /Pages >> @@ -38,16 +38,11 @@ endobj null endobj -%% Original object ID: 10 0 -5 0 obj -null -endobj - %% Page 1 %% Original object ID: 3 0 -6 0 obj +5 0 obj << - /Contents 7 0 R + /Contents 6 0 R /MediaBox [ 0 0 @@ -57,9 +52,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 9 0 R + /F1 8 0 R >> - /ProcSet 10 0 R + /ProcSet 9 0 R >> /Type /Page >> @@ -67,9 +62,9 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -7 0 obj +6 0 obj << - /Length 8 0 R + /Length 7 0 R >> stream BT @@ -80,12 +75,12 @@ ET endstream endobj -8 0 obj +7 0 obj 44 endobj %% Original object ID: 6 0 -9 0 obj +8 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -96,7 +91,7 @@ endobj endobj %% Original object ID: 7 0 -10 0 obj +9 0 obj [ /PDF /Text @@ -104,24 +99,23 @@ endobj endobj xref -0 11 +0 10 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000239 00000 n -0000000338 00000 n -0000000387 00000 n -0000000445 00000 n -0000000688 00000 n -0000000787 00000 n -0000000833 00000 n -0000000978 00000 n +0000000238 00000 n +0000000337 00000 n +0000000395 00000 n +0000000637 00000 n +0000000736 00000 n +0000000782 00000 n +0000000927 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 11 + /Size 10 /ID [<06c2c8fc54c5f9cc9246898e1e1a7146><31415926535897932384626433832795>] >> startxref -1014 +962 %%EOF diff --git a/qpdf/qtest/qpdf/json-changed-good13.pdf b/qpdf/qtest/qpdf/json-changed-good13.pdf index 2c25334c..b0cb9cc5 100644 --- a/qpdf/qtest/qpdf/json-changed-good13.pdf +++ b/qpdf/qtest/qpdf/json-changed-good13.pdf @@ -14,14 +14,14 @@ endobj 2 0 obj << /dangling-ref-for-json-test [ - 4 0 R + null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] - /indirect 5 0 R + /indirect 4 0 R /names [ /nesting /hex#20strings @@ -71,27 +71,22 @@ endobj << /Count 1 /Kids [ - 6 0 R + 5 0 R ] /Type /Pages >> endobj -%% Original object ID: 9 0 -4 0 obj -null -endobj - %% Original object ID: 8 0 -5 0 obj +4 0 obj (hello) endobj %% Page 1 %% Original object ID: 3 0 -6 0 obj +5 0 obj << - /Contents 7 0 R + /Contents 6 0 R /MediaBox [ 0 0 @@ -101,9 +96,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 9 0 R + /F1 8 0 R >> - /ProcSet 10 0 R + /ProcSet 9 0 R >> /Type /Page >> @@ -111,9 +106,9 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -7 0 obj +6 0 obj << - /Length 8 0 R + /Length 7 0 R >> stream BT @@ -124,12 +119,12 @@ ET endstream endobj -8 0 obj +7 0 obj 44 endobj %% Original object ID: 6 0 -9 0 obj +8 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -140,7 +135,7 @@ endobj endobj %% Original object ID: 5 0 -10 0 obj +9 0 obj [ /PDF /Text @@ -148,24 +143,23 @@ endobj endobj xref -0 11 +0 10 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000752 00000 n -0000000851 00000 n -0000000899 00000 n -0000000960 00000 n -0000001203 00000 n -0000001302 00000 n -0000001348 00000 n -0000001493 00000 n +0000000751 00000 n +0000000850 00000 n +0000000911 00000 n +0000001153 00000 n +0000001252 00000 n +0000001298 00000 n +0000001443 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 11 + /Size 10 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> startxref -1529 +1478 %%EOF diff --git a/qpdf/qtest/qpdf/replace-with-stream-updated.pdf b/qpdf/qtest/qpdf/replace-with-stream-updated.pdf index d8dc76a3..a1ec222e 100644 --- a/qpdf/qtest/qpdf/replace-with-stream-updated.pdf +++ b/qpdf/qtest/qpdf/replace-with-stream-updated.pdf @@ -14,14 +14,14 @@ endobj 2 0 obj << /dangling-ref-for-json-test [ - 4 0 R + null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] - /indirect 5 0 R + /indirect 4 0 R /names [ /nesting /hex#20strings @@ -71,37 +71,32 @@ endobj << /Count 1 /Kids [ - 7 0 R + 6 0 R ] /Type /Pages >> endobj -%% Original object ID: 9 0 -4 0 obj -null -endobj - %% Original object ID: 8 0 -5 0 obj +4 0 obj << /K /V - /Length 6 0 R + /Length 5 0 R >> stream new-stream-here endstream endobj -6 0 obj +5 0 obj 16 endobj %% Page 1 %% Original object ID: 3 0 -7 0 obj +6 0 obj << - /Contents 8 0 R + /Contents 7 0 R /MediaBox [ 0 0 @@ -111,9 +106,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 10 0 R + /F1 9 0 R >> - /ProcSet 11 0 R + /ProcSet 10 0 R >> /Type /Page >> @@ -121,9 +116,9 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -8 0 obj +7 0 obj << - /Length 9 0 R + /Length 8 0 R >> stream BT @@ -134,12 +129,12 @@ ET endstream endobj -9 0 obj +8 0 obj 44 endobj %% Original object ID: 6 0 -10 0 obj +9 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -150,7 +145,7 @@ endobj endobj %% Original object ID: 5 0 -11 0 obj +10 0 obj [ /PDF /Text @@ -158,25 +153,24 @@ endobj endobj xref -0 12 +0 11 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000756 00000 n -0000000855 00000 n -0000000903 00000 n -0000000982 00000 n -0000001038 00000 n -0000001282 00000 n -0000001381 00000 n -0000001427 00000 n -0000001573 00000 n +0000000755 00000 n +0000000854 00000 n +0000000933 00000 n +0000000989 00000 n +0000001232 00000 n +0000001331 00000 n +0000001377 00000 n +0000001522 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 12 + /Size 11 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> startxref -1609 +1558 %%EOF diff --git a/qpdf/qtest/qpdf/update-stream-data-updated.pdf b/qpdf/qtest/qpdf/update-stream-data-updated.pdf index 3f9ae74d..7a18211d 100644 --- a/qpdf/qtest/qpdf/update-stream-data-updated.pdf +++ b/qpdf/qtest/qpdf/update-stream-data-updated.pdf @@ -14,14 +14,14 @@ endobj 2 0 obj << /dangling-ref-for-json-test [ - 4 0 R + null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] - /indirect 5 0 R + /indirect 4 0 R /names [ /nesting /hex#20strings @@ -71,27 +71,22 @@ endobj << /Count 1 /Kids [ - 6 0 R + 5 0 R ] /Type /Pages >> endobj -%% Original object ID: 9 0 -4 0 obj -null -endobj - %% Original object ID: 8 0 -5 0 obj +4 0 obj (hello) endobj %% Page 1 %% Original object ID: 3 0 -6 0 obj +5 0 obj << - /Contents 7 0 R + /Contents 6 0 R /MediaBox [ 0 0 @@ -101,9 +96,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 9 0 R + /F1 8 0 R >> - /ProcSet 10 0 R + /ProcSet 9 0 R >> /Type /Page >> @@ -111,9 +106,9 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -7 0 obj +6 0 obj << - /Length 8 0 R + /Length 7 0 R >> stream BT @@ -124,12 +119,12 @@ ET endstream endobj -8 0 obj +7 0 obj 43 endobj %% Original object ID: 6 0 -9 0 obj +8 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -140,7 +135,7 @@ endobj endobj %% Original object ID: 5 0 -10 0 obj +9 0 obj [ /PDF /Text @@ -148,24 +143,23 @@ endobj endobj xref -0 11 +0 10 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000756 00000 n -0000000855 00000 n -0000000903 00000 n -0000000964 00000 n -0000001207 00000 n -0000001305 00000 n -0000001351 00000 n -0000001496 00000 n +0000000755 00000 n +0000000854 00000 n +0000000915 00000 n +0000001157 00000 n +0000001255 00000 n +0000001301 00000 n +0000001446 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 11 + /Size 10 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> startxref -1532 +1481 %%EOF diff --git a/qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf b/qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf index f2bd079f..0e3a18bb 100644 --- a/qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf +++ b/qpdf/qtest/qpdf/update-stream-dict-only-updated.pdf @@ -14,14 +14,14 @@ endobj 2 0 obj << /dangling-ref-for-json-test [ - 4 0 R + null ] /hex#20strings [ (Potato) <01020300040560> (AB) ] - /indirect 5 0 R + /indirect 4 0 R /names [ /nesting /hex#20strings @@ -71,27 +71,22 @@ endobj << /Count 1 /Kids [ - 6 0 R + 5 0 R ] /Type /Pages >> endobj -%% Original object ID: 9 0 -4 0 obj -null -endobj - %% Original object ID: 8 0 -5 0 obj +4 0 obj (hello) endobj %% Page 1 %% Original object ID: 3 0 -6 0 obj +5 0 obj << - /Contents 7 0 R + /Contents 6 0 R /MediaBox [ 0 0 @@ -101,9 +96,9 @@ endobj /Parent 3 0 R /Resources << /Font << - /F1 9 0 R + /F1 8 0 R >> - /ProcSet 10 0 R + /ProcSet 9 0 R >> /Type /Page >> @@ -111,10 +106,10 @@ endobj %% Contents for page 1 %% Original object ID: 4 0 -7 0 obj +6 0 obj << /Potato (salad) - /Length 8 0 R + /Length 7 0 R >> stream BT @@ -125,12 +120,12 @@ ET endstream endobj -8 0 obj +7 0 obj 44 endobj %% Original object ID: 6 0 -9 0 obj +8 0 obj << /BaseFont /Helvetica /Encoding /WinAnsiEncoding @@ -141,7 +136,7 @@ endobj endobj %% Original object ID: 5 0 -10 0 obj +9 0 obj [ /PDF /Text @@ -149,24 +144,23 @@ endobj endobj xref -0 11 +0 10 0000000000 65535 f 0000000052 00000 n 0000000133 00000 n -0000000756 00000 n -0000000855 00000 n -0000000903 00000 n -0000000964 00000 n -0000001207 00000 n -0000001324 00000 n -0000001370 00000 n -0000001515 00000 n +0000000755 00000 n +0000000854 00000 n +0000000915 00000 n +0000001157 00000 n +0000001274 00000 n +0000001320 00000 n +0000001465 00000 n trailer << /QTest 2 0 R /Root 1 0 R - /Size 11 + /Size 10 /ID [<31415926535897932384626433832795><31415926535897932384626433832795>] >> startxref -1551 +1500 %%EOF