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

View File

@ -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

View File

@ -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<QPDFObjGen> 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<QPDFObjGen, QPDFXRefEntry> 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(

View File

@ -1481,7 +1481,7 @@ QPDF::outputLengthNextN(
void
QPDF::calculateHPageOffset(
std::map<int, QPDFXRefEntry> const& xref,
QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> 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<int, QPDFXRefEntry> const& xref,
QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> 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<int, QPDFXRefEntry> const& xref,
QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> 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<int, QPDFXRefEntry> const& xref,
QPDFWriter::NewObjTable const& new_obj,
std::map<int, qpdf_offset_t> const& lengths,
QPDFWriter::ObjTable const& obj,
std::shared_ptr<Buffer>& 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.

View File

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