diff --git a/Tests/images/bw_gradient.imt b/Tests/images/bw_gradient.imt new file mode 100644 index 00000000000..d765cf95fac Binary files /dev/null and b/Tests/images/bw_gradient.imt differ diff --git a/Tests/test_file_imt.py b/Tests/test_file_imt.py new file mode 100644 index 00000000000..f56acc42949 --- /dev/null +++ b/Tests/test_file_imt.py @@ -0,0 +1,19 @@ +import io + +import pytest + +from PIL import Image, ImtImagePlugin + +from .helper import assert_image_equal_tofile + + +def test_sanity(): + with Image.open("Tests/images/bw_gradient.imt") as im: + assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") + + +@pytest.mark.parametrize("data", (b"\n", b"\n-", b"width 1\n")) +def test_invalid_file(data): + with io.BytesIO(data) as fp: + with pytest.raises(SyntaxError): + ImtImagePlugin.ImtImageFile(fp) diff --git a/src/PIL/ImtImagePlugin.py b/src/PIL/ImtImagePlugin.py index 5790acdaf52..dc707801274 100644 --- a/src/PIL/ImtImagePlugin.py +++ b/src/PIL/ImtImagePlugin.py @@ -39,15 +39,19 @@ def _open(self): # Quick rejection: if there's not a LF among the first # 100 bytes, this is (probably) not a text header. - if b"\n" not in self.fp.read(100): + buffer = self.fp.read(100) + if b"\n" not in buffer: raise SyntaxError("not an IM file") - self.fp.seek(0) xsize = ysize = 0 while True: - s = self.fp.read(1) + if buffer: + s = buffer[:1] + buffer = buffer[1:] + else: + s = self.fp.read(1) if not s: break @@ -55,7 +59,12 @@ def _open(self): # image data begins self.tile = [ - ("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1)) + ( + "raw", + (0, 0) + self.size, + self.fp.tell() - len(buffer), + (self.mode, 0, 1), + ) ] break @@ -63,8 +72,11 @@ def _open(self): else: # read key/value pair - # FIXME: dangerous, may read whole file - s = s + self.fp.readline() + if b"\n" not in buffer: + buffer += self.fp.read(100) + lines = buffer.split(b"\n") + s += lines.pop(0) + buffer = b"\n".join(lines) if len(s) == 1 or len(s) > 100: break if s[0] == ord(b"*"): @@ -74,13 +86,13 @@ def _open(self): if not m: break k, v = m.group(1, 2) - if k == "width": + if k == b"width": xsize = int(v) self._size = xsize, ysize - elif k == "height": + elif k == b"height": ysize = int(v) self._size = xsize, ysize - elif k == "pixel" and v == "n8": + elif k == b"pixel" and v == b"n8": self.mode = "L"