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,65 +680,56 @@ QPDF::replaceForeignIndirectObjects(QPDFObjectHandle foreign, ObjCopier& obj_cop | ||
| 680 | } | 680 | } |
| 681 | 681 | ||
| 682 | void | 682 | void |
| 683 | -QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) | 683 | +QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign_oh) |
| 684 | { | 684 | { |
| 685 | // This method was originally written for copying foreign streams, but it is used by | 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 | QPDFObjGen local_og(result.getObjGen()); | 693 | QPDFObjGen local_og(result.getObjGen()); |
| 696 | // Copy information from the foreign stream so we can pipe its data later without keeping the | 694 | // Copy information from the foreign stream so we can pipe its data later without keeping the |
| 697 | // original QPDF object around. | 695 | // original QPDF object around. |
| 698 | 696 | ||
| 699 | QPDF& foreign_stream_qpdf = | 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 | throw std::logic_error("unable to retrieve underlying stream object from foreign stream"); | 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 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the | 706 | // Pull the stream data into a buffer before attempting the copy operation. Do it on the |
| 709 | // source stream so that if the source stream is copied multiple times, we don't have to | 707 | // source stream so that if the source stream is copied multiple times, we don't have to |
| 710 | // keep duplicating the memory. | 708 | // keep duplicating the memory. |
| 711 | - QTC::TC("qpdf", "QPDF immediate copy stream data"); | ||
| 712 | foreign.replaceStreamData( | 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 | // In this case, the remote stream's QPDF must stay in scope. | 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 | result.replaceStreamData( | 719 | result.replaceStreamData( |
| 729 | - m->copied_streams, dict.getKey("/Filter"), dict.getKey("/DecodeParms")); | 720 | + m->copied_stream_data_provider, dict["/Filter"], dict["/DecodeParms"]); |
| 730 | } else { | 721 | } else { |
| 731 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( | 722 | auto foreign_stream_data = std::make_shared<ForeignStreamData>( |
| 732 | foreign_stream_qpdf.m->encp, | 723 | foreign_stream_qpdf.m->encp, |
| 733 | foreign_stream_qpdf.m->file, | 724 | foreign_stream_qpdf.m->file, |
| 734 | foreign, | 725 | foreign, |
| 735 | foreign.offset(), | 726 | foreign.offset(), |
| 736 | - stream.getLength(), | 727 | + foreign.getLength(), |
| 737 | dict, | 728 | dict, |
| 738 | - stream.isRootMetadata()); | 729 | + foreign.isRootMetadata()); |
| 739 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); | 730 | m->copied_stream_data_provider->registerForeignStream(local_og, foreign_stream_data); |
| 740 | result.replaceStreamData( | 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,6 +628,16 @@ Stream::pipeStreamData( | ||
| 628 | 628 | ||
| 629 | void | 629 | void |
| 630 | Stream::replaceStreamData( | 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 | std::shared_ptr<Buffer> data, | 641 | std::shared_ptr<Buffer> data, |
| 632 | QPDFObjectHandle const& filter, | 642 | QPDFObjectHandle const& filter, |
| 633 | QPDFObjectHandle const& decode_parms) | 643 | QPDFObjectHandle const& decode_parms) |
| @@ -635,7 +645,7 @@ Stream::replaceStreamData( | @@ -635,7 +645,7 @@ Stream::replaceStreamData( | ||
| 635 | auto s = stream(); | 645 | auto s = stream(); |
| 636 | s->stream_data = data; | 646 | s->stream_data = data; |
| 637 | s->stream_provider = nullptr; | 647 | s->stream_provider = nullptr; |
| 638 | - replaceFilterData(filter, decode_parms, data->getSize()); | 648 | + replaceFilterData(filter, decode_parms, data->size()); |
| 639 | } | 649 | } |
| 640 | 650 | ||
| 641 | void | 651 | void |
| @@ -781,12 +791,8 @@ void | @@ -781,12 +791,8 @@ void | ||
| 781 | QPDFObjectHandle::replaceStreamData( | 791 | QPDFObjectHandle::replaceStreamData( |
| 782 | std::string const& data, QPDFObjectHandle const& filter, QPDFObjectHandle const& decode_parms) | 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 | void | 798 | void |
libqpdf/qpdf/QPDFObjectHandle_private.hh
| @@ -520,6 +520,10 @@ namespace qpdf | @@ -520,6 +520,10 @@ namespace qpdf | ||
| 520 | std::string getStreamData(qpdf_stream_decode_level_e level); | 520 | std::string getStreamData(qpdf_stream_decode_level_e level); |
| 521 | std::string getRawStreamData(); | 521 | std::string getRawStreamData(); |
| 522 | void replaceStreamData( | 522 | void replaceStreamData( |
| 523 | + std::string&& data, | ||
| 524 | + QPDFObjectHandle const& filter, | ||
| 525 | + QPDFObjectHandle const& decode_parms); | ||
| 526 | + void replaceStreamData( | ||
| 523 | std::shared_ptr<Buffer> data, | 527 | std::shared_ptr<Buffer> data, |
| 524 | QPDFObjectHandle const& filter, | 528 | QPDFObjectHandle const& filter, |
| 525 | QPDFObjectHandle const& decode_parms); | 529 | QPDFObjectHandle const& decode_parms); |
libqpdf/qpdf/QPDF_private.hh
| @@ -846,9 +846,7 @@ class QPDF::Members | @@ -846,9 +846,7 @@ class QPDF::Members | ||
| 846 | bool ever_called_get_all_pages{false}; | 846 | bool ever_called_get_all_pages{false}; |
| 847 | std::vector<QPDFExc> warnings; | 847 | std::vector<QPDFExc> warnings; |
| 848 | std::map<unsigned long long, ObjCopier> object_copiers; | 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 | bool reconstructed_xref{false}; | 850 | bool reconstructed_xref{false}; |
| 853 | bool in_read_xref_stream{false}; | 851 | bool in_read_xref_stream{false}; |
| 854 | bool fixed_dangling_refs{false}; | 852 | bool fixed_dangling_refs{false}; |
qpdf/qpdf.testcov
| @@ -252,9 +252,6 @@ QPDFJob image optimize no pipeline 0 | @@ -252,9 +252,6 @@ QPDFJob image optimize no pipeline 0 | ||
| 252 | QPDFJob image optimize no shrink 0 | 252 | QPDFJob image optimize no shrink 0 |
| 253 | QPDFJob image optimize too small 0 | 253 | QPDFJob image optimize too small 0 |
| 254 | QPDF pipe foreign encrypted stream 0 | 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 | QPDFJob copy same page more than once 1 | 255 | QPDFJob copy same page more than once 1 |
| 259 | QPDFPageObjectHelper bad token finding names 0 | 256 | QPDFPageObjectHelper bad token finding names 0 |
| 260 | QPDFJob password mode bytes 0 | 257 | QPDFJob password mode bytes 0 |