aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/Pl_Flate.cc
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2021-11-02 22:54:10 +0100
committerJay Berkenbilt <ejb@ql.org>2021-11-03 14:43:17 +0100
commit532a4f3d60f6981b22beb32e6ff688ec41f87e26 (patch)
tree73800f3a6da80171152df8c9236ce390bcd581f4 /libqpdf/Pl_Flate.cc
parentc491d9f6af8dd2ecfbc5bd70b2054e03ac2521ac (diff)
downloadqpdf-532a4f3d60f6981b22beb32e6ff688ec41f87e26.tar.zst
Detect recoverable but invalid zlib data streams (fixes #562)
Diffstat (limited to 'libqpdf/Pl_Flate.cc')
-rw-r--r--libqpdf/Pl_Flate.cc35
1 files changed, 32 insertions, 3 deletions
diff --git a/libqpdf/Pl_Flate.cc b/libqpdf/Pl_Flate.cc
index 1eca837e..ee07b6f1 100644
--- a/libqpdf/Pl_Flate.cc
+++ b/libqpdf/Pl_Flate.cc
@@ -72,6 +72,21 @@ Pl_Flate::~Pl_Flate()
}
void
+Pl_Flate::setWarnCallback(std::function<void(char const*, int)> callback)
+{
+ this->m->callback = callback;
+}
+
+void
+Pl_Flate::warn(char const* msg, int code)
+{
+ if (this->m->callback != nullptr)
+ {
+ this->m->callback(msg, code);
+ }
+}
+
+void
Pl_Flate::write(unsigned char* data, size_t len)
{
if (this->m->outbuf.getPointer() == 0)
@@ -164,7 +179,14 @@ Pl_Flate::handleData(unsigned char* data, size_t len, int flush)
// Probably shouldn't be able to happen, but possible as a
// boundary condition: if the last call to inflate exactly
// filled the output buffer, it's possible that the next
- // call to inflate could have nothing to do.
+ // call to inflate could have nothing to do. There are PDF
+ // files in the wild that have this error (including at
+ // least one in qpdf's test suite). In some cases, we want
+ // to know about this, because it indicates incorrect
+ // compression, so call a callback if provided.
+ this->warn(
+ "input stream is complete but output may still be valid",
+ err);
done = true;
break;
@@ -231,8 +253,15 @@ Pl_Flate::finish()
}
catch (std::exception& e)
{
- this->getNext()->finish();
- throw e;
+ try
+ {
+ this->getNext()->finish();
+ }
+ catch (...)
+ {
+ // ignore secondary exception
+ }
+ throw std::runtime_error(e.what());
}
this->getNext()->finish();
}