Commit 84353451a33171b587c0bdeaae745dbc0e553fff
1 parent
71f17135
refactor to isolate pad calculation
git-svn-id: svn+q:///qpdf/trunk@956 71b93d88-0707-0410-a8cf-f5a4172ac649
Showing
2 changed files
with
44 additions
and
48 deletions
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& 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() == | ... | ... |