Commit 84353451a33171b587c0bdeaae745dbc0e553fff

Authored by Jay Berkenbilt
1 parent 71f17135

refactor to isolate pad calculation

git-svn-id: svn+q:///qpdf/trunk@956 71b93d88-0707-0410-a8cf-f5a4172ac649
include/qpdf/QPDFWriter.hh
... ... @@ -183,6 +183,7 @@ class QPDFWriter
183 183 void writeBuffer(PointerHolder<Buffer>&);
184 184 void writeStringQDF(std::string const& str);
185 185 void writeStringNoQDF(std::string const& str);
  186 + void writePad(int nspaces);
186 187 void assignCompressedObjectNumbers(int objid);
187 188 void enqueueObject(QPDFObjectHandle object);
188 189 void writeObjectStreamOffsets(std::vector<int>& offsets, int first_obj);
... ... @@ -242,6 +243,7 @@ class QPDFWriter
242 243 int hint_offset,
243 244 int hint_length,
244 245 bool skip_compression);
  246 + int calculateXrefStreamPadding(int xref_bytes);
245 247  
246 248 // When filtering subsections, push additional pipelines to the
247 249 // stack. When ready to switch, activate the pipeline stack.
... ...
libqpdf/QPDFWriter.cc
... ... @@ -498,6 +498,15 @@ QPDFWriter::writeStringNoQDF(std::string const&amp; str)
498 498 }
499 499 }
500 500  
  501 +void
  502 +QPDFWriter::writePad(int nspaces)
  503 +{
  504 + for (int i = 0; i < nspaces; ++i)
  505 + {
  506 + writeString(" ");
  507 + }
  508 +}
  509 +
501 510 Pipeline*
502 511 QPDFWriter::pushPipeline(Pipeline* p)
503 512 {
... ... @@ -770,10 +779,7 @@ QPDFWriter::writeTrailer(trailer_e which, int size, bool xref_stream, int prev)
770 779 writeString(QUtil::int_to_string(prev));
771 780 int nspaces = pos + 11 - this->pipeline->getCount();
772 781 assert(nspaces >= 0);
773   - for (int i = 0; i < nspaces; ++i)
774   - {
775   - writeString(" ");
776   - }
  782 + writePad(nspaces);
777 783 }
778 784 }
779 785 else
... ... @@ -1855,6 +1861,20 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, int max_offset,
1855 1861 return space_before_zero;
1856 1862 }
1857 1863  
  1864 +int
  1865 +QPDFWriter::calculateXrefStreamPadding(int xref_bytes)
  1866 +{
  1867 + // This routine is called right after a linearization first pass
  1868 + // xref stream has been written without compression. Calculate
  1869 + // the amount of padding that would be required in the worst case,
  1870 + // assuming the number of uncompressed bytes remains the same.
  1871 + // The worst case for zlib is that the output is larger than the
  1872 + // input by 6 bytes plus 5 bytes per 16K, and then we'll add 10
  1873 + // extra bytes for number length increases.
  1874 +
  1875 + return 16 + (5 * ((xref_bytes + 16383) / 16384));
  1876 +}
  1877 +
1858 1878 void
1859 1879 QPDFWriter::writeLinearized()
1860 1880 {
... ... @@ -2016,10 +2036,7 @@ QPDFWriter::writeLinearized()
2016 2036 static int const pad = 150;
2017 2037 int spaces = (pos + pad - this->pipeline->getCount());
2018 2038 assert(spaces >= 0);
2019   - for (int i = 0; i < spaces; ++i)
2020   - {
2021   - writeString(" ");
2022   - }
  2039 + writePad(spaces);
2023 2040 writeString("\n");
2024 2041  
2025 2042 // Part 3: first page cross reference table and trailer.
... ... @@ -2057,32 +2074,16 @@ QPDFWriter::writeLinearized()
2057 2074 if (pass == 1)
2058 2075 {
2059 2076 // Pad so we have enough room for the real xref
2060   - // stream. We've written the stream without
2061   - // compression (but with all the stream dictionary
2062   - // parameters to enable it) and assuming a very
2063   - // generous allowance for writing file offsets. We
2064   - // need a little extra padding to allow for zlib's
2065   - // output to be larger than its input (6 bytes plus 5
2066   - // bytes per 16K), and then we'll add 10 extra bytes
2067   - // for number length increases.
2068   -
2069   - unsigned int xref_bytes = endpos - pos;
2070   - int possible_extra =
2071   - 16 + (5 * ((xref_bytes + 16383) / 16384));
2072   - for (int i = 0; i < possible_extra; ++i)
2073   - {
2074   - writeString(" ");
2075   - }
  2077 + // stream.
  2078 + writePad(calculateXrefStreamPadding(endpos - pos));
2076 2079 first_xref_end = this->pipeline->getCount();
2077 2080 }
2078 2081 else
2079 2082 {
2080 2083 // Pad so that the next object starts at the same
2081 2084 // place as in pass 1.
2082   - for (int i = 0; i < first_xref_end - endpos; ++i)
2083   - {
2084   - writeString(" ");
2085   - }
  2085 + writePad(first_xref_end - endpos);
  2086 +
2086 2087 // A failure of this insertion means we didn't allow
2087 2088 // enough padding for the first pass xref stream.
2088 2089 assert(this->pipeline->getCount() == first_xref_end);
... ... @@ -2139,27 +2140,23 @@ QPDFWriter::writeLinearized()
2139 2140 second_xref_offset = this->pipeline->getCount();
2140 2141 if (need_xref_stream)
2141 2142 {
  2143 + pos = this->pipeline->getCount();
2142 2144 space_before_zero =
2143 2145 writeXRefStream(second_half_xref,
2144 2146 second_half_end, second_xref_offset,
2145 2147 t_lin_second, 0, second_half_end,
2146   - second_trailer_size);
  2148 + second_trailer_size/*,
  2149 + 0, 0, 0, 0, (pass == 1)*/);
  2150 +/// int endpos = this->pipeline->getCount();
  2151 +
2147 2152 if (pass == 1)
2148 2153 {
2149   - // Add some padding -- we need an accurate file_size
2150   - // number, and this could change if the pass 2 xref
2151   - // stream compresses differently. There shouldn't be
2152   - // much difference, so we'll just pad 100 characters.
2153   - // This is unscientific though, and may not always
2154   - // work. The only way we could really get around this
2155   - // would be to seek back to the beginning of the file
2156   - // and update /L in the linearization dictionary, but
2157   - // that would be the only thing in the design that
2158   - // would require the output file to be seekable.
2159   - for (int i = 0; i < 99; ++i)
2160   - {
2161   - writeString(" ");
2162   - }
  2154 + // Pad so we have enough room for the real xref
  2155 + // stream. See comments for previous xref stream on
  2156 + // how we calculate the padding.
  2157 +
  2158 +/// writePad(calculateXrefStreamPadding(endpos - pos));
  2159 + writePad(99);
2163 2160 writeString("\n");
2164 2161 second_xref_end = this->pipeline->getCount();
2165 2162 }
... ... @@ -2167,12 +2164,9 @@ QPDFWriter::writeLinearized()
2167 2164 {
2168 2165 // Make the file size the same.
2169 2166 int pos = this->pipeline->getCount();
2170   - while (pos < second_xref_end + hint_length - 1)
2171   - {
2172   - ++pos;
2173   - writeString(" ");
2174   - }
  2167 + writePad(second_xref_end + hint_length - 1 - pos);
2175 2168 writeString("\n");
  2169 +
2176 2170 // If this assertion fails, maybe we didn't have
2177 2171 // enough padding above.
2178 2172 assert(this->pipeline->getCount() ==
... ...