Commit 95a45263878f33a84afba7cd7826c8dc1ea5a5b5

Authored by m-holger
Committed by GitHub
2 parents b40533ad 6cadafda

Merge pull request #1404 from m-holger/writer

Refactor writing of object streams
libqpdf/QPDFWriter.cc
@@ -1646,36 +1646,12 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1646,36 +1646,12 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1646 std::shared_ptr<Buffer> stream_buffer; 1646 std::shared_ptr<Buffer> stream_buffer;
1647 int first_obj = -1; 1647 int first_obj = -1;
1648 bool compressed = false; 1648 bool compressed = false;
1649 - for (int pass = 1; pass <= 2; ++pass) {  
1650 - // stream_buffer will be initialized only for pass 2  
1651 - PipelinePopper pp_ostream(this, &stream_buffer);  
1652 - if (pass == 1) {  
1653 - pushDiscardFilter(pp_ostream);  
1654 - } else {  
1655 - // Adjust offsets to skip over comment before first object  
1656 - first = offsets.at(0);  
1657 - for (auto& iter: offsets) {  
1658 - iter -= first;  
1659 - }  
1660 -  
1661 - // Take one pass at writing pairs of numbers so we can get their size information  
1662 - {  
1663 - PipelinePopper pp_discard(this);  
1664 - pushDiscardFilter(pp_discard);  
1665 - writeObjectStreamOffsets(offsets, first_obj);  
1666 - first += m->pipeline->getCount();  
1667 - } 1649 + {
  1650 + // Pass 1
  1651 + PipelinePopper pp_ostream_pass1(this, &stream_buffer);
1668 1652
1669 - // Set up a stream to write the stream data into a buffer.  
1670 - Pipeline* next = pushPipeline(new Pl_Buffer("object stream"));  
1671 - if (m->compress_streams && !m->qdf_mode) {  
1672 - compressed = true;  
1673 - next =  
1674 - pushPipeline(new Pl_Flate("compress object stream", next, Pl_Flate::a_deflate));  
1675 - }  
1676 - activatePipelineStack(pp_ostream);  
1677 - writeObjectStreamOffsets(offsets, first_obj);  
1678 - } 1653 + pushPipeline(new Pl_Buffer("object stream"));
  1654 + activatePipelineStack(pp_ostream_pass1);
1679 1655
1680 int count = -1; 1656 int count = -1;
1681 for (auto const& obj: m->object_stream_to_objects[old_id]) { 1657 for (auto const& obj: m->object_stream_to_objects[old_id]) {
@@ -1700,12 +1676,12 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1700,12 +1676,12 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1700 } 1676 }
1701 writeString("\n"); 1677 writeString("\n");
1702 } 1678 }
1703 - if (pass == 1) {  
1704 - offsets.push_back(m->pipeline->getCount());  
1705 - // To avoid double-counting objects being written in object streams for progress  
1706 - // reporting, decrement in pass 1.  
1707 - indicateProgress(true, false);  
1708 - } 1679 +
  1680 + offsets.push_back(m->pipeline->getCount());
  1681 + // To avoid double-counting objects being written in object streams for progress
  1682 + // reporting, decrement in pass 1.
  1683 + indicateProgress(true, false);
  1684 +
1709 QPDFObjectHandle obj_to_write = m->pdf.getObject(obj); 1685 QPDFObjectHandle obj_to_write = m->pdf.getObject(obj);
1710 if (obj_to_write.isStream()) { 1686 if (obj_to_write.isStream()) {
1711 // This condition occurred in a fuzz input. Ideally we should block it at parse 1687 // This condition occurred in a fuzz input. Ideally we should block it at parse
@@ -1718,6 +1694,32 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1718,6 +1694,32 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1718 m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); 1694 m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count);
1719 } 1695 }
1720 } 1696 }
  1697 + {
  1698 + PipelinePopper pp_ostream(this, &stream_buffer);
  1699 + // Adjust offsets to skip over comment before first object
  1700 + first = offsets.at(0);
  1701 + for (auto& iter: offsets) {
  1702 + iter -= first;
  1703 + }
  1704 +
  1705 + // Take one pass at writing pairs of numbers so we can get their size information
  1706 + {
  1707 + PipelinePopper pp_discard(this);
  1708 + pushDiscardFilter(pp_discard);
  1709 + writeObjectStreamOffsets(offsets, first_obj);
  1710 + first += m->pipeline->getCount();
  1711 + }
  1712 +
  1713 + // Set up a stream to write the stream data into a buffer.
  1714 + Pipeline* next = pushPipeline(new Pl_Buffer("object stream"));
  1715 + if (m->compress_streams && !m->qdf_mode) {
  1716 + compressed = true;
  1717 + next = pushPipeline(new Pl_Flate("compress object stream", next, Pl_Flate::a_deflate));
  1718 + }
  1719 + activatePipelineStack(pp_ostream);
  1720 + writeObjectStreamOffsets(offsets, first_obj);
  1721 + writeBuffer(stream_buffer);
  1722 + }
1721 1723
1722 // Write the object 1724 // Write the object
1723 openObject(new_stream_id); 1725 openObject(new_stream_id);
manual/release-notes.rst
@@ -26,6 +26,9 @@ more detail. @@ -26,6 +26,9 @@ more detail.
26 - There have been further enhancements to how files with damaged xref 26 - There have been further enhancements to how files with damaged xref
27 tables are recovered. 27 tables are recovered.
28 28
  29 + - There has been some refactoring of how object streams are written with
  30 + some performance improvement.
  31 +
29 .. cSpell:ignore substract 32 .. cSpell:ignore substract
30 33
31 .. _r12-0-0: 34 .. _r12-0-0: