Commit 403dbd5f5bf61c989faee4e4038d13af2f4e9931
1 parent
d207f615
Refactor stream copying: simplify `replaceStreamData` logic and remove redundant…
… `StreamDataProvider` management.
Showing
5 changed files
with
41 additions
and
45 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -680,65 +680,56 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop |
| 680 | 680 | } |
| 681 | 681 | |
| 682 | 682 | void |
| 683 | -QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | |
| 683 | +QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign_oh) | |
| 684 | 684 | { |
| 685 | 685 | // This method was originally written for copying foreign streams, but it is used by |
| 686 | - // QPDFObjectHandle to copy streams from the same QPDF object as well. | |
| 687 | - | |
| 688 | - QPDFObjectHandle dict = result.getDict(); | |
| 689 | - QPDFObjectHandle old_dict = foreign.getDict(); | |
| 690 | - if (m->copied_stream_data_provider == nullptr) { | |
| 691 | - m->copied_stream_data_provider = new CopiedStreamDataProvider(*this); | |
| 692 | - m->copied_streams = | |
| 693 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider>(m->copied_stream_data_provider); | |
| 686 | + // Stream::copy to copy streams from the same QPDF object as well. | |
| 687 | + | |
| 688 | + Dictionary dict = result.getDict(); | |
| 689 | + Dictionary old_dict = foreign_oh.getDict(); | |
| 690 | + if (!m->copied_stream_data_provider) { | |
| 691 | + m->copied_stream_data_provider = std::make_shared<CopiedStreamDataProvider>(*this); | |
| 694 | 692 | } |
| 695 | 693 | QPDFObjGen local_og(result.getObjGen()); |
| 696 | 694 | // Copy information from the foreign stream so we can pipe its data later without keeping the |
| 697 | 695 | // original QPDF object around. |
| 698 | 696 | |
| 699 | 697 | QPDF& foreign_stream_qpdf = |
| 700 | - foreign.getQPDF("unable to retrieve owning qpdf from foreign stream"); | |
| 698 | + foreign_oh.getQPDF("unable to retrieve owning qpdf from foreign stream"); | |
| 701 | 699 | |
| 702 | - auto stream = foreign.as_stream(); | |
| 703 | - if (!stream) { | |
| 700 | + Stream foreign = foreign_oh; | |
| 701 | + if (!foreign) { | |
| 704 | 702 | throw std::logic_error("unable to retrieve underlying stream object from foreign stream"); |
| 705 | 703 | } |
| 706 | - std::shared_ptr<Buffer> stream_buffer = stream.getStreamDataBuffer(); | |
| 707 | - if ((foreign_stream_qpdf.m->immediate_copy_from) && (stream_buffer == nullptr)) { | |
| 704 | + std::shared_ptr<Buffer> stream_buffer = foreign.getStreamDataBuffer(); | |
| 705 | + if (foreign_stream_qpdf.m->immediate_copy_from && !stream_buffer) { | |
| 708 | 706 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the |
| 709 | 707 | // source stream so that if the source stream is copied multiple times, we don't have to |
| 710 | 708 | // keep duplicating the memory. |
| 711 | - QTC::TC("qpdf", "QPDF immediate copy stream data"); | |
| 712 | 709 | foreign.replaceStreamData( |
| 713 | - foreign.getRawStreamData(), | |
| 714 | - old_dict.getKey("/Filter"), | |
| 715 | - old_dict.getKey("/DecodeParms")); | |
| 716 | - stream_buffer = stream.getStreamDataBuffer(); | |
| 710 | + foreign.getRawStreamData(), old_dict["/Filter"], old_dict["/DecodeParms"]); | |
| 711 | + stream_buffer = foreign.getStreamDataBuffer(); | |
| 717 | 712 | } |
| 718 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider = | |
| 719 | - stream.getStreamDataProvider(); | |
| 720 | - if (stream_buffer.get()) { | |
| 721 | - QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); | |
| 722 | - result.replaceStreamData( | |
| 723 | - stream_buffer, dict.getKey("/Filter"), dict.getKey("/DecodeParms")); | |
| 724 | - } else if (stream_provider.get()) { | |
| 713 | + auto stream_provider = foreign.getStreamDataProvider(); | |
| 714 | + if (stream_buffer) { | |
| 715 | + result.replaceStreamData(stream_buffer, dict["/Filter"], dict["/DecodeParms"]); | |
| 716 | + } else if (stream_provider) { | |
| 725 | 717 | // In this case, the remote stream's QPDF must stay in scope. |
| 726 | - QTC::TC("qpdf", "QPDF copy foreign stream with provider"); | |
| 727 | - m->copied_stream_data_provider->registerForeignStream(local_og, foreign); | |
| 718 | + m->copied_stream_data_provider->registerForeignStream(local_og, foreign_oh); | |
| 728 | 719 | result.replaceStreamData( |
| 729 | - m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms")); | |
| 720 | + m->copied_stream_data_provider, dict["/Filter"], dict["/DecodeParms"]); | |
| 730 | 721 | } else { |
| 731 | 722 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( |
| 732 | 723 | foreign_stream_qpdf.m->encp, |
| 733 | 724 | foreign_stream_qpdf.m->file, |
| 734 | 725 | foreign, |
| 735 | 726 | foreign.offset(), |
| 736 | - stream.getLength(), | |
| 727 | + foreign.getLength(), | |
| 737 | 728 | dict, |
| 738 | - stream.isRootMetadata()); | |
| 729 | + foreign.isRootMetadata()); | |
| 739 | 730 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); |
| 740 | 731 | result.replaceStreamData( |
| 741 | - m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms")); | |
| 732 | + m->copied_stream_data_provider, dict["/Filter"], dict["/DecodeParms"]); | |
| 742 | 733 | } |
| 743 | 734 | } |
| 744 | 735 | ... | ... |
libqpdf/QPDF_Stream.cc
| ... | ... | @@ -628,6 +628,16 @@ Stream::pipeStreamData( |
| 628 | 628 | |
| 629 | 629 | void |
| 630 | 630 | Stream::replaceStreamData( |
| 631 | + std::string&& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) | |
| 632 | +{ | |
| 633 | + auto s = stream(); | |
| 634 | + s->stream_data = std::make_shared<Buffer>(std::move(data)); | |
| 635 | + s->stream_provider = nullptr; | |
| 636 | + replaceFilterData(filter, decode_parms, s->stream_data->getSize()); | |
| 637 | +} | |
| 638 | + | |
| 639 | +void | |
| 640 | +Stream::replaceStreamData( | |
| 631 | 641 | std::shared_ptr<Buffer> data, |
| 632 | 642 | QPDFObjectHandle const& filter, |
| 633 | 643 | QPDFObjectHandle const& decode_parms) |
| ... | ... | @@ -635,7 +645,7 @@ Stream::replaceStreamData( |
| 635 | 645 | auto s = stream(); |
| 636 | 646 | s->stream_data = data; |
| 637 | 647 | s->stream_provider = nullptr; |
| 638 | - replaceFilterData(filter, decode_parms, data->getSize()); | |
| 648 | + replaceFilterData(filter, decode_parms, data->size()); | |
| 639 | 649 | } |
| 640 | 650 | |
| 641 | 651 | void |
| ... | ... | @@ -781,12 +791,8 @@ void |
| 781 | 791 | QPDFObjectHandle::replaceStreamData( |
| 782 | 792 | std::string const& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) |
| 783 | 793 | { |
| 784 | - auto b = std::make_shared<Buffer>(data.length()); | |
| 785 | - unsigned char* bp = b->getBuffer(); | |
| 786 | - if (bp) { | |
| 787 | - memcpy(bp, data.c_str(), data.length()); | |
| 788 | - } | |
| 789 | - as_stream(error).replaceStreamData(b, filter, decode_parms); | |
| 794 | + std::string s(data); | |
| 795 | + as_stream(error).replaceStreamData(std::move(s), filter, decode_parms); | |
| 790 | 796 | } |
| 791 | 797 | |
| 792 | 798 | void | ... | ... |
libqpdf/qpdf/QPDFObjectHandle_private.hh
| ... | ... | @@ -520,6 +520,10 @@ namespace qpdf |
| 520 | 520 | std::string getStreamData(qpdf_stream_decode_level_e level); |
| 521 | 521 | std::string getRawStreamData(); |
| 522 | 522 | void replaceStreamData( |
| 523 | + std::string&& data, | |
| 524 | + QPDFObjectHandle const& filter, | |
| 525 | + QPDFObjectHandle const& decode_parms); | |
| 526 | + void replaceStreamData( | |
| 523 | 527 | std::shared_ptr<Buffer> data, |
| 524 | 528 | QPDFObjectHandle const& filter, |
| 525 | 529 | QPDFObjectHandle const& decode_parms); | ... | ... |
libqpdf/qpdf/QPDF_private.hh
| ... | ... | @@ -846,9 +846,7 @@ class QPDF::Members |
| 846 | 846 | bool ever_called_get_all_pages{false}; |
| 847 | 847 | std::vector<QPDFExc> warnings; |
| 848 | 848 | std::map<unsigned long long, ObjCopier> object_copiers; |
| 849 | - std::shared_ptr<QPDFObjectHandle::StreamDataProvider> copied_streams; | |
| 850 | - // copied_stream_data_provider is owned by copied_streams | |
| 851 | - CopiedStreamDataProvider* copied_stream_data_provider{nullptr}; | |
| 849 | + std::shared_ptr<CopiedStreamDataProvider> copied_stream_data_provider; | |
| 852 | 850 | bool reconstructed_xref{false}; |
| 853 | 851 | bool in_read_xref_stream{false}; |
| 854 | 852 | bool fixed_dangling_refs{false}; | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -252,9 +252,6 @@ QPDFJob image optimize no pipeline 0 |
| 252 | 252 | QPDFJob image optimize no shrink 0 |
| 253 | 253 | QPDFJob image optimize too small 0 |
| 254 | 254 | QPDF pipe foreign encrypted stream 0 |
| 255 | -QPDF copy foreign stream with provider 0 | |
| 256 | -QPDF copy foreign stream with buffer 0 | |
| 257 | -QPDF immediate copy stream data 0 | |
| 258 | 255 | QPDFJob copy same page more than once 1 |
| 259 | 256 | QPDFPageObjectHelper bad token finding names 0 |
| 260 | 257 | QPDFJob password mode bytes 0 | ... | ... |