diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index fd1e4ce..7dfcbeb 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -800,9 +800,6 @@ class QPDF bool is_root_metadata, std::unique_ptr& heap); - // Methods to support object copying - void copyStreamData(QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream); - struct HPageOffsetEntry; struct HPageOffset; struct HSharedObjectEntry; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index db4977b..e6eb71d 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -112,14 +112,14 @@ namespace }; } // namespace -Streams::Copier::Data::Data(Stream& foreign, qpdf_offset_t offset, QPDFObjectHandle local_dict) : - encp(foreign.qpdf()->m->encp), - file(foreign.qpdf()->m->file), - foreign_og(foreign.id_gen()), - offset(offset), - length(foreign.getLength()), - local_dict(local_dict), - is_root_metadata(foreign.isRootMetadata()) +Streams::Copier::Data::Data(Stream& source, QPDFObjectHandle const& dest_dict) : + encp(source.qpdf()->m->encp), + file(source.qpdf()->m->file), + source_og(source.id_gen()), + offset(source.offset()), + length(source.getLength()), + dest_dict(dest_dict), + is_root_metadata(source.isRootMetadata()) { } @@ -141,10 +141,10 @@ Streams::Copier::provideStreamData( fd.encp, fd.file, streams.qpdf(), - fd.foreign_og, + fd.source_og, fd.offset, fd.length, - fd.local_dict, + fd.dest_dict, fd.is_root_metadata, pipeline, suppress_warnings, @@ -667,7 +667,7 @@ Objects::Foreign::Copier::replace_indirect_object(QPDFObjectHandle const& foreig dict.replaceKey(key, replace_indirect_object(value)); } } - qpdf.copyStreamData(result, foreign); + stream.copy_data_to(result); return result; } diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index 44740df..20f7d8a 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -27,6 +27,12 @@ using namespace qpdf; using Streams = QPDF::Doc::Objects::Streams; +bool +Streams::immediate_copy_from() const +{ + return qpdf_.m->immediate_copy_from; +} + namespace { class SF_Crypt final: public QPDFStreamFilter @@ -188,50 +194,42 @@ Stream::Stream( } Stream -Stream::copy() const +Stream::copy() { Stream result = qpdf()->newStream(); result.stream()->stream_dict = getDict().copy(); - Streams::copyStreamData(qpdf(), result, *this); + copy_data_to(result); return result; } void -QPDF::copyStreamData(QPDFObjectHandle dest, QPDFObjectHandle source_oh) +Stream::copy_data_to(Stream& dest) { - Dictionary dict = dest.getDict(); - Dictionary old_dict = source_oh.getDict(); - QPDFObjGen local_og(dest.getObjGen()); - // Copy information from the foreign stream so we can pipe its data later without keeping the - // original QPDF object around. + qpdf_expect(dest); + auto s = stream(); + auto& streams = qpdf()->doc().objects().streams(); + auto& d_streams = dest.qpdf()->doc().objects().streams(); - QPDF& source_qpdf = source_oh.getQPDF("unable to retrieve owning qpdf from foreign stream"); + auto dict = dest.getDict(); - Stream source = source_oh; - if (!source) { - throw std::logic_error("unable to retrieve underlying stream object from foreign stream"); - } - std::shared_ptr stream_buffer = source.getStreamDataBuffer(); - if (source_qpdf.m->immediate_copy_from && !stream_buffer) { + // Copy information from the foreign stream so we can pipe its data later without keeping the + // original QPDF object around. + if (streams.immediate_copy_from() && !s->stream_data) { // Pull the stream data into a buffer before attempting the copy operation. Do it on the // source stream so that if the source stream is copied multiple times, we don't have to // keep duplicating the memory. - source.replaceStreamData( - source.getRawStreamData(), old_dict["/Filter"], old_dict["/DecodeParms"]); - stream_buffer = source.getStreamDataBuffer(); - } - auto stream_provider = source.getStreamDataProvider(); - if (stream_buffer) { - dest.replaceStreamData(stream_buffer, dict["/Filter"], dict["/DecodeParms"]); - } else if (stream_provider) { - // In this case, the remote stream's QPDF must stay in scope. - m->objects.streams().copier()->register_copy(local_og, source_oh); - dest.replaceStreamData( - m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); + replaceStreamData( + getRawStreamData(), s->stream_dict["/Filter"], s->stream_dict["/DecodeParms"]); + } + if (s->stream_data) { + dest.replaceStreamData(s->stream_data, dict["/Filter"], dict["/DecodeParms"]); + } else if (s->stream_provider) { + // In this case, the source stream's QPDF must stay in scope. + d_streams.copier()->register_copy(dest, *this); + dest.replaceStreamData(d_streams.copier(), dict["/Filter"], dict["/DecodeParms"]); } else { - m->objects.streams().copier()->register_copy(local_og, source, source.offset(), dict); - dest.replaceStreamData( - m->objects.streams().copier(), dict["/Filter"], dict["/DecodeParms"]); + d_streams.copier()->register_copy(dest, *this, offset(), dict); + dest.replaceStreamData(d_streams.copier(), dict["/Filter"], dict["/DecodeParms"]); } } diff --git a/libqpdf/qpdf/QPDFObjectHandle_private.hh b/libqpdf/qpdf/QPDFObjectHandle_private.hh index 2073456..6cf3424 100644 --- a/libqpdf/qpdf/QPDFObjectHandle_private.hh +++ b/libqpdf/qpdf/QPDFObjectHandle_private.hh @@ -469,7 +469,9 @@ namespace qpdf qpdf_offset_t offset, size_t length); - Stream copy() const; + Stream copy(); + + void copy_data_to(Stream& target); Dictionary getDict() const diff --git a/libqpdf/qpdf/QPDF_private.hh b/libqpdf/qpdf/QPDF_private.hh index c898a01..4f112b7 100644 --- a/libqpdf/qpdf/QPDF_private.hh +++ b/libqpdf/qpdf/QPDF_private.hh @@ -587,15 +587,15 @@ class QPDF::Doc friend class Streams; public: - Data(Stream& foreign, qpdf_offset_t offset, QPDFObjectHandle local_dict); + Data(Stream& source, QPDFObjectHandle const& dest_dict); private: std::shared_ptr encp; std::shared_ptr file; - QPDFObjGen foreign_og; + QPDFObjGen source_og; qpdf_offset_t offset; size_t length; - QPDFObjectHandle local_dict; + QPDFObjectHandle dest_dict; bool is_root_metadata{false}; }; @@ -628,7 +628,7 @@ class QPDF::Doc qpdf_offset_t offset, QPDFObjectHandle const& local_dict) { - copied_data.insert_or_assign(local_og, Data(foreign, offset, local_dict)); + copied_data.insert_or_assign(local_og, Data(foreign, local_dict)); } private: @@ -675,12 +675,6 @@ class QPDF::Doc will_retry); } - static void - copyStreamData(QPDF* qpdf, QPDFObjectHandle const& dest, QPDFObjectHandle const& src) - { - qpdf->copyStreamData(dest, src); - } - QPDF& qpdf() const { @@ -693,11 +687,13 @@ class QPDF::Doc return copier_; } + bool immediate_copy_from() const; + private: QPDF& qpdf_; std::shared_ptr copier_; - }; + }; // class QPDF::Doc::Objects::Streams public: Objects() = delete;