diff --git a/Tests/test_pdfparser.py b/Tests/test_pdfparser.py index cba6cd05390..4c522eb7a50 100644 --- a/Tests/test_pdfparser.py +++ b/Tests/test_pdfparser.py @@ -1,6 +1,7 @@ from __future__ import annotations import time +import zlib import pytest @@ -95,6 +96,16 @@ def test_parsing() -> None: assert time.strftime("%Y%m%d%H%M%S", getattr(d, name)) == value +def test_pdfstream_flatedecode() -> None: + d = PdfDict({b"Filter": b"FlateDecode"}) + buf = zlib.compress(b"test") + s = PdfStream(d, buf) + assert s.decode() == b"test" + + with pytest.raises(ValueError, match="Decompressed data too large"): + s.decode(3) + + def test_pdf_repr() -> None: assert bytes(IndirectReference(1, 2)) == b"1 2 R" assert bytes(IndirectObjectDef(*IndirectReference(1, 2))) == b"1 2 obj" diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index e4e094e715a..c2e1568f969 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -10,6 +10,8 @@ import zlib from typing import Any, NamedTuple +from . import ImageFile + TYPE_CHECKING = False if TYPE_CHECKING: from typing import IO @@ -320,17 +322,18 @@ def __init__(self, dictionary: PdfDict, buf: bytes) -> None: self.dictionary = dictionary self.buf = buf - def decode(self) -> bytes: + def decode(self, max_length: int = ImageFile.SAFEBLOCK) -> bytes: try: filter = self.dictionary[b"Filter"] except KeyError: return self.buf if filter == b"FlateDecode": - try: - expected_length = self.dictionary[b"DL"] - except KeyError: - expected_length = self.dictionary[b"Length"] - return zlib.decompress(self.buf, bufsize=int(expected_length)) + dobj = zlib.decompressobj() + plaintext = dobj.decompress(self.buf, max_length) + if dobj.unconsumed_tail: + msg = "Decompressed data too large" + raise ValueError(msg) + return plaintext else: msg = f"stream filter {repr(filter)} unknown/unsupported" raise NotImplementedError(msg)