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,6 +183,7 @@ class QPDFWriter
183 void writeBuffer(PointerHolder<Buffer>&); 183 void writeBuffer(PointerHolder<Buffer>&);
184 void writeStringQDF(std::string const& str); 184 void writeStringQDF(std::string const& str);
185 void writeStringNoQDF(std::string const& str); 185 void writeStringNoQDF(std::string const& str);
  186 + void writePad(int nspaces);
186 void assignCompressedObjectNumbers(int objid); 187 void assignCompressedObjectNumbers(int objid);
187 void enqueueObject(QPDFObjectHandle object); 188 void enqueueObject(QPDFObjectHandle object);
188 void writeObjectStreamOffsets(std::vector<int>& offsets, int first_obj); 189 void writeObjectStreamOffsets(std::vector<int>& offsets, int first_obj);
@@ -242,6 +243,7 @@ class QPDFWriter @@ -242,6 +243,7 @@ class QPDFWriter
242 int hint_offset, 243 int hint_offset,
243 int hint_length, 244 int hint_length,
244 bool skip_compression); 245 bool skip_compression);
  246 + int calculateXrefStreamPadding(int xref_bytes);
245 247
246 // When filtering subsections, push additional pipelines to the 248 // When filtering subsections, push additional pipelines to the
247 // stack. When ready to switch, activate the pipeline stack. 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,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 Pipeline* 510 Pipeline*
502 QPDFWriter::pushPipeline(Pipeline* p) 511 QPDFWriter::pushPipeline(Pipeline* p)
503 { 512 {
@@ -770,10 +779,7 @@ QPDFWriter::writeTrailer(trailer_e which, int size, bool xref_stream, int prev) @@ -770,10 +779,7 @@ QPDFWriter::writeTrailer(trailer_e which, int size, bool xref_stream, int prev)
770 writeString(QUtil::int_to_string(prev)); 779 writeString(QUtil::int_to_string(prev));
771 int nspaces = pos + 11 - this->pipeline->getCount(); 780 int nspaces = pos + 11 - this->pipeline->getCount();
772 assert(nspaces >= 0); 781 assert(nspaces >= 0);
773 - for (int i = 0; i < nspaces; ++i)  
774 - {  
775 - writeString(" ");  
776 - } 782 + writePad(nspaces);
777 } 783 }
778 } 784 }
779 else 785 else
@@ -1855,6 +1861,20 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, int max_offset, @@ -1855,6 +1861,20 @@ QPDFWriter::writeXRefStream(int xref_id, int max_id, int max_offset,
1855 return space_before_zero; 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 void 1878 void
1859 QPDFWriter::writeLinearized() 1879 QPDFWriter::writeLinearized()
1860 { 1880 {
@@ -2016,10 +2036,7 @@ QPDFWriter::writeLinearized() @@ -2016,10 +2036,7 @@ QPDFWriter::writeLinearized()
2016 static int const pad = 150; 2036 static int const pad = 150;
2017 int spaces = (pos + pad - this->pipeline->getCount()); 2037 int spaces = (pos + pad - this->pipeline->getCount());
2018 assert(spaces >= 0); 2038 assert(spaces >= 0);
2019 - for (int i = 0; i < spaces; ++i)  
2020 - {  
2021 - writeString(" ");  
2022 - } 2039 + writePad(spaces);
2023 writeString("\n"); 2040 writeString("\n");
2024 2041
2025 // Part 3: first page cross reference table and trailer. 2042 // Part 3: first page cross reference table and trailer.
@@ -2057,32 +2074,16 @@ QPDFWriter::writeLinearized() @@ -2057,32 +2074,16 @@ QPDFWriter::writeLinearized()
2057 if (pass == 1) 2074 if (pass == 1)
2058 { 2075 {
2059 // Pad so we have enough room for the real xref 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 first_xref_end = this->pipeline->getCount(); 2079 first_xref_end = this->pipeline->getCount();
2077 } 2080 }
2078 else 2081 else
2079 { 2082 {
2080 // Pad so that the next object starts at the same 2083 // Pad so that the next object starts at the same
2081 // place as in pass 1. 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 // A failure of this insertion means we didn't allow 2087 // A failure of this insertion means we didn't allow
2087 // enough padding for the first pass xref stream. 2088 // enough padding for the first pass xref stream.
2088 assert(this->pipeline->getCount() == first_xref_end); 2089 assert(this->pipeline->getCount() == first_xref_end);
@@ -2139,27 +2140,23 @@ QPDFWriter::writeLinearized() @@ -2139,27 +2140,23 @@ QPDFWriter::writeLinearized()
2139 second_xref_offset = this->pipeline->getCount(); 2140 second_xref_offset = this->pipeline->getCount();
2140 if (need_xref_stream) 2141 if (need_xref_stream)
2141 { 2142 {
  2143 + pos = this->pipeline->getCount();
2142 space_before_zero = 2144 space_before_zero =
2143 writeXRefStream(second_half_xref, 2145 writeXRefStream(second_half_xref,
2144 second_half_end, second_xref_offset, 2146 second_half_end, second_xref_offset,
2145 t_lin_second, 0, second_half_end, 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 if (pass == 1) 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 writeString("\n"); 2160 writeString("\n");
2164 second_xref_end = this->pipeline->getCount(); 2161 second_xref_end = this->pipeline->getCount();
2165 } 2162 }
@@ -2167,12 +2164,9 @@ QPDFWriter::writeLinearized() @@ -2167,12 +2164,9 @@ QPDFWriter::writeLinearized()
2167 { 2164 {
2168 // Make the file size the same. 2165 // Make the file size the same.
2169 int pos = this->pipeline->getCount(); 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 writeString("\n"); 2168 writeString("\n");
  2169 +
2176 // If this assertion fails, maybe we didn't have 2170 // If this assertion fails, maybe we didn't have
2177 // enough padding above. 2171 // enough padding above.
2178 assert(this->pipeline->getCount() == 2172 assert(this->pipeline->getCount() ==