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,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