Commit 403dbd5f5bf61c989faee4e4038d13af2f4e9931

Authored by m-holger
1 parent d207f615

Refactor stream copying: simplify `replaceStreamData` logic and remove redundant…

… `StreamDataProvider` management.
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
... ...