2
1
mirror of https://github.com/qpdf/qpdf.git synced 2025-02-02 11:58:25 +00:00

refactor to isolate pad calculation

git-svn-id: svn+q:///qpdf/trunk@956 71b93d88-0707-0410-a8cf-f5a4172ac649
This commit is contained in:
Jay Berkenbilt 2010-04-18 23:01:31 +00:00
parent 71f171356a
commit 84353451a3
2 changed files with 44 additions and 48 deletions

View File

@ -183,6 +183,7 @@ class QPDFWriter
void writeBuffer(PointerHolder<Buffer>&); void writeBuffer(PointerHolder<Buffer>&);
void writeStringQDF(std::string const& str); void writeStringQDF(std::string const& str);
void writeStringNoQDF(std::string const& str); void writeStringNoQDF(std::string const& str);
void writePad(int nspaces);
void assignCompressedObjectNumbers(int objid); void assignCompressedObjectNumbers(int objid);
void enqueueObject(QPDFObjectHandle object); void enqueueObject(QPDFObjectHandle object);
void writeObjectStreamOffsets(std::vector<int>& offsets, int first_obj); void writeObjectStreamOffsets(std::vector<int>& offsets, int first_obj);
@ -242,6 +243,7 @@ class QPDFWriter
int hint_offset, int hint_offset,
int hint_length, int hint_length,
bool skip_compression); bool skip_compression);
int calculateXrefStreamPadding(int xref_bytes);
// When filtering subsections, push additional pipelines to the // When filtering subsections, push additional pipelines to the
// stack. When ready to switch, activate the pipeline stack. // stack. When ready to switch, activate the pipeline stack.

View File

@ -498,6 +498,15 @@ QPDFWriter::writeStringNoQDF(std::string const& str)
} }
} }
void
QPDFWriter::writePad(int nspaces)
{
for (int i = 0; i < nspaces; ++i)
{
writeString(" ");
}
}
Pipeline* Pipeline*
QPDFWriter::pushPipeline(Pipeline* p) QPDFWriter::pushPipeline(Pipeline* p)
{ {
@ -770,10 +779,7 @@ QPDFWriter::writeTrailer(trailer_e which, int size, bool xref_stream, int prev)
writeString(QUtil::int_to_string(prev)); writeString(QUtil::int_to_string(prev));
int nspaces = pos + 11 - this->pipeline->getCount(); int nspaces = pos + 11 - this->pipeline->getCount();
assert(nspaces >= 0); assert(nspaces >= 0);
for (int i = 0; i < nspaces; ++i) writePad(nspaces);
{
writeString(" ");
}
} }
} }
else else
@ -1855,6 +1861,20 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, int max_offset,
return space_before_zero; return space_before_zero;
} }
int
QPDFWriter::calculateXrefStreamPadding(int xref_bytes)
{
// This routine is called right after a linearization first pass
// xref stream has been written without compression. Calculate
// the amount of padding that would be required in the worst case,
// assuming the number of uncompressed bytes remains the same.
// The worst case for zlib is that the output is larger than the
// input by 6 bytes plus 5 bytes per 16K, and then we'll add 10
// extra bytes for number length increases.
return 16 + (5 * ((xref_bytes + 16383) / 16384));
}
void void
QPDFWriter::writeLinearized() QPDFWriter::writeLinearized()
{ {
@ -2016,10 +2036,7 @@ QPDFWriter::writeLinearized()
static int const pad = 150; static int const pad = 150;
int spaces = (pos + pad - this->pipeline->getCount()); int spaces = (pos + pad - this->pipeline->getCount());
assert(spaces >= 0); assert(spaces >= 0);
for (int i = 0; i < spaces; ++i) writePad(spaces);
{
writeString(" ");
}
writeString("\n"); writeString("\n");
// Part 3: first page cross reference table and trailer. // Part 3: first page cross reference table and trailer.
@ -2057,32 +2074,16 @@ QPDFWriter::writeLinearized()
if (pass == 1) if (pass == 1)
{ {
// Pad so we have enough room for the real xref // Pad so we have enough room for the real xref
// stream. We've written the stream without // stream.
// compression (but with all the stream dictionary writePad(calculateXrefStreamPadding(endpos - pos));
// parameters to enable it) and assuming a very
// generous allowance for writing file offsets. We
// need a little extra padding to allow for zlib's
// output to be larger than its input (6 bytes plus 5
// bytes per 16K), and then we'll add 10 extra bytes
// for number length increases.
unsigned int xref_bytes = endpos - pos;
int possible_extra =
16 + (5 * ((xref_bytes + 16383) / 16384));
for (int i = 0; i < possible_extra; ++i)
{
writeString(" ");
}
first_xref_end = this->pipeline->getCount(); first_xref_end = this->pipeline->getCount();
} }
else else
{ {
// Pad so that the next object starts at the same // Pad so that the next object starts at the same
// place as in pass 1. // place as in pass 1.
for (int i = 0; i < first_xref_end - endpos; ++i) writePad(first_xref_end - endpos);
{
writeString(" ");
}
// A failure of this insertion means we didn't allow // A failure of this insertion means we didn't allow
// enough padding for the first pass xref stream. // enough padding for the first pass xref stream.
assert(this->pipeline->getCount() == first_xref_end); assert(this->pipeline->getCount() == first_xref_end);
@ -2139,27 +2140,23 @@ QPDFWriter::writeLinearized()
second_xref_offset = this->pipeline->getCount(); second_xref_offset = this->pipeline->getCount();
if (need_xref_stream) if (need_xref_stream)
{ {
pos = this->pipeline->getCount();
space_before_zero = space_before_zero =
writeXRefStream(second_half_xref, writeXRefStream(second_half_xref,
second_half_end, second_xref_offset, second_half_end, second_xref_offset,
t_lin_second, 0, second_half_end, t_lin_second, 0, second_half_end,
second_trailer_size); second_trailer_size/*,
0, 0, 0, 0, (pass == 1)*/);
/// int endpos = this->pipeline->getCount();
if (pass == 1) if (pass == 1)
{ {
// Add some padding -- we need an accurate file_size // Pad so we have enough room for the real xref
// number, and this could change if the pass 2 xref // stream. See comments for previous xref stream on
// stream compresses differently. There shouldn't be // how we calculate the padding.
// much difference, so we'll just pad 100 characters.
// This is unscientific though, and may not always /// writePad(calculateXrefStreamPadding(endpos - pos));
// work. The only way we could really get around this writePad(99);
// would be to seek back to the beginning of the file
// and update /L in the linearization dictionary, but
// that would be the only thing in the design that
// would require the output file to be seekable.
for (int i = 0; i < 99; ++i)
{
writeString(" ");
}
writeString("\n"); writeString("\n");
second_xref_end = this->pipeline->getCount(); second_xref_end = this->pipeline->getCount();
} }
@ -2167,12 +2164,9 @@ QPDFWriter::writeLinearized()
{ {
// Make the file size the same. // Make the file size the same.
int pos = this->pipeline->getCount(); int pos = this->pipeline->getCount();
while (pos < second_xref_end + hint_length - 1) writePad(second_xref_end + hint_length - 1 - pos);
{
++pos;
writeString(" ");
}
writeString("\n"); writeString("\n");
// If this assertion fails, maybe we didn't have // If this assertion fails, maybe we didn't have
// enough padding above. // enough padding above.
assert(this->pipeline->getCount() == assert(this->pipeline->getCount() ==