diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java index ce42f658..096d99d9 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStream.java @@ -33,6 +33,7 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEG; import javax.imageio.IIOException; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStreamImpl; +import java.io.EOFException; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; @@ -41,7 +42,7 @@ import java.util.List; import static com.twelvemonkeys.lang.Validate.notNull; /** - * JPEGSegmentImageInputStream. + * ImageInputStream implementation that filters out certain JPEG segments. * * @author Harald Kuhr * @author last modified by $Author: haraldk$ @@ -174,7 +175,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl { else { stream.seek(segment.realStart + streamPos - segment.start); } - + return segment; } @@ -231,7 +232,15 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl { private void repositionAsNecessary() throws IOException { if (segment == null || streamPos < segment.start || streamPos >= segment.end()) { - fetchSegment(); + try { + fetchSegment(); + } + catch (EOFException ignore) { + // This might happen if the segment lengths in the stream are bad. + // We MUST leave internal state untouched in this case. + // We ignore this exception here, but client code will get + // an EOFException (or -1 return code) on subsequent reads. + } } } diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStreamTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStreamTest.java index edb4f0fe..e38bc75d 100644 --- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStreamTest.java +++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGSegmentImageInputStreamTest.java @@ -153,4 +153,29 @@ public class JPEGSegmentImageInputStreamTest { assertEquals(1061L, length); // Sanity check: same as file size, except padding and the filtered ICC_PROFILE segment } + + @Test + public void testEOFExceptionInSegmentParsingShouldNotCreateBadState() throws IOException { + ImageInputStream iis = new JPEGSegmentImageInputStream(ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/broken-no-sof-ascii-transfer-mode.jpg"))); + int fileLength = 2021; + + byte[] buffer = new byte[4096]; + + // NOTE: This is a simulation of how the native parts of com.sun...JPEGImageReader would read the image... + assertEquals(fileLength, iis.read(buffer, 0, buffer.length)); + assertEquals(fileLength, iis.getStreamPosition()); + + iis.seek(0x2012); // bad segment length, should have been 0x0012, not 0x2012 + assertEquals(0x2012, iis.getStreamPosition()); + + // So far, so good (but stream position is now really beyond EOF)... + + // This however, will blow up with an EOFException internally (but we'll return -1 to be good) + assertEquals(-1, iis.read(buffer, 0, buffer.length)); + assertEquals(0x2012, iis.getStreamPosition()); + + // Again, should just continue returning -1 for ever + assertEquals(-1, iis.read(buffer, 0, buffer.length)); + assertEquals(0x2012, iis.getStreamPosition()); + } }