From ccad589f7d2e732f780d7160af0b23546888fa82 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sun, 25 Feb 2024 12:17:14 +0000 Subject: [PATCH] In QPDFWriter replace map xref with new ObjTable new_obj --- include/qpdf/QPDF.hh | 12 ++++----- include/qpdf/QPDFWriter.hh | 2 ++ libqpdf/QPDFWriter.cc | 39 ++++++++++++++---------------- libqpdf/QPDF_linearization.cc | 22 ++++++++--------- libqpdf/qpdf/QPDFWriter_private.hh | 12 ++++++++- 5 files changed, 48 insertions(+), 39 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 331a5f1f..046c0103 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -743,7 +743,7 @@ class QPDF static void generateHintStream( QPDF& qpdf, - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj, std::shared_ptr& hint_stream, @@ -751,7 +751,7 @@ class QPDF int& O, bool compressed) { - return qpdf.generateHintStream(xref, lengths, obj, hint_stream, S, O, compressed); + return qpdf.generateHintStream(new_obj, lengths, obj, hint_stream, S, O, compressed); } static void @@ -1102,7 +1102,7 @@ class QPDF std::vector& part9); void generateHintStream( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj, std::shared_ptr& hint_stream, @@ -1381,15 +1381,15 @@ class QPDF std::map const& lengths, QPDFWriter::ObjTable const& obj); void calculateHPageOffset( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj); void calculateHSharedObject( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj); void calculateHOutline( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj); void writeHPageOffset(BitWriter&); diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 78fa9280..0d0a69e4 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -439,7 +439,9 @@ class QPDFWriter // The following structs / classes are not part of the public API. struct Object; + struct NewObject; class ObjTable; + class NewObjTable; private: // flags used by unparseObject diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index 66480049..51052cdb 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -1038,7 +1038,7 @@ QPDFWriter::openObject(int objid) if (objid == 0) { objid = m->next_objid++; } - m->xref[objid] = QPDFXRefEntry(m->pipeline->getCount()); + m->new_obj[objid].xref = QPDFXRefEntry(m->pipeline->getCount()); writeString(std::to_string(objid)); writeString(" 0 obj\n"); return objid; @@ -1050,7 +1050,7 @@ QPDFWriter::closeObject(int objid) // Write a newline before endobj as it makes the file easier to repair. writeString("\nendobj\n"); writeStringQDF("\n"); - m->lengths[objid] = m->pipeline->getCount() - m->xref[objid].getOffset(); + m->lengths[objid] = m->pipeline->getCount() - m->new_obj[objid].xref.getOffset(); } void @@ -1703,7 +1703,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) } writeObject(obj_to_write, count); - m->xref[new_obj] = QPDFXRefEntry(new_stream_id, count); + m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); } } @@ -1978,8 +1978,6 @@ QPDFWriter::generateObjectStreams() std::vector eligible = QPDF::Writer::getCompressibleObjGens(m->pdf); size_t n_object_streams = (eligible.size() + 99U) / 100U; - // Initialize object table for all existing objects plus some headroom for objects created - // during writing. initializeTables(2U * n_object_streams); if (n_object_streams == 0) { m->obj.streams_empty = true; @@ -2065,6 +2063,7 @@ QPDFWriter::initializeTables(size_t extra) { auto size = QIntC::to_size(QPDF::Writer::tableSize(m->pdf) + 100) + extra; m->obj.initialize(size); + m->new_obj.initialize(size); } void @@ -2136,8 +2135,6 @@ QPDFWriter::doWriteSetup() switch (m->object_stream_mode) { case qpdf_o_disable: - // Initialize object table for all existing objects plus some headroom for objects created - // during writing. initializeTables(); m->obj.streams_empty = true; break; @@ -2245,12 +2242,12 @@ QPDFWriter::getWrittenXRefTable() { std::map result; - for (auto const& iter: m->xref) { - if (iter.first != 0 && iter.second.getType() != 0) { - result[QPDFObjGen(iter.first, 0)] = iter.second; + auto it = result.begin(); + m->new_obj.forEach([&it, &result](auto id, auto const& item) -> void { + if (item.xref.getType() != 0) { + it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref); } - } - + }); return result; } @@ -2313,7 +2310,7 @@ QPDFWriter::writeHintStream(int hint_id) int O = 0; bool compressed = (m->compress_streams && !m->qdf_mode); QPDF::Writer::generateHintStream( - m->pdf, m->xref, m->lengths, m->obj, hint_buffer, S, O, compressed); + m->pdf, m->new_obj, m->lengths, m->obj, hint_buffer, S, O, compressed); openObject(hint_id); setDataKey(hint_id); @@ -2386,7 +2383,7 @@ QPDFWriter::writeXRefTable( } else { qpdf_offset_t offset = 0; if (!suppress_offsets) { - offset = m->xref[i].getOffset(); + offset = m->new_obj[i].xref.getOffset(); if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) { offset += hint_length; } @@ -2439,7 +2436,7 @@ QPDFWriter::writeXRefStream( // Must store in xref table in advance of writing the actual data rather than waiting for // openObject to do it. - m->xref[xref_id] = QPDFXRefEntry(m->pipeline->getCount()); + m->new_obj[xref_id].xref = QPDFXRefEntry(m->pipeline->getCount()); Pipeline* p = pushPipeline(new Pl_Buffer("xref stream")); bool compressed = false; @@ -2457,7 +2454,7 @@ QPDFWriter::writeXRefStream( PipelinePopper pp_xref(this, &xref_data); activatePipelineStack(pp_xref); for (int i = first; i <= last; ++i) { - QPDFXRefEntry& e = m->xref[i]; + QPDFXRefEntry& e = m->new_obj[i].xref; switch (e.getType()) { case 0: writeBinary(0, 1); @@ -2712,7 +2709,7 @@ QPDFWriter::writeLinearized() writeString(std::to_string(file_size + hint_length)); // Implementation note 121 states that a space is mandatory after this open bracket. writeString(" /H [ "); - writeString(std::to_string(m->xref[hint_id].getOffset())); + writeString(std::to_string(m->new_obj[hint_id].xref.getOffset())); writeString(" "); writeString(std::to_string(hint_length)); writeString(" ] /O "); @@ -2739,7 +2736,7 @@ QPDFWriter::writeLinearized() qpdf_offset_t first_xref_offset = m->pipeline->getCount(); qpdf_offset_t hint_offset = 0; if (pass == 2) { - hint_offset = m->xref[hint_id].getOffset(); + hint_offset = m->new_obj[hint_id].xref.getOffset(); } if (need_xref_stream) { // Must pad here too. @@ -2810,7 +2807,7 @@ QPDFWriter::writeLinearized() writeEncryptionDictionary(); } if (pass == 1) { - m->xref[hint_id] = QPDFXRefEntry(m->pipeline->getCount()); + m->new_obj[hint_id].xref = QPDFXRefEntry(m->pipeline->getCount()); } else { // Part 5: hint stream writeBuffer(hint_buffer); @@ -2883,7 +2880,7 @@ QPDFWriter::writeLinearized() pp_pass1 = nullptr; // Save hint offset since it will be set to zero by calling openObject. - qpdf_offset_t hint_offset1 = m->xref[hint_id].getOffset(); + qpdf_offset_t hint_offset1 = m->new_obj[hint_id].xref.getOffset(); // Write hint stream to a buffer { @@ -2895,7 +2892,7 @@ QPDFWriter::writeLinearized() hint_length = QIntC::to_offset(hint_buffer->getSize()); // Restore hint offset - m->xref[hint_id] = QPDFXRefEntry(hint_offset1); + m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1); if (lin_pass1_file) { // Write some debugging information fprintf( diff --git a/libqpdf/QPDF_linearization.cc b/libqpdf/QPDF_linearization.cc index 4891900b..de32beb1 100644 --- a/libqpdf/QPDF_linearization.cc +++ b/libqpdf/QPDF_linearization.cc @@ -1481,7 +1481,7 @@ QPDF::outputLengthNextN( void QPDF::calculateHPageOffset( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj) { @@ -1530,8 +1530,7 @@ QPDF::calculateHPageOffset( } ph.min_nobjects = min_nobjects; - int out_page0_id = obj[pages.at(0)].renumber; - ph.first_page_offset = (*(xref.find(out_page0_id))).second.getOffset(); + ph.first_page_offset = new_obj[obj[pages.at(0)].renumber].xref.getOffset(); ph.nbits_delta_nobjects = nbits(max_nobjects - min_nobjects); ph.min_page_length = min_length; ph.nbits_delta_page_length = nbits(max_length - min_length); @@ -1566,7 +1565,7 @@ QPDF::calculateHPageOffset( void QPDF::calculateHSharedObject( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj) { @@ -1595,7 +1594,8 @@ QPDF::calculateHSharedObject( so.nshared_first_page = cso.nshared_first_page; if (so.nshared_total > so.nshared_first_page) { so.first_shared_obj = obj[cso.first_shared_obj].renumber; - so.first_shared_offset = (*(xref.find(so.first_shared_obj))).second.getOffset(); + so.min_group_length = min_length; + so.first_shared_offset = new_obj[so.first_shared_obj].xref.getOffset(); } so.min_group_length = min_length; so.nbits_delta_group_length = nbits(max_length - min_length); @@ -1611,7 +1611,7 @@ QPDF::calculateHSharedObject( void QPDF::calculateHOutline( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj) { @@ -1624,7 +1624,7 @@ QPDF::calculateHOutline( HGeneric& ho = m->outline_hints; ho.first_object = obj[cho.first_object].renumber; - ho.first_object_offset = (*(xref.find(ho.first_object))).second.getOffset(); + ho.first_object_offset = new_obj[ho.first_object].xref.getOffset(); ho.nobjects = cho.nobjects; ho.group_length = outputLengthNextN(cho.first_object, ho.nobjects, lengths, obj); } @@ -1755,7 +1755,7 @@ QPDF::writeHGeneric(BitWriter& w, HGeneric& t) void QPDF::generateHintStream( - std::map const& xref, + QPDFWriter::NewObjTable const& new_obj, std::map const& lengths, QPDFWriter::ObjTable const& obj, std::shared_ptr& hint_buffer, @@ -1764,9 +1764,9 @@ QPDF::generateHintStream( bool compressed) { // Populate actual hint table values - calculateHPageOffset(xref, lengths, obj); - calculateHSharedObject(xref, lengths, obj); - calculateHOutline(xref, lengths, obj); + calculateHPageOffset(new_obj, lengths, obj); + calculateHSharedObject(new_obj, lengths, obj); + calculateHOutline(new_obj, lengths, obj); // Write the hint stream itself into a compressed memory buffer. Write through a counter so we // can get offsets. diff --git a/libqpdf/qpdf/QPDFWriter_private.hh b/libqpdf/qpdf/QPDFWriter_private.hh index 3857caeb..eeff3888 100644 --- a/libqpdf/qpdf/QPDFWriter_private.hh +++ b/libqpdf/qpdf/QPDFWriter_private.hh @@ -15,6 +15,11 @@ struct QPDFWriter::Object int object_stream{0}; }; +struct QPDFWriter::NewObject +{ + QPDFXRefEntry xref; +}; + class QPDFWriter::ObjTable: public ::ObjTable { friend class QPDFWriter; @@ -31,6 +36,11 @@ class QPDFWriter::ObjTable: public ::ObjTable bool streams_empty{false}; }; +class QPDFWriter::NewObjTable: public ::ObjTable +{ + friend class QPDFWriter; +}; + class QPDFWriter::Members { friend class QPDFWriter; @@ -91,7 +101,7 @@ class QPDFWriter::Members std::vector object_queue; size_t object_queue_front{0}; QPDFWriter::ObjTable obj; - std::map xref; + QPDFWriter::NewObjTable new_obj; std::map lengths; int next_objid{1}; int cur_stream_length_id{0};