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,6 +466,7 @@ class QPDFWriter | ||
| 466 | QPDFWriter& write(std::integral auto val); | 466 | QPDFWriter& write(std::integral auto val); |
| 467 | QPDFWriter& write_name(std::string const& str); | 467 | QPDFWriter& write_name(std::string const& str); |
| 468 | QPDFWriter& write_string(std::string const& str, bool force_binary = false); | 468 | QPDFWriter& write_string(std::string const& str, bool force_binary = false); |
| 469 | + QPDFWriter& write_encrypted(std::string_view str); | ||
| 469 | 470 | ||
| 470 | template <typename... Args> | 471 | template <typename... Args> |
| 471 | QPDFWriter& write_qdf(Args&&... args); | 472 | QPDFWriter& write_qdf(Args&&... args); |
| @@ -569,7 +570,6 @@ class QPDFWriter | @@ -569,7 +570,6 @@ class QPDFWriter | ||
| 569 | // is popped. | 570 | // is popped. |
| 570 | 571 | ||
| 571 | void adjustAESStreamLength(size_t& length); | 572 | void adjustAESStreamLength(size_t& length); |
| 572 | - PipelinePopper pushEncryptionFilter(); | ||
| 573 | void pushMD5Pipeline(PipelinePopper&); | 573 | void pushMD5Pipeline(PipelinePopper&); |
| 574 | void computeDeterministicIDData(); | 574 | void computeDeterministicIDData(); |
| 575 | 575 |
libqpdf/QPDFWriter.cc
| @@ -1098,32 +1098,27 @@ QPDFWriter::adjustAESStreamLength(size_t& length) | @@ -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 | true, | 1110 | true, |
| 1112 | QUtil::unsigned_char_pointer(m->cur_data_key), | 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 | QUtil::unsigned_char_pointer(m->cur_data_key), | 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 | void | 1124 | void |
| @@ -1659,18 +1654,9 @@ QPDFWriter::unparseObject( | @@ -1659,18 +1654,9 @@ QPDFWriter::unparseObject( | ||
| 1659 | adjustAESStreamLength(m->cur_stream_length); | 1654 | adjustAESStreamLength(m->cur_stream_length); |
| 1660 | unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); | 1655 | unparseObject(stream_dict, 0, flags, m->cur_stream_length, compress_stream); |
| 1661 | char last_char = stream_data.empty() ? '\0' : stream_data.back(); | 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 | } else if (tc == ::ot_string) { | 1660 | } else if (tc == ::ot_string) { |
| 1675 | std::string val; | 1661 | std::string val; |
| 1676 | if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && | 1662 | if (m->encryption && !(flags & f_in_ostream) && !(flags & f_no_encryption) && |
| @@ -1842,18 +1828,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | @@ -1842,18 +1828,11 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object) | ||
| 1842 | unparseChild(extends, 1, f_in_ostream); | 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 | if (m->encryption) { | 1832 | if (m->encryption) { |
| 1847 | QTC::TC("qpdf", "QPDFWriter encrypt object stream"); | 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 | m->cur_data_key.clear(); | 1836 | m->cur_data_key.clear(); |
| 1858 | closeObject(new_stream_id); | 1837 | closeObject(new_stream_id); |
| 1859 | } | 1838 | } |
| @@ -2462,21 +2441,13 @@ QPDFWriter::writeHintStream(int hint_id) | @@ -2462,21 +2441,13 @@ QPDFWriter::writeHintStream(int hint_id) | ||
| 2462 | } | 2441 | } |
| 2463 | adjustAESStreamLength(hlen); | 2442 | adjustAESStreamLength(hlen); |
| 2464 | write(" /Length ").write(hlen); | 2443 | write(" /Length ").write(hlen); |
| 2465 | - write(" >>\nstream\n"); | 2444 | + write(" >>\nstream\n").write_encrypted(hint_buffer); |
| 2466 | 2445 | ||
| 2467 | if (m->encryption) { | 2446 | if (m->encryption) { |
| 2468 | QTC::TC("qpdf", "QPDFWriter encrypted hint stream"); | 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 | closeObject(hint_id); | 2451 | closeObject(hint_id); |
| 2481 | } | 2452 | } |
| 2482 | 2453 |
libqpdf/qpdf/Pipeline_private.hh
| @@ -173,6 +173,18 @@ namespace qpdf::pl | @@ -173,6 +173,18 @@ namespace qpdf::pl | ||
| 173 | unsigned long id_{0}; | 173 | unsigned long id_{0}; |
| 174 | bool pass_immediately_to_next{false}; | 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 | } // namespace qpdf::pl | 188 | } // namespace qpdf::pl |
| 177 | 189 | ||
| 178 | #endif // PIPELINE_PRIVATE_HH | 190 | #endif // PIPELINE_PRIVATE_HH |