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,7 +569,7 @@ class QPDFWriter | ||
| 569 | // is popped. | 569 | // is popped. |
| 570 | 570 | ||
| 571 | void adjustAESStreamLength(size_t& length); | 571 | void adjustAESStreamLength(size_t& length); |
| 572 | - void pushEncryptionFilter(PipelinePopper&); | 572 | + PipelinePopper pushEncryptionFilter(); |
| 573 | void pushMD5Pipeline(PipelinePopper&); | 573 | void pushMD5Pipeline(PipelinePopper&); |
| 574 | void computeDeterministicIDData(); | 574 | void computeDeterministicIDData(); |
| 575 | 575 |
libqpdf/QPDFWriter.cc
| @@ -50,22 +50,52 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) | @@ -50,22 +50,52 @@ QPDFWriter::FunctionProgressReporter::reportProgress(int progress) | ||
| 50 | handler(progress); | 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 | class QPDFWriter::PipelinePopper | 63 | class QPDFWriter::PipelinePopper |
| 60 | { | 64 | { |
| 61 | public: | 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 | ~PipelinePopper(); | 96 | ~PipelinePopper(); |
| 67 | 97 | ||
| 68 | - QPDFWriter* qw{nullptr}; | 98 | + Pl_stack* stack{nullptr}; |
| 69 | unsigned long stack_id{0}; | 99 | unsigned long stack_id{0}; |
| 70 | }; | 100 | }; |
| 71 | 101 | ||
| @@ -82,6 +112,12 @@ namespace | @@ -82,6 +112,12 @@ namespace | ||
| 82 | { | 112 | { |
| 83 | } | 113 | } |
| 84 | 114 | ||
| 115 | + PP | ||
| 116 | + popper() | ||
| 117 | + { | ||
| 118 | + return {*this}; | ||
| 119 | + } | ||
| 120 | + | ||
| 85 | void | 121 | void |
| 86 | initialize(Pipeline* p) | 122 | initialize(Pipeline* p) |
| 87 | { | 123 | { |
| @@ -90,6 +126,14 @@ namespace | @@ -90,6 +126,14 @@ namespace | ||
| 90 | stack.emplace_back(top); | 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 | void | 137 | void |
| 94 | activate(PP& pp, std::string& str) | 138 | activate(PP& pp, std::string& str) |
| 95 | { | 139 | { |
| @@ -103,6 +147,17 @@ namespace | @@ -103,6 +147,17 @@ namespace | ||
| 103 | activate(pp, false, &count_buffer, std::move(link)); | 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 | void | 161 | void |
| 107 | activate( | 162 | activate( |
| 108 | PP& pp, | 163 | PP& pp, |
| @@ -178,6 +233,13 @@ namespace | @@ -178,6 +233,13 @@ namespace | ||
| 178 | }; | 233 | }; |
| 179 | } // namespace | 234 | } // namespace |
| 180 | 235 | ||
| 236 | +QPDFWriter::PipelinePopper::~PipelinePopper() | ||
| 237 | +{ | ||
| 238 | + if (stack) { | ||
| 239 | + stack->pop(stack_id); | ||
| 240 | + } | ||
| 241 | +} | ||
| 242 | + | ||
| 181 | class QPDFWriter::Members | 243 | class QPDFWriter::Members |
| 182 | { | 244 | { |
| 183 | friend class QPDFWriter; | 245 | friend class QPDFWriter; |
| @@ -1014,11 +1076,6 @@ QPDFWriter::write_no_qdf(Args&&... args) | @@ -1014,11 +1076,6 @@ QPDFWriter::write_no_qdf(Args&&... args) | ||
| 1014 | return *this; | 1076 | return *this; |
| 1015 | } | 1077 | } |
| 1016 | 1078 | ||
| 1017 | -QPDFWriter::PipelinePopper::~PipelinePopper() | ||
| 1018 | -{ | ||
| 1019 | - qw->m->pipeline_stack.pop(stack_id); | ||
| 1020 | -} | ||
| 1021 | - | ||
| 1022 | void | 1079 | void |
| 1023 | QPDFWriter::adjustAESStreamLength(size_t& length) | 1080 | QPDFWriter::adjustAESStreamLength(size_t& length) |
| 1024 | { | 1081 | { |
| @@ -1029,9 +1086,10 @@ QPDFWriter::adjustAESStreamLength(size_t& length) | @@ -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 | if (m->encryption && !m->cur_data_key.empty()) { | 1093 | if (m->encryption && !m->cur_data_key.empty()) { |
| 1036 | Pipeline* p = nullptr; | 1094 | Pipeline* p = nullptr; |
| 1037 | if (m->encrypt_use_aes) { | 1095 | if (m->encrypt_use_aes) { |
| @@ -1053,6 +1111,7 @@ QPDFWriter::pushEncryptionFilter(PipelinePopper& pp) | @@ -1053,6 +1111,7 @@ QPDFWriter::pushEncryptionFilter(PipelinePopper& pp) | ||
| 1053 | // Must call this unconditionally so we can call popPipelineStack to balance | 1111 | // Must call this unconditionally so we can call popPipelineStack to balance |
| 1054 | // pushEncryptionFilter(). | 1112 | // pushEncryptionFilter(). |
| 1055 | m->pipeline_stack.activate(pp); | 1113 | m->pipeline_stack.activate(pp); |
| 1114 | + return pp; | ||
| 1056 | } | 1115 | } |
| 1057 | 1116 | ||
| 1058 | void | 1117 | void |
| @@ -1328,12 +1387,9 @@ QPDFWriter::willFilterStream( | @@ -1328,12 +1387,9 @@ QPDFWriter::willFilterStream( | ||
| 1328 | 1387 | ||
| 1329 | bool filtered = false; | 1388 | bool filtered = false; |
| 1330 | for (bool first_attempt: {true, false}) { | 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 | try { | 1393 | try { |
| 1338 | filtered = stream.pipeStreamData( | 1394 | filtered = stream.pipeStreamData( |
| 1339 | m->pipeline, | 1395 | m->pipeline, |
| @@ -1593,8 +1649,7 @@ QPDFWriter::unparseObject( | @@ -1593,8 +1649,7 @@ QPDFWriter::unparseObject( | ||
| 1593 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); | 1649 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1594 | write("\nstream\n"); | 1650 | write("\nstream\n"); |
| 1595 | { | 1651 | { |
| 1596 | - PipelinePopper pp_enc(this); | ||
| 1597 | - pushEncryptionFilter(pp_enc); | 1652 | + auto pp_enc = pushEncryptionFilter(); |
| 1598 | write(stream_data); | 1653 | write(stream_data); |
| 1599 | } | 1654 | } |
| 1600 | 1655 | ||
| @@ -1683,8 +1738,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1683,8 +1738,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1683 | const bool compressed = m->compress_streams && !m->qdf_mode; | 1738 | const bool compressed = m->compress_streams && !m->qdf_mode; |
| 1684 | { | 1739 | { |
| 1685 | // Pass 1 | 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 | int count = -1; | 1743 | int count = -1; |
| 1690 | for (auto const& obj: m->object_stream_to_objects[old_id]) { | 1744 | for (auto const& obj: m->object_stream_to_objects[old_id]) { |
| @@ -1726,7 +1780,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -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 | // Adjust offsets to skip over comment before first object | 1784 | // Adjust offsets to skip over comment before first object |
| 1731 | first = offsets.at(0); | 1785 | first = offsets.at(0); |
| 1732 | for (auto& iter: offsets) { | 1786 | for (auto& iter: offsets) { |
| @@ -1735,8 +1789,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1735,8 +1789,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1735 | 1789 | ||
| 1736 | // Take one pass at writing pairs of numbers so we can get their size information | 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 | writeObjectStreamOffsets(offsets, first_obj); | 1793 | writeObjectStreamOffsets(offsets, first_obj); |
| 1741 | first += m->pipeline->getCount(); | 1794 | first += m->pipeline->getCount(); |
| 1742 | } | 1795 | } |
| @@ -1782,8 +1835,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1782,8 +1835,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1782 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); | 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 | write(stream_buffer_pass2); | 1839 | write(stream_buffer_pass2); |
| 1788 | } | 1840 | } |
| 1789 | if (m->newline_before_endstream) { | 1841 | if (m->newline_before_endstream) { |
| @@ -2405,8 +2457,7 @@ QPDFWriter::writeHintStream(int hint_id) | @@ -2405,8 +2457,7 @@ QPDFWriter::writeHintStream(int hint_id) | ||
| 2405 | } | 2457 | } |
| 2406 | char last_char = hint_buffer.empty() ? '\0' : hint_buffer.back(); | 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 | write(hint_buffer); | 2461 | write(hint_buffer); |
| 2411 | } | 2462 | } |
| 2412 | 2463 | ||
| @@ -2504,7 +2555,7 @@ QPDFWriter::writeXRefStream( | @@ -2504,7 +2555,7 @@ QPDFWriter::writeXRefStream( | ||
| 2504 | std::string xref_data; | 2555 | std::string xref_data; |
| 2505 | const bool compressed = m->compress_streams && !m->qdf_mode; | 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 | if (compressed) { | 2559 | if (compressed) { |
| 2509 | m->pipeline_stack.clear_buffer(); | 2560 | m->pipeline_stack.clear_buffer(); |
| 2510 | auto link = pl::create<pl::String>(xref_data); | 2561 | auto link = pl::create<pl::String>(xref_data); |
| @@ -2711,8 +2762,8 @@ QPDFWriter::writeLinearized() | @@ -2711,8 +2762,8 @@ QPDFWriter::writeLinearized() | ||
| 2711 | // Write file in two passes. Part numbers refer to PDF spec 1.4. | 2762 | // Write file in two passes. Part numbers refer to PDF spec 1.4. |
| 2712 | 2763 | ||
| 2713 | FILE* lin_pass1_file = nullptr; | 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 | for (int pass: {1, 2}) { | 2767 | for (int pass: {1, 2}) { |
| 2717 | if (pass == 1) { | 2768 | if (pass == 1) { |
| 2718 | if (!m->lin_pass1_filename.empty()) { | 2769 | if (!m->lin_pass1_filename.empty()) { |
| @@ -2911,8 +2962,7 @@ QPDFWriter::writeLinearized() | @@ -2911,8 +2962,7 @@ QPDFWriter::writeLinearized() | ||
| 2911 | 2962 | ||
| 2912 | // Write hint stream to a buffer | 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 | writeHintStream(hint_id); | 2966 | writeHintStream(hint_id); |
| 2917 | } | 2967 | } |
| 2918 | hint_length = QIntC::to_offset(hint_buffer.size()); | 2968 | hint_length = QIntC::to_offset(hint_buffer.size()); |
| @@ -3030,7 +3080,7 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | @@ -3030,7 +3080,7 @@ QPDFWriter::registerProgressReporter(std::shared_ptr<ProgressReporter> pr) | ||
| 3030 | void | 3080 | void |
| 3031 | QPDFWriter::writeStandard() | 3081 | QPDFWriter::writeStandard() |
| 3032 | { | 3082 | { |
| 3033 | - auto pp_md5 = PipelinePopper(this); | 3083 | + auto pp_md5 = m->pipeline_stack.popper(); |
| 3034 | if (m->deterministic_id) { | 3084 | if (m->deterministic_id) { |
| 3035 | pushMD5Pipeline(pp_md5); | 3085 | pushMD5Pipeline(pp_md5); |
| 3036 | } | 3086 | } |