2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-10-31 19:02:30 +00:00

In QPDFWriter replace map xref with new ObjTable new_obj

This commit is contained in:
m-holger 2024-02-25 12:17:14 +00:00
parent 47cf4e3a50
commit ccad589f7d
5 changed files with 48 additions and 39 deletions

View File

@ -743,7 +743,7 @@ class QPDF
static void static void
generateHintStream( generateHintStream(
QPDF& qpdf, QPDF& qpdf,
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj, QPDFWriter::ObjTable const& obj,
std::shared_ptr<Buffer>& hint_stream, std::shared_ptr<Buffer>& hint_stream,
@ -751,7 +751,7 @@ class QPDF
int& O, int& O,
bool compressed) 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 static void
@ -1102,7 +1102,7 @@ class QPDF
std::vector<QPDFObjectHandle>& part9); std::vector<QPDFObjectHandle>& part9);
void generateHintStream( void generateHintStream(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj, QPDFWriter::ObjTable const& obj,
std::shared_ptr<Buffer>& hint_stream, std::shared_ptr<Buffer>& hint_stream,
@ -1381,15 +1381,15 @@ class QPDF
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj); QPDFWriter::ObjTable const& obj);
void calculateHPageOffset( void calculateHPageOffset(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj); QPDFWriter::ObjTable const& obj);
void calculateHSharedObject( void calculateHSharedObject(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj); QPDFWriter::ObjTable const& obj);
void calculateHOutline( void calculateHOutline(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj); QPDFWriter::ObjTable const& obj);
void writeHPageOffset(BitWriter&); void writeHPageOffset(BitWriter&);

View File

@ -439,7 +439,9 @@ class QPDFWriter
// The following structs / classes are not part of the public API. // The following structs / classes are not part of the public API.
struct Object; struct Object;
struct NewObject;
class ObjTable; class ObjTable;
class NewObjTable;
private: private:
// flags used by unparseObject // flags used by unparseObject

View File

@ -1038,7 +1038,7 @@ QPDFWriter::openObject(int objid)
if (objid == 0) { if (objid == 0) {
objid = m->next_objid++; 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(std::to_string(objid));
writeString(" 0 obj\n"); writeString(" 0 obj\n");
return objid; return objid;
@ -1050,7 +1050,7 @@ QPDFWriter::closeObject(int objid)
// Write a newline before endobj as it makes the file easier to repair. // Write a newline before endobj as it makes the file easier to repair.
writeString("\nendobj\n"); writeString("\nendobj\n");
writeStringQDF("\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 void
@ -1703,7 +1703,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
} }
writeObject(obj_to_write, count); 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<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(m->pdf); std::vector<QPDFObjGen> eligible = QPDF::Writer::getCompressibleObjGens(m->pdf);
size_t n_object_streams = (eligible.size() + 99U) / 100U; 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); initializeTables(2U * n_object_streams);
if (n_object_streams == 0) { if (n_object_streams == 0) {
m->obj.streams_empty = true; 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; auto size = QIntC::to_size(QPDF::Writer::tableSize(m->pdf) + 100) + extra;
m->obj.initialize(size); m->obj.initialize(size);
m->new_obj.initialize(size);
} }
void void
@ -2136,8 +2135,6 @@ QPDFWriter::doWriteSetup()
switch (m->object_stream_mode) { switch (m->object_stream_mode) {
case qpdf_o_disable: case qpdf_o_disable:
// Initialize object table for all existing objects plus some headroom for objects created
// during writing.
initializeTables(); initializeTables();
m->obj.streams_empty = true; m->obj.streams_empty = true;
break; break;
@ -2245,12 +2242,12 @@ QPDFWriter::getWrittenXRefTable()
{ {
std::map<QPDFObjGen, QPDFXRefEntry> result; std::map<QPDFObjGen, QPDFXRefEntry> result;
for (auto const& iter: m->xref) { auto it = result.begin();
if (iter.first != 0 && iter.second.getType() != 0) { m->new_obj.forEach([&it, &result](auto id, auto const& item) -> void {
result[QPDFObjGen(iter.first, 0)] = iter.second; if (item.xref.getType() != 0) {
it = result.emplace_hint(it, QPDFObjGen(id, 0), item.xref);
} }
} });
return result; return result;
} }
@ -2313,7 +2310,7 @@ QPDFWriter::writeHintStream(int hint_id)
int O = 0; int O = 0;
bool compressed = (m->compress_streams && !m->qdf_mode); bool compressed = (m->compress_streams && !m->qdf_mode);
QPDF::Writer::generateHintStream( 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); openObject(hint_id);
setDataKey(hint_id); setDataKey(hint_id);
@ -2386,7 +2383,7 @@ QPDFWriter::writeXRefTable(
} else { } else {
qpdf_offset_t offset = 0; qpdf_offset_t offset = 0;
if (!suppress_offsets) { 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)) { if ((hint_id != 0) && (i != hint_id) && (offset >= hint_offset)) {
offset += hint_length; 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 // Must store in xref table in advance of writing the actual data rather than waiting for
// openObject to do it. // 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")); Pipeline* p = pushPipeline(new Pl_Buffer("xref stream"));
bool compressed = false; bool compressed = false;
@ -2457,7 +2454,7 @@ QPDFWriter::writeXRefStream(
PipelinePopper pp_xref(this, &xref_data); PipelinePopper pp_xref(this, &xref_data);
activatePipelineStack(pp_xref); activatePipelineStack(pp_xref);
for (int i = first; i <= last; ++i) { for (int i = first; i <= last; ++i) {
QPDFXRefEntry& e = m->xref[i]; QPDFXRefEntry& e = m->new_obj[i].xref;
switch (e.getType()) { switch (e.getType()) {
case 0: case 0:
writeBinary(0, 1); writeBinary(0, 1);
@ -2712,7 +2709,7 @@ QPDFWriter::writeLinearized()
writeString(std::to_string(file_size + hint_length)); writeString(std::to_string(file_size + hint_length));
// Implementation note 121 states that a space is mandatory after this open bracket. // Implementation note 121 states that a space is mandatory after this open bracket.
writeString(" /H [ "); writeString(" /H [ ");
writeString(std::to_string(m->xref[hint_id].getOffset())); writeString(std::to_string(m->new_obj[hint_id].xref.getOffset()));
writeString(" "); writeString(" ");
writeString(std::to_string(hint_length)); writeString(std::to_string(hint_length));
writeString(" ] /O "); writeString(" ] /O ");
@ -2739,7 +2736,7 @@ QPDFWriter::writeLinearized()
qpdf_offset_t first_xref_offset = m->pipeline->getCount(); qpdf_offset_t first_xref_offset = m->pipeline->getCount();
qpdf_offset_t hint_offset = 0; qpdf_offset_t hint_offset = 0;
if (pass == 2) { if (pass == 2) {
hint_offset = m->xref[hint_id].getOffset(); hint_offset = m->new_obj[hint_id].xref.getOffset();
} }
if (need_xref_stream) { if (need_xref_stream) {
// Must pad here too. // Must pad here too.
@ -2810,7 +2807,7 @@ QPDFWriter::writeLinearized()
writeEncryptionDictionary(); writeEncryptionDictionary();
} }
if (pass == 1) { if (pass == 1) {
m->xref[hint_id] = QPDFXRefEntry(m->pipeline->getCount()); m->new_obj[hint_id].xref = QPDFXRefEntry(m->pipeline->getCount());
} else { } else {
// Part 5: hint stream // Part 5: hint stream
writeBuffer(hint_buffer); writeBuffer(hint_buffer);
@ -2883,7 +2880,7 @@ QPDFWriter::writeLinearized()
pp_pass1 = nullptr; pp_pass1 = nullptr;
// Save hint offset since it will be set to zero by calling openObject. // 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 // Write hint stream to a buffer
{ {
@ -2895,7 +2892,7 @@ QPDFWriter::writeLinearized()
hint_length = QIntC::to_offset(hint_buffer->getSize()); hint_length = QIntC::to_offset(hint_buffer->getSize());
// Restore hint offset // Restore hint offset
m->xref[hint_id] = QPDFXRefEntry(hint_offset1); m->new_obj[hint_id].xref = QPDFXRefEntry(hint_offset1);
if (lin_pass1_file) { if (lin_pass1_file) {
// Write some debugging information // Write some debugging information
fprintf( fprintf(

View File

@ -1481,7 +1481,7 @@ QPDF::outputLengthNextN(
void void
QPDF::calculateHPageOffset( QPDF::calculateHPageOffset(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj) QPDFWriter::ObjTable const& obj)
{ {
@ -1530,8 +1530,7 @@ QPDF::calculateHPageOffset(
} }
ph.min_nobjects = min_nobjects; ph.min_nobjects = min_nobjects;
int out_page0_id = obj[pages.at(0)].renumber; ph.first_page_offset = new_obj[obj[pages.at(0)].renumber].xref.getOffset();
ph.first_page_offset = (*(xref.find(out_page0_id))).second.getOffset();
ph.nbits_delta_nobjects = nbits(max_nobjects - min_nobjects); ph.nbits_delta_nobjects = nbits(max_nobjects - min_nobjects);
ph.min_page_length = min_length; ph.min_page_length = min_length;
ph.nbits_delta_page_length = nbits(max_length - min_length); ph.nbits_delta_page_length = nbits(max_length - min_length);
@ -1566,7 +1565,7 @@ QPDF::calculateHPageOffset(
void void
QPDF::calculateHSharedObject( QPDF::calculateHSharedObject(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj) QPDFWriter::ObjTable const& obj)
{ {
@ -1595,7 +1594,8 @@ QPDF::calculateHSharedObject(
so.nshared_first_page = cso.nshared_first_page; so.nshared_first_page = cso.nshared_first_page;
if (so.nshared_total > so.nshared_first_page) { if (so.nshared_total > so.nshared_first_page) {
so.first_shared_obj = obj[cso.first_shared_obj].renumber; 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.min_group_length = min_length;
so.nbits_delta_group_length = nbits(max_length - min_length); so.nbits_delta_group_length = nbits(max_length - min_length);
@ -1611,7 +1611,7 @@ QPDF::calculateHSharedObject(
void void
QPDF::calculateHOutline( QPDF::calculateHOutline(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj) QPDFWriter::ObjTable const& obj)
{ {
@ -1624,7 +1624,7 @@ QPDF::calculateHOutline(
HGeneric& ho = m->outline_hints; HGeneric& ho = m->outline_hints;
ho.first_object = obj[cho.first_object].renumber; 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.nobjects = cho.nobjects;
ho.group_length = outputLengthNextN(cho.first_object, ho.nobjects, lengths, obj); ho.group_length = outputLengthNextN(cho.first_object, ho.nobjects, lengths, obj);
} }
@ -1755,7 +1755,7 @@ QPDF::writeHGeneric(BitWriter& w, HGeneric& t)
void void
QPDF::generateHintStream( QPDF::generateHintStream(
std::map<int, QPDFXRefEntry> const& xref, QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths, std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj, QPDFWriter::ObjTable const& obj,
std::shared_ptr<Buffer>& hint_buffer, std::shared_ptr<Buffer>& hint_buffer,
@ -1764,9 +1764,9 @@ QPDF::generateHintStream(
bool compressed) bool compressed)
{ {
// Populate actual hint table values // Populate actual hint table values
calculateHPageOffset(xref, lengths, obj); calculateHPageOffset(new_obj, lengths, obj);
calculateHSharedObject(xref, lengths, obj); calculateHSharedObject(new_obj, lengths, obj);
calculateHOutline(xref, lengths, obj); calculateHOutline(new_obj, lengths, obj);
// Write the hint stream itself into a compressed memory buffer. Write through a counter so we // Write the hint stream itself into a compressed memory buffer. Write through a counter so we
// can get offsets. // can get offsets.

View File

@ -15,6 +15,11 @@ struct QPDFWriter::Object
int object_stream{0}; int object_stream{0};
}; };
struct QPDFWriter::NewObject
{
QPDFXRefEntry xref;
};
class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object> class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object>
{ {
friend class QPDFWriter; friend class QPDFWriter;
@ -31,6 +36,11 @@ class QPDFWriter::ObjTable: public ::ObjTable<QPDFWriter::Object>
bool streams_empty{false}; bool streams_empty{false};
}; };
class QPDFWriter::NewObjTable: public ::ObjTable<QPDFWriter::NewObject>
{
friend class QPDFWriter;
};
class QPDFWriter::Members class QPDFWriter::Members
{ {
friend class QPDFWriter; friend class QPDFWriter;
@ -91,7 +101,7 @@ class QPDFWriter::Members
std::vector<QPDFObjectHandle> object_queue; std::vector<QPDFObjectHandle> object_queue;
size_t object_queue_front{0}; size_t object_queue_front{0};
QPDFWriter::ObjTable obj; QPDFWriter::ObjTable obj;
std::map<int, QPDFXRefEntry> xref; QPDFWriter::NewObjTable new_obj;
std::map<int, qpdf_offset_t> lengths; std::map<int, qpdf_offset_t> lengths;
int next_objid{1}; int next_objid{1};
int cur_stream_length_id{0}; int cur_stream_length_id{0};