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 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  
... ...