From 893d38b87e4ad6c6c55f49464f6b721c516ec878 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sat, 4 Apr 2020 23:35:35 -0400 Subject: Allow propagation of errors and retry through StreamDataProvider StreamDataProvider::provideStreamData now has a rich enough API for it to effectively proxy to pipeStreamData. --- libqpdf/QPDF.cc | 25 +++++++++++++++-------- libqpdf/QPDFObjectHandle.cc | 49 +++++++++++++++++++++++++++++++++++++++++++-- libqpdf/QPDF_Stream.cc | 41 ++++++++++++++++++++++++++++++------- libqpdf/qpdf/QPDF_Stream.hh | 2 +- 4 files changed, 99 insertions(+), 18 deletions(-) (limited to 'libqpdf') diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 3177d38b..6219509e 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -68,27 +68,37 @@ QPDF::ForeignStreamData::ForeignStreamData( QPDF::CopiedStreamDataProvider::CopiedStreamDataProvider( QPDF& destination_qpdf) : + QPDFObjectHandle::StreamDataProvider(true), destination_qpdf(destination_qpdf) { } -void +bool QPDF::CopiedStreamDataProvider::provideStreamData( - int objid, int generation, Pipeline* pipeline) + int objid, int generation, Pipeline* pipeline, + bool suppress_warnings, bool will_retry) { PointerHolder foreign_data = this->foreign_stream_data[QPDFObjGen(objid, generation)]; + bool result = false; if (foreign_data.getPointer()) { - destination_qpdf.pipeForeignStreamData( - foreign_data, pipeline, 0, qpdf_dl_none); + result = destination_qpdf.pipeForeignStreamData( + foreign_data, pipeline, suppress_warnings, will_retry); + QTC::TC("qpdf", "QPDF copy foreign with data", + result ? 0 : 1); } else { QPDFObjectHandle foreign_stream = this->foreign_streams[QPDFObjGen(objid, generation)]; - foreign_stream.pipeStreamData(pipeline, 0, qpdf_dl_none); + result = foreign_stream.pipeStreamData( + pipeline, nullptr, 0, qpdf_dl_none, + suppress_warnings, will_retry); + QTC::TC("qpdf", "QPDF copy foreign with foreign_stream", + result ? 0 : 1); } + return result; } void @@ -2851,8 +2861,7 @@ bool QPDF::pipeForeignStreamData( PointerHolder foreign, Pipeline* pipeline, - int encode_flags, - qpdf_stream_decode_level_e decode_level) + bool suppress_warnings, bool will_retry) { if (foreign->encp->encrypted) { @@ -2863,7 +2872,7 @@ QPDF::pipeForeignStreamData( foreign->foreign_objid, foreign->foreign_generation, foreign->offset, foreign->length, foreign->local_dict, foreign->is_attachment_stream, - pipeline, false, false); + pipeline, suppress_warnings, will_retry); } void diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index dca59216..ab77fb73 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -36,6 +36,36 @@ class TerminateParsing { }; +QPDFObjectHandle::StreamDataProvider::StreamDataProvider( + bool supports_retry) : + supports_retry(supports_retry) +{ +} + +void +QPDFObjectHandle::StreamDataProvider::provideStreamData( + int objid, int generation, Pipeline* pipeline) +{ + throw std::logic_error( + "you must override provideStreamData -- see QPDFObjectHandle.hh"); +} + +bool +QPDFObjectHandle::StreamDataProvider::provideStreamData( + int objid, int generation, Pipeline* pipeline, + bool suppress_warnings, bool will_retry) +{ + throw std::logic_error( + "you must override provideStreamData -- see QPDFObjectHandle.hh"); + return false; +} + +bool +QPDFObjectHandle::StreamDataProvider::supportsRetry() +{ + return this->supports_retry; +} + class CoalesceProvider: public QPDFObjectHandle::StreamDataProvider { public: @@ -1135,14 +1165,29 @@ QPDFObjectHandle::getRawStreamData() } bool -QPDFObjectHandle::pipeStreamData(Pipeline* p, +QPDFObjectHandle::pipeStreamData(Pipeline* p, bool* filtering_attempted, int encode_flags, qpdf_stream_decode_level_e decode_level, bool suppress_warnings, bool will_retry) { assertStream(); return dynamic_cast(obj.getPointer())->pipeStreamData( - p, encode_flags, decode_level, suppress_warnings, will_retry); + p, filtering_attempted, encode_flags, decode_level, + suppress_warnings, will_retry); +} + +bool +QPDFObjectHandle::pipeStreamData(Pipeline* p, + int encode_flags, + qpdf_stream_decode_level_e decode_level, + bool suppress_warnings, bool will_retry) +{ + assertStream(); + bool filtering_attempted; + dynamic_cast(obj.getPointer())->pipeStreamData( + p, &filtering_attempted, encode_flags, decode_level, + suppress_warnings, will_retry); + return filtering_attempted; } bool diff --git a/libqpdf/QPDF_Stream.cc b/libqpdf/QPDF_Stream.cc index dd2796e8..48c1ccf9 100644 --- a/libqpdf/QPDF_Stream.cc +++ b/libqpdf/QPDF_Stream.cc @@ -163,7 +163,7 @@ PointerHolder QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) { Pl_Buffer buf("stream data buffer"); - if (! pipeStreamData(&buf, 0, decode_level, false, false)) + if (! pipeStreamData(&buf, nullptr, 0, decode_level, false, false)) { throw QPDFExc(qpdf_e_unsupported, qpdf->getFilename(), "", this->offset, @@ -177,7 +177,12 @@ PointerHolder QPDF_Stream::getRawStreamData() { Pl_Buffer buf("stream data buffer"); - pipeStreamData(&buf, 0, qpdf_dl_none, false, false); + if (! pipeStreamData(&buf, nullptr, 0, qpdf_dl_none, false, false)) + { + throw QPDFExc(qpdf_e_unsupported, qpdf->getFilename(), + "", this->offset, + "error getting raw stream data"); + } QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); return buf.getBuffer(); } @@ -467,7 +472,7 @@ QPDF_Stream::filterable(std::vector& filters, } bool -QPDF_Stream::pipeStreamData(Pipeline* pipeline, +QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool* filterp, int encode_flags, qpdf_stream_decode_level_e decode_level, bool suppress_warnings, bool will_retry) @@ -480,7 +485,14 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, bool early_code_change = true; bool specialized_compression = false; bool lossy_compression = false; - bool filter = (! ((encode_flags == 0) && (decode_level == qpdf_dl_none))); + bool ignored; + if (filterp == nullptr) + { + filterp = &ignored; + } + bool& filter = *filterp; + filter = (! ((encode_flags == 0) && (decode_level == qpdf_dl_none))); + bool success = true; if (filter) { filter = filterable(filters, specialized_compression, lossy_compression, @@ -505,6 +517,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, if (pipeline == 0) { QTC::TC("qpdf", "QPDF_Stream pipeStreamData with null pipeline"); + // Return value is whether we can filter in this case. return filter; } @@ -625,8 +638,21 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, else if (this->stream_provider.getPointer()) { Pl_Count count("stream provider count", pipeline); - this->stream_provider->provideStreamData( - this->objid, this->generation, &count); + if (this->stream_provider->supportsRetry()) + { + if (! this->stream_provider->provideStreamData( + this->objid, this->generation, &count, + suppress_warnings, will_retry)) + { + filter = false; + success = false; + } + } + else + { + this->stream_provider->provideStreamData( + this->objid, this->generation, &count); + } qpdf_offset_t actual_length = count.getCount(); qpdf_offset_t desired_length = 0; if (this->stream_dict.hasKey("/Length")) @@ -674,6 +700,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, will_retry)) { filter = false; + success = false; } } @@ -704,7 +731,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, " for content normalization in the manual.")); } - return filter; + return success; } void diff --git a/libqpdf/qpdf/QPDF_Stream.hh b/libqpdf/qpdf/QPDF_Stream.hh index b6428cc9..da9f91a0 100644 --- a/libqpdf/qpdf/QPDF_Stream.hh +++ b/libqpdf/qpdf/QPDF_Stream.hh @@ -31,7 +31,7 @@ class QPDF_Stream: public QPDFObject PointerHolder getStreamDataProvider() const; // See comments in QPDFObjectHandle.hh for these methods. - bool pipeStreamData(Pipeline*, + bool pipeStreamData(Pipeline*, bool* tried_filtering, int encode_flags, qpdf_stream_decode_level_e decode_level, bool suppress_warnings, bool will_retry); -- cgit v1.2.3-54-g00ecf