Commit 19073b4602b60367dfeefde3c551c374f052d400

Authored by m-holger
1 parent 171027b1

Refactor stream copying: move `copyStreamData` logic into `Stream::copy_data_to`…

… and streamline stream handling.
include/qpdf/QPDF.hh
@@ -800,9 +800,6 @@ class QPDF @@ -800,9 +800,6 @@ class QPDF
800 bool is_root_metadata, 800 bool is_root_metadata,
801 std::unique_ptr<Pipeline>& heap); 801 std::unique_ptr<Pipeline>& heap);
802 802
803 - // Methods to support object copying  
804 - void copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream);  
805 -  
806 struct HPageOffsetEntry; 803 struct HPageOffsetEntry;
807 struct HPageOffset; 804 struct HPageOffset;
808 struct HSharedObjectEntry; 805 struct HSharedObjectEntry;
libqpdf/QPDF.cc
@@ -112,14 +112,14 @@ namespace @@ -112,14 +112,14 @@ namespace
112 }; 112 };
113 } // namespace 113 } // namespace
114 114
115 -Streams::Copier::Data::Data(Stream& foreign, qpdf_offset_t offset, QPDFObjectHandle local_dict) :  
116 - encp(foreign.qpdf()->m->encp),  
117 - file(foreign.qpdf()->m->file),  
118 - foreign_og(foreign.id_gen()),  
119 - offset(offset),  
120 - length(foreign.getLength()),  
121 - local_dict(local_dict),  
122 - is_root_metadata(foreign.isRootMetadata()) 115 +Streams::Copier::Data::Data(Stream& source, QPDFObjectHandle const& dest_dict) :
  116 + encp(source.qpdf()->m->encp),
  117 + file(source.qpdf()->m->file),
  118 + source_og(source.id_gen()),
  119 + offset(source.offset()),
  120 + length(source.getLength()),
  121 + dest_dict(dest_dict),
  122 + is_root_metadata(source.isRootMetadata())
123 { 123 {
124 } 124 }
125 125
@@ -141,10 +141,10 @@ Streams::Copier::provideStreamData( @@ -141,10 +141,10 @@ Streams::Copier::provideStreamData(
141 fd.encp, 141 fd.encp,
142 fd.file, 142 fd.file,
143 streams.qpdf(), 143 streams.qpdf(),
144 - fd.foreign_og, 144 + fd.source_og,
145 fd.offset, 145 fd.offset,
146 fd.length, 146 fd.length,
147 - fd.local_dict, 147 + fd.dest_dict,
148 fd.is_root_metadata, 148 fd.is_root_metadata,
149 pipeline, 149 pipeline,
150 suppress_warnings, 150 suppress_warnings,
@@ -667,7 +667,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig @@ -667,7 +667,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig
667 dict.replaceKey(key, replace_indirect_object(value)); 667 dict.replaceKey(key, replace_indirect_object(value));
668 } 668 }
669 } 669 }
670 - qpdf.copyStreamData(result, foreign); 670 + stream.copy_data_to(result);
671 return result; 671 return result;
672 } 672 }
673 673
libqpdf/QPDF_Stream.cc
@@ -27,6 +27,12 @@ using namespace qpdf; @@ -27,6 +27,12 @@ using namespace qpdf;
27 27
28 using Streams = QPDF::Doc::Objects::Streams; 28 using Streams = QPDF::Doc::Objects::Streams;
29 29
  30 +bool
  31 +Streams::immediate_copy_from() const
  32 +{
  33 + return qpdf_.m->immediate_copy_from;
  34 +}
  35 +
30 namespace 36 namespace
31 { 37 {
32 class SF_Crypt final: public QPDFStreamFilter 38 class SF_Crypt final: public QPDFStreamFilter
@@ -188,50 +194,42 @@ Stream::Stream( @@ -188,50 +194,42 @@ Stream::Stream(
188 } 194 }
189 195
190 Stream 196 Stream
191 -Stream::copy() const 197 +Stream::copy()
192 { 198 {
193 Stream result = qpdf()->newStream(); 199 Stream result = qpdf()->newStream();
194 result.stream()->stream_dict = getDict().copy(); 200 result.stream()->stream_dict = getDict().copy();
195 - Streams::copyStreamData(qpdf(), result, *this); 201 + copy_data_to(result);
196 return result; 202 return result;
197 } 203 }
198 204
199 void 205 void
200 -QPDF::copyStreamData(QPDFObjectHandle dest, QPDFObjectHandle source_oh) 206 +Stream::copy_data_to(Stream& dest)
201 { 207 {
202 - Dictionary dict = dest.getDict();  
203 - Dictionary old_dict = source_oh.getDict();  
204 - QPDFObjGen local_og(dest.getObjGen());  
205 - // Copy information from the foreign stream so we can pipe its data later without keeping the  
206 - // original QPDF object around. 208 + qpdf_expect(dest);
  209 + auto s = stream();
  210 + auto& streams = qpdf()->doc().objects().streams();
  211 + auto& d_streams = dest.qpdf()->doc().objects().streams();
207 212
208 - QPDF& source_qpdf = source_oh.getQPDF("unable to retrieve owning qpdf from foreign stream"); 213 + auto dict = dest.getDict();
209 214
210 - Stream source = source_oh;  
211 - if (!source) {  
212 - throw std::logic_error("unable to retrieve underlying stream object from foreign stream");  
213 - }  
214 - std::shared_ptr<Buffer> stream_buffer = source.getStreamDataBuffer();  
215 - if (source_qpdf.m->immediate_copy_from && !stream_buffer) { 215 + // Copy information from the foreign stream so we can pipe its data later without keeping the
  216 + // original QPDF object around.
  217 + if (streams.immediate_copy_from() && !s->stream_data) {
216 // Pull the stream data into a buffer before attempting the copy operation. Do it on the 218 // Pull the stream data into a buffer before attempting the copy operation. Do it on the
217 // source stream so that if the source stream is copied multiple times, we don't have to 219 // source stream so that if the source stream is copied multiple times, we don't have to
218 // keep duplicating the memory. 220 // keep duplicating the memory.
219 - source.replaceStreamData(  
220 - source.getRawStreamData(), old_dict["/Filter"], old_dict["/DecodeParms"]);  
221 - stream_buffer = source.getStreamDataBuffer();  
222 - }  
223 - auto stream_provider = source.getStreamDataProvider();  
224 - if (stream_buffer) {  
225 - dest.replaceStreamData(stream_buffer, dict["/Filter"], dict["/DecodeParms"]);  
226 - } else if (stream_provider) {  
227 - // In this case, the remote stream's QPDF must stay in scope.  
228 - m->objects.streams().copier()->register_copy(local_og, source_oh);  
229 - dest.replaceStreamData(  
230 - m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); 221 + replaceStreamData(
  222 + getRawStreamData(), s->stream_dict["/Filter"], s->stream_dict["/DecodeParms"]);
  223 + }
  224 + if (s->stream_data) {
  225 + dest.replaceStreamData(s->stream_data, dict["/Filter"], dict["/DecodeParms"]);
  226 + } else if (s->stream_provider) {
  227 + // In this case, the source stream's QPDF must stay in scope.
  228 + d_streams.copier()->register_copy(dest, *this);
  229 + dest.replaceStreamData(d_streams.copier(), dict["/Filter"], dict["/DecodeParms"]);
231 } else { 230 } else {
232 - m->objects.streams().copier()->register_copy(local_og, source, source.offset(), dict);  
233 - dest.replaceStreamData(  
234 - m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); 231 + d_streams.copier()->register_copy(dest, *this, offset(), dict);
  232 + dest.replaceStreamData(d_streams.copier(), dict["/Filter"], dict["/DecodeParms"]);
235 } 233 }
236 } 234 }
237 235
libqpdf/qpdf/QPDFObjectHandle_private.hh
@@ -469,7 +469,9 @@ namespace qpdf @@ -469,7 +469,9 @@ namespace qpdf
469 qpdf_offset_t offset, 469 qpdf_offset_t offset,
470 size_t length); 470 size_t length);
471 471
472 - Stream copy() const; 472 + Stream copy();
  473 +
  474 + void copy_data_to(Stream& target);
473 475
474 Dictionary 476 Dictionary
475 getDict() const 477 getDict() const
libqpdf/qpdf/QPDF_private.hh
@@ -587,15 +587,15 @@ class QPDF::Doc @@ -587,15 +587,15 @@ class QPDF::Doc
587 friend class Streams; 587 friend class Streams;
588 588
589 public: 589 public:
590 - Data(Stream& foreign, qpdf_offset_t offset, QPDFObjectHandle local_dict); 590 + Data(Stream& source, QPDFObjectHandle const& dest_dict);
591 591
592 private: 592 private:
593 std::shared_ptr<EncryptionParameters> encp; 593 std::shared_ptr<EncryptionParameters> encp;
594 std::shared_ptr<InputSource> file; 594 std::shared_ptr<InputSource> file;
595 - QPDFObjGen foreign_og; 595 + QPDFObjGen source_og;
596 qpdf_offset_t offset; 596 qpdf_offset_t offset;
597 size_t length; 597 size_t length;
598 - QPDFObjectHandle local_dict; 598 + QPDFObjectHandle dest_dict;
599 bool is_root_metadata{false}; 599 bool is_root_metadata{false};
600 }; 600 };
601 601
@@ -628,7 +628,7 @@ class QPDF::Doc @@ -628,7 +628,7 @@ class QPDF::Doc
628 qpdf_offset_t offset, 628 qpdf_offset_t offset,
629 QPDFObjectHandle const& local_dict) 629 QPDFObjectHandle const& local_dict)
630 { 630 {
631 - copied_data.insert_or_assign(local_og, Data(foreign, offset, local_dict)); 631 + copied_data.insert_or_assign(local_og, Data(foreign, local_dict));
632 } 632 }
633 633
634 private: 634 private:
@@ -675,12 +675,6 @@ class QPDF::Doc @@ -675,12 +675,6 @@ class QPDF::Doc
675 will_retry); 675 will_retry);
676 } 676 }
677 677
678 - static void  
679 - copyStreamData(QPDF* qpdf, QPDFObjectHandle const& dest, QPDFObjectHandle const& src)  
680 - {  
681 - qpdf->copyStreamData(dest, src);  
682 - }  
683 -  
684 QPDF& 678 QPDF&
685 qpdf() const 679 qpdf() const
686 { 680 {
@@ -693,11 +687,13 @@ class QPDF::Doc @@ -693,11 +687,13 @@ class QPDF::Doc
693 return copier_; 687 return copier_;
694 } 688 }
695 689
  690 + bool immediate_copy_from() const;
  691 +
696 private: 692 private:
697 QPDF& qpdf_; 693 QPDF& qpdf_;
698 694
699 std::shared_ptr<Copier> copier_; 695 std::shared_ptr<Copier> copier_;
700 - }; 696 + }; // class QPDF::Doc::Objects::Streams
701 697
702 public: 698 public:
703 Objects() = delete; 699 Objects() = delete;