From fddbcab0e7cc5978802251696055efa64667f637 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 6 Jan 2019 21:18:36 -0500 Subject: Mostly don't require original QPDF for copyForeignObject (fixes #219) The original QPDF is only required now when the source QPDFObjectHandle is a stream that gets its stream data from a QPDFObjectHandle::StreamDataProvider. --- libqpdf/QPDF.cc | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 9 deletions(-) (limited to 'libqpdf/QPDF.cc') diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index f5267dea..c5172fd7 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -18,6 +18,7 @@ #include #include #include +#include std::string QPDF::qpdf_version = "8.2.1"; @@ -39,13 +40,50 @@ static char const* EMPTY_PDF = "110\n" "%%EOF\n"; +QPDF::ForeignStreamData::ForeignStreamData( + PointerHolder encp, + PointerHolder file, + int foreign_objid, + int foreign_generation, + qpdf_offset_t offset, + size_t length, + bool is_attachment_stream, + QPDFObjectHandle local_dict) + : + encp(encp), + file(file), + foreign_objid(foreign_objid), + foreign_generation(foreign_generation), + offset(offset), + length(length), + is_attachment_stream(is_attachment_stream), + local_dict(local_dict) +{ +} + +QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider( + QPDF& destination_qpdf) : + destination_qpdf(destination_qpdf) +{ +} + void QPDF::CopiedStreamDataProvider::provideStreamData( int objid, int generation, Pipeline* pipeline) { - QPDFObjectHandle foreign_stream = - this->foreign_streams[QPDFObjGen(objid, generation)]; - foreign_stream.pipeStreamData(pipeline, 0, qpdf_dl_none); + PointerHolder foreign_data = + this->foreign_stream_data[QPDFObjGen(objid, generation)]; + if (foreign_data.getPointer()) + { + destination_qpdf.pipeForeignStreamData( + foreign_data, pipeline, 0, qpdf_dl_none); + } + else + { + QPDFObjectHandle foreign_stream = + this->foreign_streams[QPDFObjGen(objid, generation)]; + foreign_stream.pipeStreamData(pipeline, 0, qpdf_dl_none); + } } void @@ -55,6 +93,14 @@ QPDF::CopiedStreamDataProvider::registerForeignStream( this->foreign_streams[local_og] = foreign_stream; } +void +QPDF::CopiedStreamDataProvider::registerForeignStream( + QPDFObjGen const& local_og, + PointerHolder foreign_stream) +{ + this->foreign_stream_data[local_og] = foreign_stream; +} + QPDF::StringDecrypter::StringDecrypter(QPDF* qpdf, int objid, int gen) : qpdf(qpdf), objid(objid), @@ -2307,15 +2353,67 @@ QPDF::replaceForeignIndirectObjects( if (this->m->copied_stream_data_provider == 0) { this->m->copied_stream_data_provider = - new CopiedStreamDataProvider(); + new CopiedStreamDataProvider(*this); this->m->copied_streams = this->m->copied_stream_data_provider; } QPDFObjGen local_og(result.getObjGen()); - this->m->copied_stream_data_provider->registerForeignStream( - local_og, foreign); - result.replaceStreamData(this->m->copied_streams, - dict.getKey("/Filter"), - dict.getKey("/DecodeParms")); + // 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(); + 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(), + (foreign_stream_qpdf->m->attachment_streams.count( + foreign.getObjGen()) > 0), + 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")); + } } else { @@ -2613,6 +2711,25 @@ QPDF::pipeStreamData(int objid, int generation, pipeline, suppress_warnings, will_retry); } +bool +QPDF::pipeForeignStreamData( + PointerHolder foreign, + Pipeline* pipeline, + unsigned long encode_flags, + qpdf_stream_decode_level_e decode_level) +{ + if (foreign->encp->encrypted) + { + QTC::TC("qpdf", "QPDF pipe foreign encrypted stream"); + } + return pipeStreamData( + foreign->encp, foreign->file, *this, + foreign->foreign_objid, foreign->foreign_generation, + foreign->offset, foreign->length, + foreign->local_dict, foreign->is_attachment_stream, + pipeline, false, false); +} + void QPDF::findAttachmentStreams() { -- cgit v1.2.3-70-g09d2