aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2020-04-05 05:35:35 +0200
committerJay Berkenbilt <ejb@ql.org>2020-04-06 02:07:13 +0200
commit893d38b87e4ad6c6c55f49464f6b721c516ec878 (patch)
tree200289d57f269a394bc2a93f5978322d037f8628 /libqpdf
parenta5367003c3eaf7f21d369c1c6d11338564cf04f2 (diff)
downloadqpdf-893d38b87e4ad6c6c55f49464f6b721c516ec878.tar.zst
Allow propagation of errors and retry through StreamDataProvider
StreamDataProvider::provideStreamData now has a rich enough API for it to effectively proxy to pipeStreamData.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDF.cc25
-rw-r--r--libqpdf/QPDFObjectHandle.cc49
-rw-r--r--libqpdf/QPDF_Stream.cc41
-rw-r--r--libqpdf/qpdf/QPDF_Stream.hh2
4 files changed, 99 insertions, 18 deletions
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<ForeignStreamData> 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<ForeignStreamData> 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<QPDF_Stream*>(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<QPDF_Stream*>(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<Buffer>
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<Buffer>
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<std::string>& 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<QPDFObjectHandle::StreamDataProvider> 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);