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 800 bool is_root_metadata,
801 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 803 struct HPageOffsetEntry;
807 804 struct HPageOffset;
808 805 struct HSharedObjectEntry;
... ...
libqpdf/QPDF.cc
... ... @@ -112,14 +112,14 @@ namespace
112 112 };
113 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 141 fd.encp,
142 142 fd.file,
143 143 streams.qpdf(),
144   - fd.foreign_og,
  144 + fd.source_og,
145 145 fd.offset,
146 146 fd.length,
147   - fd.local_dict,
  147 + fd.dest_dict,
148 148 fd.is_root_metadata,
149 149 pipeline,
150 150 suppress_warnings,
... ... @@ -667,7 +667,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const&amp; foreig
667 667 dict.replaceKey(key, replace_indirect_object(value));
668 668 }
669 669 }
670   - qpdf.copyStreamData(result, foreign);
  670 + stream.copy_data_to(result);
671 671 return result;
672 672 }
673 673  
... ...
libqpdf/QPDF_Stream.cc
... ... @@ -27,6 +27,12 @@ using namespace qpdf;
27 27  
28 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 36 namespace
31 37 {
32 38 class SF_Crypt final: public QPDFStreamFilter
... ... @@ -188,50 +194,42 @@ Stream::Stream(
188 194 }
189 195  
190 196 Stream
191   -Stream::copy() const
  197 +Stream::copy()
192 198 {
193 199 Stream result = qpdf()->newStream();
194 200 result.stream()->stream_dict = getDict().copy();
195   - Streams::copyStreamData(qpdf(), result, *this);
  201 + copy_data_to(result);
196 202 return result;
197 203 }
198 204  
199 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 218 // Pull the stream data into a buffer before attempting the copy operation. Do it on the
217 219 // source stream so that if the source stream is copied multiple times, we don't have to
218 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 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 469 qpdf_offset_t offset,
470 470 size_t length);
471 471  
472   - Stream copy() const;
  472 + Stream copy();
  473 +
  474 + void copy_data_to(Stream& target);
473 475  
474 476 Dictionary
475 477 getDict() const
... ...
libqpdf/qpdf/QPDF_private.hh
... ... @@ -587,15 +587,15 @@ class QPDF::Doc
587 587 friend class Streams;
588 588  
589 589 public:
590   - Data(Stream& foreign, qpdf_offset_t offset, QPDFObjectHandle local_dict);
  590 + Data(Stream& source, QPDFObjectHandle const& dest_dict);
591 591  
592 592 private:
593 593 std::shared_ptr<EncryptionParameters> encp;
594 594 std::shared_ptr<InputSource> file;
595   - QPDFObjGen foreign_og;
  595 + QPDFObjGen source_og;
596 596 qpdf_offset_t offset;
597 597 size_t length;
598   - QPDFObjectHandle local_dict;
  598 + QPDFObjectHandle dest_dict;
599 599 bool is_root_metadata{false};
600 600 };
601 601  
... ... @@ -628,7 +628,7 @@ class QPDF::Doc
628 628 qpdf_offset_t offset,
629 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 634 private:
... ... @@ -675,12 +675,6 @@ class QPDF::Doc
675 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 678 QPDF&
685 679 qpdf() const
686 680 {
... ... @@ -693,11 +687,13 @@ class QPDF::Doc
693 687 return copier_;
694 688 }
695 689  
  690 + bool immediate_copy_from() const;
  691 +
696 692 private:
697 693 QPDF& qpdf_;
698 694  
699 695 std::shared_ptr<Copier> copier_;
700   - };
  696 + }; // class QPDF::Doc::Objects::Streams
701 697  
702 698 public:
703 699 Objects() = delete;
... ...