Commit 46cb7392732451e7ba12a8e1a7d30c4cb1014ac0
1 parent
a78d18f7
Refactor `QPDFWriter` encryption logic to simplify pipeline writes and consolida…
…te encryption handling
Showing
3 changed files
with
37 additions
and
54 deletions
include/qpdf/QPDFWriter.hh
| ... | ... | @@ -466,6 +466,7 @@ class QPDFWriter |
| 466 | 466 | QPDFWriter& write(std::integral auto val); |
| 467 | 467 | QPDFWriter& write_name(std::string const& str); |
| 468 | 468 | QPDFWriter& write_string(std::string const& str, bool force_binary = false); |
| 469 | + QPDFWriter& write_encrypted(std::string_view str); | |
| 469 | 470 | |
| 470 | 471 | template <typename... Args> |
| 471 | 472 | QPDFWriter& write_qdf(Args&&... args); |
| ... | ... | @@ -569,7 +570,6 @@ class QPDFWriter |
| 569 | 570 | // is popped. |
| 570 | 571 | |
| 571 | 572 | void adjustAESStreamLength(size_t& length); |
| 572 | - PipelinePopper pushEncryptionFilter(); | |
| 573 | 573 | void pushMD5Pipeline(PipelinePopper&); |
| 574 | 574 | void computeDeterministicIDData(); |
| 575 | 575 | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -1098,32 +1098,27 @@ QPDFWriter::adjustAESStreamLength(size_t& length) |
| 1098 | 1098 | } |
| 1099 | 1099 | } |
| 1100 | 1100 | |
| 1101 | -QPDFWriter::PipelinePopper | |
| 1102 | -QPDFWriter::pushEncryptionFilter() | |
| 1103 | -{ | |
| 1104 | - auto pp = m->pipeline_stack.popper(); | |
| 1105 | - if (m->encryption && !m->cur_data_key.empty()) { | |
| 1106 | - Pipeline* p = nullptr; | |
| 1107 | - if (m->encrypt_use_aes) { | |
| 1108 | - p = new Pl_AES_PDF( | |
| 1109 | - "aes stream encryption", | |
| 1110 | - m->pipeline, | |
| 1101 | +QPDFWriter& | |
| 1102 | +QPDFWriter::write_encrypted(std::string_view str) | |
| 1103 | +{ | |
| 1104 | + if (!(m->encryption && !m->cur_data_key.empty())) { | |
| 1105 | + write(str); | |
| 1106 | + } else if (m->encrypt_use_aes) { | |
| 1107 | + write( | |
| 1108 | + pl::pipe<Pl_AES_PDF>( | |
| 1109 | + str, | |
| 1111 | 1110 | true, |
| 1112 | 1111 | QUtil::unsigned_char_pointer(m->cur_data_key), |
| 1113 | - m->cur_data_key.length()); | |
| 1114 | - } else { | |
| 1115 | - p = new Pl_RC4( | |
| 1116 | - "rc4 stream encryption", | |
| 1117 | - m->pipeline, | |
| 1112 | + m->cur_data_key.length())); | |
| 1113 | + } else { | |
| 1114 | + write( | |
| 1115 | + pl::pipe<Pl_RC4>( | |
| 1116 | + str, | |
| 1118 | 1117 | QUtil::unsigned_char_pointer(m->cur_data_key), |
| 1119 | - QIntC::to_int(m->cur_data_key.length())); | |
| 1120 | - } | |
| 1121 | - m->pipeline_stack.push(p); | |
| 1118 | + QIntC::to_int(m->cur_data_key.length()))); | |
| 1122 | 1119 | } |
| 1123 | - // Must call this unconditionally so we can call popPipelineStack to balance | |
| 1124 | - // pushEncryptionFilter(). | |
| 1125 | - m->pipeline_stack.activate(pp); | |
| 1126 | - return pp; | |
| 1120 | + | |
| 1121 | + return *this; | |
| 1127 | 1122 | } |
| 1128 | 1123 | |
| 1129 | 1124 | void |
| ... | ... | @@ -1659,18 +1654,9 @@ QPDFWriter::unparseObject( |
| 1659 | 1654 | adjustAESStreamLength(m->cur_stream_length); |
| 1660 | 1655 | unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); |
| 1661 | 1656 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); |
| 1662 | - write("\nstream\n"); | |
| 1663 | - { | |
| 1664 | - auto pp_enc = pushEncryptionFilter(); | |
| 1665 | - write(stream_data); | |
| 1666 | - } | |
| 1667 | - | |
| 1668 | - if ((m->added_newline = | |
| 1669 | - m->newline_before_endstream || (m->qdf_mode && last_char != '\n'))) { | |
| 1670 | - write("\nendstream"); | |
| 1671 | - } else { | |
| 1672 | - write("endstream"); | |
| 1673 | - } | |
| 1657 | + write("\nstream\n").write_encrypted(stream_data); | |
| 1658 | + m->added_newline = m->newline_before_endstream || (m->qdf_mode && last_char != '\n'); | |
| 1659 | + write(m->added_newline ? "\nendstream" : "endstream"); | |
| 1674 | 1660 | } else if (tc == ::ot_string) { |
| 1675 | 1661 | std::string val; |
| 1676 | 1662 | if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && |
| ... | ... | @@ -1842,18 +1828,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) |
| 1842 | 1828 | unparseChild(extends, 1, f_in_ostream); |
| 1843 | 1829 | } |
| 1844 | 1830 | } |
| 1845 | - write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n"); | |
| 1831 | + write_qdf("\n").write_no_qdf(" ").write(">>\nstream\n").write_encrypted(stream_buffer_pass2); | |
| 1846 | 1832 | if (m->encryption) { |
| 1847 | 1833 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); |
| 1848 | 1834 | } |
| 1849 | - { | |
| 1850 | - auto pp_enc = pushEncryptionFilter(); | |
| 1851 | - write(stream_buffer_pass2); | |
| 1852 | - } | |
| 1853 | - if (m->newline_before_endstream) { | |
| 1854 | - write("\n"); | |
| 1855 | - } | |
| 1856 | - write("endstream"); | |
| 1835 | + write(m->newline_before_endstream ? "\nendstream" : "endstream"); | |
| 1857 | 1836 | m->cur_data_key.clear(); |
| 1858 | 1837 | closeObject(new_stream_id); |
| 1859 | 1838 | } |
| ... | ... | @@ -2462,21 +2441,13 @@ QPDFWriter::writeHintStream(int hint_id) |
| 2462 | 2441 | } |
| 2463 | 2442 | adjustAESStreamLength(hlen); |
| 2464 | 2443 | write(" /Length ").write(hlen); |
| 2465 | - write(" >>\nstream\n"); | |
| 2444 | + write(" >>\nstream\n").write_encrypted(hint_buffer); | |
| 2466 | 2445 | |
| 2467 | 2446 | if (m->encryption) { |
| 2468 | 2447 | QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); |
| 2469 | 2448 | } |
| 2470 | - char last_char = hint_buffer.empty() ? '\0' : hint_buffer.back(); | |
| 2471 | - { | |
| 2472 | - auto pp_enc = pushEncryptionFilter(); | |
| 2473 | - write(hint_buffer); | |
| 2474 | - } | |
| 2475 | 2449 | |
| 2476 | - if (last_char != '\n') { | |
| 2477 | - write("\n"); | |
| 2478 | - } | |
| 2479 | - write("endstream"); | |
| 2450 | + write(hint_buffer.empty() || hint_buffer.back() != '\n' ? "\nendstream" : "endstream"); | |
| 2480 | 2451 | closeObject(hint_id); |
| 2481 | 2452 | } |
| 2482 | 2453 | ... | ... |
libqpdf/qpdf/Pipeline_private.hh
| ... | ... | @@ -173,6 +173,18 @@ namespace qpdf::pl |
| 173 | 173 | unsigned long id_{0}; |
| 174 | 174 | bool pass_immediately_to_next{false}; |
| 175 | 175 | }; |
| 176 | + | |
| 177 | + template <typename P, typename... Args> | |
| 178 | + std::string | |
| 179 | + pipe(std::string_view data, Args&&... args) | |
| 180 | + { | |
| 181 | + std::string result; | |
| 182 | + String s("", nullptr, result); | |
| 183 | + P pl("", &s, std::forward<Args>(args)...); | |
| 184 | + pl.write(reinterpret_cast<unsigned char const*>(data.data()), data.size()); | |
| 185 | + pl.finish(); | |
| 186 | + return result; | |
| 187 | + } | |
| 176 | 188 | } // namespace qpdf::pl |
| 177 | 189 | |
| 178 | 190 | #endif // PIPELINE_PRIVATE_HH | ... | ... |