Commit ae9e65f3ebce92342011e70b70920df52bb41152

Authored by m-holger
1 parent b40533ad

Refactor writing of object streams

Cache output of pass 1.
Showing 1 changed file with 43 additions and 39 deletions
libqpdf/QPDFWriter.cc
@@ -1646,11 +1646,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1646,11 +1646,11 @@ 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 1649 + for (int pass: {1, 2}) {
1651 PipelinePopper pp_ostream(this, &stream_buffer); 1650 PipelinePopper pp_ostream(this, &stream_buffer);
1652 if (pass == 1) { 1651 if (pass == 1) {
1653 - pushDiscardFilter(pp_ostream); 1652 + pushPipeline(new Pl_Buffer("object stream"));
  1653 + activatePipelineStack(pp_ostream);
1654 } else { 1654 } else {
1655 // Adjust offsets to skip over comment before first object 1655 // Adjust offsets to skip over comment before first object
1656 first = offsets.at(0); 1656 first = offsets.at(0);
@@ -1675,47 +1675,51 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) @@ -1675,47 +1675,51 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
1675 } 1675 }
1676 activatePipelineStack(pp_ostream); 1676 activatePipelineStack(pp_ostream);
1677 writeObjectStreamOffsets(offsets, first_obj); 1677 writeObjectStreamOffsets(offsets, first_obj);
  1678 + writeBuffer(stream_buffer);
1678 } 1679 }
1679 1680
1680 - int count = -1;  
1681 - for (auto const& obj: m->object_stream_to_objects[old_id]) {  
1682 - ++count;  
1683 - int new_obj = m->obj[obj].renumber;  
1684 - if (first_obj == -1) {  
1685 - first_obj = new_obj;  
1686 - }  
1687 - if (m->qdf_mode) {  
1688 - writeString(  
1689 - "%% Object stream: object " + std::to_string(new_obj) + ", index " +  
1690 - std::to_string(count));  
1691 - if (!m->suppress_original_object_ids) {  
1692 - writeString("; original object ID: " + std::to_string(obj.getObj()));  
1693 - // For compatibility, only write the generation if non-zero. While object  
1694 - // streams only allow objects with generation 0, if we are generating object  
1695 - // streams, the old object could have a non-zero generation.  
1696 - if (obj.getGen() != 0) {  
1697 - QTC::TC("qpdf", "QPDFWriter original obj non-zero gen");  
1698 - writeString(" " + std::to_string(obj.getGen())); 1681 + if (pass == 1) {
  1682 + int count = -1;
  1683 + for (auto const& obj: m->object_stream_to_objects[old_id]) {
  1684 + ++count;
  1685 + int new_obj = m->obj[obj].renumber;
  1686 + if (first_obj == -1) {
  1687 + first_obj = new_obj;
  1688 + }
  1689 + if (m->qdf_mode) {
  1690 + writeString(
  1691 + "%% Object stream: object " + std::to_string(new_obj) + ", index " +
  1692 + std::to_string(count));
  1693 + if (!m->suppress_original_object_ids) {
  1694 + writeString("; original object ID: " + std::to_string(obj.getObj()));
  1695 + // For compatibility, only write the generation if non-zero. While object
  1696 + // streams only allow objects with generation 0, if we are generating object
  1697 + // streams, the old object could have a non-zero generation.
  1698 + if (obj.getGen() != 0) {
  1699 + QTC::TC("qpdf", "QPDFWriter original obj non-zero gen");
  1700 + writeString(" " + std::to_string(obj.getGen()));
  1701 + }
1699 } 1702 }
  1703 + writeString("\n");
1700 } 1704 }
1701 - writeString("\n");  
1702 - }  
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 - }  
1709 - QPDFObjectHandle obj_to_write = m->pdf.getObject(obj);  
1710 - if (obj_to_write.isStream()) {  
1711 - // This condition occurred in a fuzz input. Ideally we should block it at parse  
1712 - // time, but it's not clear to me how to construct a case for this.  
1713 - obj_to_write.warnIfPossible("stream found inside object stream; treating as null");  
1714 - obj_to_write = QPDFObjectHandle::newNull();  
1715 - }  
1716 - writeObject(obj_to_write, count); 1705 + if (pass == 1) {
  1706 + offsets.push_back(m->pipeline->getCount());
  1707 + // To avoid double-counting objects being written in object streams for progress
  1708 + // reporting, decrement in pass 1.
  1709 + indicateProgress(true, false);
  1710 + }
  1711 + QPDFObjectHandle obj_to_write = m->pdf.getObject(obj);
  1712 + if (obj_to_write.isStream()) {
  1713 + // This condition occurred in a fuzz input. Ideally we should block it at parse
  1714 + // time, but it's not clear to me how to construct a case for this.
  1715 + obj_to_write.warnIfPossible(
  1716 + "stream found inside object stream; treating as null");
  1717 + obj_to_write = QPDFObjectHandle::newNull();
  1718 + }
  1719 + writeObject(obj_to_write, count);
1717 1720
1718 - m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count); 1721 + m->new_obj[new_obj].xref = QPDFXRefEntry(new_stream_id, count);
  1722 + }
1719 } 1723 }
1720 } 1724 }
1721 1725