From 60afe4142e4399b12f21aced476df7ef719008b9 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 21 Feb 2021 05:56:52 -0500 Subject: [PATCH] Refactor: separate copyStreamData from replaceForeignIndirectObjects --- include/qpdf/QPDF.hh | 2 + libqpdf/QPDF.cc | 162 +++++++++++++++++++++++-------------------- 2 files changed, 87 insertions(+), 77 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 4490189d..ee00b23f 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1005,6 +1005,8 @@ class QPDF bool top); QPDFObjectHandle replaceForeignIndirectObjects( QPDFObjectHandle foreign, ObjCopier& obj_copier, bool top); + void copyStreamData( + QPDFObjectHandle dest_stream, QPDFObjectHandle src_stream); // Linearization Hint table structures. // Naming conventions: diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 3209903f..5dfc9224 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -2569,88 +2569,14 @@ QPDF::replaceForeignIndirectObjects( QPDFObjectHandle old_dict = foreign.getDict(); std::set keys = old_dict.getKeys(); for (std::set::iterator iter = keys.begin(); - iter != keys.end(); ++iter) - { + iter != keys.end(); ++iter) + { dict.replaceKey( *iter, replaceForeignIndirectObjects( old_dict.getKey(*iter), obj_copier, false)); - } - if (this->m->copied_stream_data_provider == 0) - { - this->m->copied_stream_data_provider = - new CopiedStreamDataProvider(*this); - this->m->copied_streams = this->m->copied_stream_data_provider; - } - QPDFObjGen local_og(result.getObjGen()); - // Copy information from the foreign stream so we can pipe its - // data later without keeping the original QPDF object around. - QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(); - if (! foreign_stream_qpdf) - { - throw std::logic_error("unable to retrieve owning qpdf" - " from foreign stream"); - } - QPDF_Stream* stream = - dynamic_cast( - QPDFObjectHandle::ObjAccessor::getObject( - foreign).getPointer()); - if (! stream) - { - throw std::logic_error("unable to retrieve underlying" - " stream object from foreign stream"); - } - PointerHolder stream_buffer = - stream->getStreamDataBuffer(); - if ((foreign_stream_qpdf->m->immediate_copy_from) && - (stream_buffer.getPointer() == 0)) - { - // 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. - QTC::TC("qpdf", "QPDF immediate copy stream data"); - foreign.replaceStreamData(foreign.getRawStreamData(), - old_dict.getKey("/Filter"), - old_dict.getKey("/DecodeParms")); - stream_buffer = stream->getStreamDataBuffer(); - } - PointerHolder stream_provider = - stream->getStreamDataProvider(); - if (stream_buffer.getPointer()) - { - QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); - result.replaceStreamData(stream_buffer, - dict.getKey("/Filter"), - dict.getKey("/DecodeParms")); - } - else if (stream_provider.getPointer()) - { - // In this case, the remote stream's QPDF must stay in scope. - QTC::TC("qpdf", "QPDF copy foreign stream with provider"); - this->m->copied_stream_data_provider->registerForeignStream( - local_og, foreign); - result.replaceStreamData(this->m->copied_streams, - dict.getKey("/Filter"), - dict.getKey("/DecodeParms")); - } - else - { - PointerHolder foreign_stream_data = - new ForeignStreamData( - foreign_stream_qpdf->m->encp, - foreign_stream_qpdf->m->file, - foreign.getObjectID(), - foreign.getGeneration(), - stream->getOffset(), - stream->getLength(), - dict); - this->m->copied_stream_data_provider->registerForeignStream( - local_og, foreign_stream_data); - result.replaceStreamData(this->m->copied_streams, - dict.getKey("/Filter"), - dict.getKey("/DecodeParms")); } + copyStreamData(result, foreign); } else { @@ -2667,6 +2593,88 @@ QPDF::replaceForeignIndirectObjects( return result; } +void +QPDF::copyStreamData(QPDFObjectHandle result, QPDFObjectHandle foreign) +{ + QPDFObjectHandle dict = result.getDict(); + QPDFObjectHandle old_dict = foreign.getDict(); + if (this->m->copied_stream_data_provider == 0) + { + this->m->copied_stream_data_provider = + new CopiedStreamDataProvider(*this); + this->m->copied_streams = this->m->copied_stream_data_provider; + } + QPDFObjGen local_og(result.getObjGen()); + // Copy information from the foreign stream so we can pipe its + // data later without keeping the original QPDF object around. + QPDF* foreign_stream_qpdf = foreign.getOwningQPDF(); + if (! foreign_stream_qpdf) + { + throw std::logic_error("unable to retrieve owning qpdf" + " from foreign stream"); + } + QPDF_Stream* stream = + dynamic_cast( + QPDFObjectHandle::ObjAccessor::getObject( + foreign).getPointer()); + if (! stream) + { + throw std::logic_error("unable to retrieve underlying" + " stream object from foreign stream"); + } + PointerHolder stream_buffer = + stream->getStreamDataBuffer(); + if ((foreign_stream_qpdf->m->immediate_copy_from) && + (stream_buffer.getPointer() == 0)) + { + // 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. + QTC::TC("qpdf", "QPDF immediate copy stream data"); + foreign.replaceStreamData(foreign.getRawStreamData(), + old_dict.getKey("/Filter"), + old_dict.getKey("/DecodeParms")); + stream_buffer = stream->getStreamDataBuffer(); + } + PointerHolder stream_provider = + stream->getStreamDataProvider(); + if (stream_buffer.getPointer()) + { + QTC::TC("qpdf", "QPDF copy foreign stream with buffer"); + result.replaceStreamData(stream_buffer, + dict.getKey("/Filter"), + dict.getKey("/DecodeParms")); + } + else if (stream_provider.getPointer()) + { + // In this case, the remote stream's QPDF must stay in scope. + QTC::TC("qpdf", "QPDF copy foreign stream with provider"); + this->m->copied_stream_data_provider->registerForeignStream( + local_og, foreign); + result.replaceStreamData(this->m->copied_streams, + dict.getKey("/Filter"), + dict.getKey("/DecodeParms")); + } + else + { + PointerHolder foreign_stream_data = + new ForeignStreamData( + foreign_stream_qpdf->m->encp, + foreign_stream_qpdf->m->file, + foreign.getObjectID(), + foreign.getGeneration(), + stream->getOffset(), + stream->getLength(), + dict); + this->m->copied_stream_data_provider->registerForeignStream( + local_og, foreign_stream_data); + result.replaceStreamData(this->m->copied_streams, + dict.getKey("/Filter"), + dict.getKey("/DecodeParms")); + } +} + void QPDF::swapObjects(QPDFObjGen const& og1, QPDFObjGen const& og2) {