diff options
-rw-r--r-- | include/qpdf/QPDF.hh | 1 | ||||
-rw-r--r-- | libqpdf/QPDF.cc | 84 |
2 files changed, 46 insertions, 39 deletions
diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index ead09a0a..61510c17 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1009,6 +1009,7 @@ class QPDF QPDFObjectHandle readTrailer(); QPDFObjectHandle readObject(std::string const& description, QPDFObjGen og); void readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); + void validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset); QPDFObjectHandle readObjectInStream(std::shared_ptr<InputSource>, QPDFObjGen og); size_t recoverStreamLength( std::shared_ptr<InputSource> input, QPDFObjGen const& og, qpdf_offset_t stream_offset); diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 3fbb4da1..05929764 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1324,6 +1324,47 @@ QPDF::readObject(std::string const& description, QPDFObjGen og) void QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) { + validateStreamLineEnd(object, og, offset); + + // Must get offset before accessing any additional objects since resolving a previously + // unresolved indirect object will change file position. + qpdf_offset_t stream_offset = m->file->tell(); + size_t length = 0; + + try { + auto length_obj = object.getKey("/Length"); + + if (!length_obj.isInteger()) { + if (length_obj.isNull()) { + QTC::TC("qpdf", "QPDF stream without length"); + throw damagedPDF(offset, "stream dictionary lacks /Length key"); + } + QTC::TC("qpdf", "QPDF stream length not integer"); + throw damagedPDF(offset, "/Length key in stream dictionary is not an integer"); + } + + length = toS(length_obj.getUIntValue()); + // Seek in two steps to avoid potential integer overflow + m->file->seek(stream_offset, SEEK_SET); + m->file->seek(toO(length), SEEK_CUR); + if (!readToken(m->file).isWord("endstream")) { + QTC::TC("qpdf", "QPDF missing endstream"); + throw damagedPDF("expected endstream"); + } + } catch (QPDFExc& e) { + if (m->attempt_recovery) { + warn(e); + length = recoverStreamLength(m->file, og, stream_offset); + } else { + throw; + } + } + object = newIndirect(og, QPDF_Stream::create(this, og, object, stream_offset, length)); +} + +void +QPDF::validateStreamLineEnd(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) +{ // The PDF specification states that the word "stream" should be followed by either a carriage // return and a newline or by a newline alone. It specifically disallowed following it by a // carriage return alone since, in that case, there would be no way to tell whether the NL in a @@ -1336,12 +1377,12 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) if (m->file->read(&ch, 1) == 0) { // A premature EOF here will result in some other problem that will get reported at // another time. - break; + return; } if (ch == '\n') { // ready to read stream data QTC::TC("qpdf", "QPDF stream with NL only"); - break; + return; } if (ch == '\r') { // Read another character @@ -1358,52 +1399,17 @@ QPDF::readStream(QPDFObjectHandle& object, QPDFObjGen og, qpdf_offset_t offset) m->file->tell(), "stream keyword followed by carriage return only")); } } - break; + return; } if (!QUtil::is_space(ch)) { QTC::TC("qpdf", "QPDF stream without newline"); m->file->unreadCh(ch); warn(damagedPDF( m->file->tell(), "stream keyword not followed by proper line terminator")); - break; + return; } warn(damagedPDF(m->file->tell(), "stream keyword followed by extraneous whitespace")); } - - // Must get offset before accessing any additional objects since resolving a previously - // unresolved indirect object will change file position. - qpdf_offset_t stream_offset = m->file->tell(); - size_t length = 0; - - try { - auto length_obj = object.getKey("/Length"); - - if (!length_obj.isInteger()) { - if (length_obj.isNull()) { - QTC::TC("qpdf", "QPDF stream without length"); - throw damagedPDF(offset, "stream dictionary lacks /Length key"); - } - QTC::TC("qpdf", "QPDF stream length not integer"); - throw damagedPDF(offset, "/Length key in stream dictionary is not an integer"); - } - - length = toS(length_obj.getUIntValue()); - // Seek in two steps to avoid potential integer overflow - m->file->seek(stream_offset, SEEK_SET); - m->file->seek(toO(length), SEEK_CUR); - if (!readToken(m->file).isWord("endstream")) { - QTC::TC("qpdf", "QPDF missing endstream"); - throw damagedPDF("expected endstream"); - } - } catch (QPDFExc& e) { - if (m->attempt_recovery) { - warn(e); - length = recoverStreamLength(m->file, og, stream_offset); - } else { - throw; - } - } - object = newIndirect(og, QPDF_Stream::create(this, og, object, stream_offset, length)); } QPDFObjectHandle |