Commit 613c1221b149d1ef8bd47fd277c8385002c281ff
1 parent
83144b29
Refactor `PipelinePopper` to use `Pl_stack` for improved encapsulation and simpl…
…ify pipeline stack management
Showing
2 changed files
with
90 additions
and
40 deletions
include/qpdf/QPDFWriter.hh
| ... | ... | @@ -569,7 +569,7 @@ class QPDFWriter |
| 569 | 569 | // is popped. |
| 570 | 570 | |
| 571 | 571 | void adjustAESStreamLength(size_t& length); |
| 572 | - void pushEncryptionFilter(PipelinePopper&); | |
| 572 | + PipelinePopper pushEncryptionFilter(); | |
| 573 | 573 | void pushMD5Pipeline(PipelinePopper&); |
| 574 | 574 | void computeDeterministicIDData(); |
| 575 | 575 | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -50,22 +50,52 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) |
| 50 | 50 | handler(progress); |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | -// An reference to a PipelinePopper instance is passed into activatePipelineStack. When the | |
| 54 | -// PipelinePopper goes out of scope, the pipeline stack is popped. PipelinePopper's destructor | |
| 55 | -// calls finish on the current pipeline and pops the pipeline stack until the top of stack is a | |
| 56 | -// previous active top of stack, and restores the pipeline to that point. It deletes any | |
| 57 | -// pipelines that it pops. If the bp argument is non-null and any of the stack items are of type | |
| 58 | -// Pl_Buffer, the buffer is retrieved. | |
| 53 | +namespace | |
| 54 | +{ | |
| 55 | + class Pl_stack; | |
| 56 | +} | |
| 57 | + | |
| 58 | +// A PipelinePopper is normally returned by Pl_stack::activate, or, if necessary, a reference to a | |
| 59 | +// PipelinePopper instance can be passed into activate. When the PipelinePopper goes out of scope, | |
| 60 | +// the pipeline stack is popped. This causes finish to be called on the current pipeline and the | |
| 61 | +// pipeline stack to be popped until the top of stack is a previous active top of stack, and | |
| 62 | +// restores the pipeline to that point. It deletes any pipelines that it pops. | |
| 59 | 63 | class QPDFWriter::PipelinePopper |
| 60 | 64 | { |
| 61 | 65 | public: |
| 62 | - PipelinePopper(QPDFWriter* qw) : | |
| 63 | - qw(qw) | |
| 66 | + PipelinePopper(Pl_stack& stack) : | |
| 67 | + stack(&stack) | |
| 64 | 68 | { |
| 65 | 69 | } |
| 70 | + PipelinePopper() = default; | |
| 71 | + PipelinePopper(PipelinePopper const&) = delete; | |
| 72 | + PipelinePopper(PipelinePopper&& other) noexcept | |
| 73 | + { | |
| 74 | + // For MSVC, default pops the stack | |
| 75 | + if (this != &other) { | |
| 76 | + stack = other.stack; | |
| 77 | + stack_id = other.stack_id; | |
| 78 | + other.stack = nullptr; | |
| 79 | + other.stack_id = 0; | |
| 80 | + }; | |
| 81 | + } | |
| 82 | + PipelinePopper& operator=(PipelinePopper const&) = delete; | |
| 83 | + PipelinePopper& | |
| 84 | + operator=(PipelinePopper&& other) noexcept | |
| 85 | + { | |
| 86 | + // For MSVC, default pops the stack | |
| 87 | + if (this != &other) { | |
| 88 | + stack = other.stack; | |
| 89 | + stack_id = other.stack_id; | |
| 90 | + other.stack = nullptr; | |
| 91 | + other.stack_id = 0; | |
| 92 | + }; | |
| 93 | + return *this; | |
| 94 | + } | |
| 95 | + | |
| 66 | 96 | ~PipelinePopper(); |
| 67 | 97 | |
| 68 | - QPDFWriter* qw{nullptr}; | |
| 98 | + Pl_stack* stack{nullptr}; | |
| 69 | 99 | unsigned long stack_id{0}; |
| 70 | 100 | }; |
| 71 | 101 | |
| ... | ... | @@ -82,6 +112,12 @@ namespace |
| 82 | 112 | { |
| 83 | 113 | } |
| 84 | 114 | |
| 115 | + PP | |
| 116 | + popper() | |
| 117 | + { | |
| 118 | + return {*this}; | |
| 119 | + } | |
| 120 | + | |
| 85 | 121 | void |
| 86 | 122 | initialize(Pipeline* p) |
| 87 | 123 | { |
| ... | ... | @@ -90,6 +126,14 @@ namespace |
| 90 | 126 | stack.emplace_back(top); |
| 91 | 127 | } |
| 92 | 128 | |
| 129 | + PP | |
| 130 | + activate(std::string& str) | |
| 131 | + { | |
| 132 | + PP pp{*this}; | |
| 133 | + activate(pp, str); | |
| 134 | + return pp; | |
| 135 | + } | |
| 136 | + | |
| 93 | 137 | void |
| 94 | 138 | activate(PP& pp, std::string& str) |
| 95 | 139 | { |
| ... | ... | @@ -103,6 +147,17 @@ namespace |
| 103 | 147 | activate(pp, false, &count_buffer, std::move(link)); |
| 104 | 148 | } |
| 105 | 149 | |
| 150 | + PP | |
| 151 | + activate( | |
| 152 | + bool discard = false, | |
| 153 | + std::string* str = nullptr, | |
| 154 | + std::unique_ptr<pl::Link> link = nullptr) | |
| 155 | + { | |
| 156 | + PP pp{*this}; | |
| 157 | + activate(pp, discard, str, std::move(link)); | |
| 158 | + return pp; | |
| 159 | + } | |
| 160 | + | |
| 106 | 161 | void |
| 107 | 162 | activate( |
| 108 | 163 | PP& pp, |
| ... | ... | @@ -178,6 +233,13 @@ namespace |
| 178 | 233 | }; |
| 179 | 234 | } // namespace |
| 180 | 235 | |
| 236 | +QPDFWriter::PipelinePopper::~PipelinePopper() | |
| 237 | +{ | |
| 238 | + if (stack) { | |
| 239 | + stack->pop(stack_id); | |
| 240 | + } | |
| 241 | +} | |
| 242 | + | |
| 181 | 243 | class QPDFWriter::Members |
| 182 | 244 | { |
| 183 | 245 | friend class QPDFWriter; |
| ... | ... | @@ -1014,11 +1076,6 @@ QPDFWriter::write_no_qdf(Args&&... args) |
| 1014 | 1076 | return *this; |
| 1015 | 1077 | } |
| 1016 | 1078 | |
| 1017 | -QPDFWriter::PipelinePopper::~PipelinePopper() | |
| 1018 | -{ | |
| 1019 | - qw->m->pipeline_stack.pop(stack_id); | |
| 1020 | -} | |
| 1021 | - | |
| 1022 | 1079 | void |
| 1023 | 1080 | QPDFWriter::adjustAESStreamLength(size_t& length) |
| 1024 | 1081 | { |
| ... | ... | @@ -1029,9 +1086,10 @@ QPDFWriter::adjustAESStreamLength(size_t& length) |
| 1029 | 1086 | } |
| 1030 | 1087 | } |
| 1031 | 1088 | |
| 1032 | -void | |
| 1033 | -QPDFWriter::pushEncryptionFilter(PipelinePopper& pp) | |
| 1089 | +QPDFWriter::PipelinePopper | |
| 1090 | +QPDFWriter::pushEncryptionFilter() | |
| 1034 | 1091 | { |
| 1092 | + auto pp = m->pipeline_stack.popper(); | |
| 1035 | 1093 | if (m->encryption && !m->cur_data_key.empty()) { |
| 1036 | 1094 | Pipeline* p = nullptr; |
| 1037 | 1095 | if (m->encrypt_use_aes) { |
| ... | ... | @@ -1053,6 +1111,7 @@ QPDFWriter::pushEncryptionFilter(PipelinePopper& pp) |
| 1053 | 1111 | // Must call this unconditionally so we can call popPipelineStack to balance |
| 1054 | 1112 | // pushEncryptionFilter(). |
| 1055 | 1113 | m->pipeline_stack.activate(pp); |
| 1114 | + return pp; | |
| 1056 | 1115 | } |
| 1057 | 1116 | |
| 1058 | 1117 | void |
| ... | ... | @@ -1328,12 +1387,9 @@ QPDFWriter::willFilterStream( |
| 1328 | 1387 | |
| 1329 | 1388 | bool filtered = false; |
| 1330 | 1389 | for (bool first_attempt: {true, false}) { |
| 1331 | - PipelinePopper pp_stream_data(this); | |
| 1332 | - if (stream_data != nullptr) { | |
| 1333 | - m->pipeline_stack.activate(pp_stream_data, *stream_data); | |
| 1334 | - } else { | |
| 1335 | - m->pipeline_stack.activate(pp_stream_data, true); | |
| 1336 | - } | |
| 1390 | + auto pp_stream_data = stream_data ? m->pipeline_stack.activate(*stream_data) | |
| 1391 | + : m->pipeline_stack.activate(true); | |
| 1392 | + | |
| 1337 | 1393 | try { |
| 1338 | 1394 | filtered = stream.pipeStreamData( |
| 1339 | 1395 | m->pipeline, |
| ... | ... | @@ -1593,8 +1649,7 @@ QPDFWriter::unparseObject( |
| 1593 | 1649 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1594 | 1650 | write("\nstream\n"); |
| 1595 | 1651 | { |
| 1596 | - PipelinePopper pp_enc(this); | |
| 1597 | - pushEncryptionFilter(pp_enc); | |
| 1652 | + auto pp_enc = pushEncryptionFilter(); | |
| 1598 | 1653 | write(stream_data); |
| 1599 | 1654 | } |
| 1600 | 1655 | |
| ... | ... | @@ -1683,8 +1738,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1683 | 1738 | const bool compressed = m->compress_streams && !m->qdf_mode; |
| 1684 | 1739 | { |
| 1685 | 1740 | // Pass 1 |
| 1686 | - PipelinePopper pp_ostream_pass1(this); | |
| 1687 | - m->pipeline_stack.activate(pp_ostream_pass1, stream_buffer_pass1); | |
| 1741 | + auto pp_ostream_pass1 = m->pipeline_stack.activate(stream_buffer_pass1); | |
| 1688 | 1742 | |
| 1689 | 1743 | int count = -1; |
| 1690 | 1744 | for (auto const& obj: m->object_stream_to_objects[old_id]) { |
| ... | ... | @@ -1726,7 +1780,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1726 | 1780 | } |
| 1727 | 1781 | } |
| 1728 | 1782 | { |
| 1729 | - PipelinePopper pp_ostream(this); | |
| 1783 | + auto pp_ostream = m->pipeline_stack.popper(); | |
| 1730 | 1784 | // Adjust offsets to skip over comment before first object |
| 1731 | 1785 | first = offsets.at(0); |
| 1732 | 1786 | for (auto& iter: offsets) { |
| ... | ... | @@ -1735,8 +1789,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1735 | 1789 | |
| 1736 | 1790 | // Take one pass at writing pairs of numbers so we can get their size information |
| 1737 | 1791 | { |
| 1738 | - PipelinePopper pp_discard(this); | |
| 1739 | - m->pipeline_stack.activate(pp_discard, true); | |
| 1792 | + auto pp_discard = m->pipeline_stack.activate(true); | |
| 1740 | 1793 | writeObjectStreamOffsets(offsets, first_obj); |
| 1741 | 1794 | first += m->pipeline->getCount(); |
| 1742 | 1795 | } |
| ... | ... | @@ -1782,8 +1835,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1782 | 1835 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); |
| 1783 | 1836 | } |
| 1784 | 1837 | { |
| 1785 | - PipelinePopper pp_enc(this); | |
| 1786 | - pushEncryptionFilter(pp_enc); | |
| 1838 | + auto pp_enc = pushEncryptionFilter(); | |
| 1787 | 1839 | write(stream_buffer_pass2); |
| 1788 | 1840 | } |
| 1789 | 1841 | if (m->newline_before_endstream) { |
| ... | ... | @@ -2405,8 +2457,7 @@ QPDFWriter::writeHintStream(int hint_id) |
| 2405 | 2457 | } |
| 2406 | 2458 | char last_char = hint_buffer.empty() ? '\0' : hint_buffer.back(); |
| 2407 | 2459 | { |
| 2408 | - PipelinePopper pp_enc(this); | |
| 2409 | - pushEncryptionFilter(pp_enc); | |
| 2460 | + auto pp_enc = pushEncryptionFilter(); | |
| 2410 | 2461 | write(hint_buffer); |
| 2411 | 2462 | } |
| 2412 | 2463 | |
| ... | ... | @@ -2504,7 +2555,7 @@ QPDFWriter::writeXRefStream( |
| 2504 | 2555 | std::string xref_data; |
| 2505 | 2556 | const bool compressed = m->compress_streams && !m->qdf_mode; |
| 2506 | 2557 | { |
| 2507 | - PipelinePopper pp_xref(this); | |
| 2558 | + auto pp_xref = m->pipeline_stack.popper(); | |
| 2508 | 2559 | if (compressed) { |
| 2509 | 2560 | m->pipeline_stack.clear_buffer(); |
| 2510 | 2561 | auto link = pl::create<pl::String>(xref_data); |
| ... | ... | @@ -2711,8 +2762,8 @@ QPDFWriter::writeLinearized() |
| 2711 | 2762 | // Write file in two passes. Part numbers refer to PDF spec 1.4. |
| 2712 | 2763 | |
| 2713 | 2764 | FILE* lin_pass1_file = nullptr; |
| 2714 | - auto pp_pass1 = std::make_unique<PipelinePopper>(this); | |
| 2715 | - auto pp_md5 = std::make_unique<PipelinePopper>(this); | |
| 2765 | + auto pp_pass1 = std::make_unique<PipelinePopper>(m->pipeline_stack); | |
| 2766 | + auto pp_md5 = std::make_unique<PipelinePopper>(m->pipeline_stack); | |
| 2716 | 2767 | for (int pass: {1, 2}) { |
| 2717 | 2768 | if (pass == 1) { |
| 2718 | 2769 | if (!m->lin_pass1_filename.empty()) { |
| ... | ... | @@ -2911,8 +2962,7 @@ QPDFWriter::writeLinearized() |
| 2911 | 2962 | |
| 2912 | 2963 | // Write hint stream to a buffer |
| 2913 | 2964 | { |
| 2914 | - PipelinePopper pp_hint(this); | |
| 2915 | - m->pipeline_stack.activate(pp_hint, hint_buffer); | |
| 2965 | + auto pp_hint = m->pipeline_stack.activate(hint_buffer); | |
| 2916 | 2966 | writeHintStream(hint_id); |
| 2917 | 2967 | } |
| 2918 | 2968 | hint_length = QIntC::to_offset(hint_buffer.size()); |
| ... | ... | @@ -3030,7 +3080,7 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) |
| 3030 | 3080 | void |
| 3031 | 3081 | QPDFWriter::writeStandard() |
| 3032 | 3082 | { |
| 3033 | - auto pp_md5 = PipelinePopper(this); | |
| 3083 | + auto pp_md5 = m->pipeline_stack.popper(); | |
| 3034 | 3084 | if (m->deterministic_id) { |
| 3035 | 3085 | pushMD5Pipeline(pp_md5); |
| 3036 | 3086 | } | ... | ... |