Commit ae9e65f3ebce92342011e70b70920df52bb41152
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 | 1646 | std::shared_ptr<Buffer> stream_buffer; |
| 1647 | 1647 | int first_obj = -1; |
| 1648 | 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 | 1650 | PipelinePopper pp_ostream(this, &stream_buffer); |
| 1652 | 1651 | if (pass == 1) { |
| 1653 | - pushDiscardFilter(pp_ostream); | |
| 1652 | + pushPipeline(new Pl_Buffer("object stream")); | |
| 1653 | + activatePipelineStack(pp_ostream); | |
| 1654 | 1654 | } else { |
| 1655 | 1655 | // Adjust offsets to skip over comment before first object |
| 1656 | 1656 | first = offsets.at(0); |
| ... | ... | @@ -1675,47 +1675,51 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1675 | 1675 | } |
| 1676 | 1676 | activatePipelineStack(pp_ostream); |
| 1677 | 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 | ... | ... |