OpenJDK / portola / portola
changeset 40438:4abe842e6c48
8145014: "IIOException: Couldn't seek!" when calling TIFFImageReader.getNumImages()
Summary: In locateImage() break and decrement image count for zero-entry IFDs and on encountering an EOF.
Reviewed-by: prr
author | bpb |
---|---|
date | Thu, 11 Aug 2016 11:35:47 -0700 |
parents | 3b33b57c0096 |
children | acd9a7547e59 |
files | jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java jdk/test/javax/imageio/plugins/tiff/BogusSecondImageTest.java |
diffstat | 2 files changed, 214 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Thu Aug 11 10:37:50 2016 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java Thu Aug 11 11:35:47 2016 -0700 @@ -35,6 +35,7 @@ import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; +import java.io.EOFException; import java.io.IOException; import java.nio.ByteOrder; import java.util.ArrayList; @@ -189,8 +190,8 @@ // Seek to start of first IFD long offset = stream.readUnsignedInt(); + stream.seek(offset); imageStartPosition.add(Long.valueOf(offset)); - stream.seek(offset); } catch (IOException e) { throw new IIOException("I/O error reading header!", e); } @@ -201,10 +202,10 @@ private int locateImage(int imageIndex) throws IIOException { readHeader(); + // Find closest known index + int index = Math.min(imageIndex, imageStartPosition.size() - 1); + try { - // Find closest known index - int index = Math.min(imageIndex, imageStartPosition.size() - 1); - // Seek to that position Long l = imageStartPosition.get(index); stream.seek(l.longValue()); @@ -212,6 +213,11 @@ // Skip IFDs until at desired index or last image found while (index < imageIndex) { int count = stream.readUnsignedShort(); + // If zero-entry IFD, decrement the index and exit the loop + if (count == 0) { + imageIndex = index > 0 ? index - 1 : 0; + break; + } stream.skipBytes(12 * count); long offset = stream.readUnsignedInt(); @@ -219,12 +225,17 @@ return index; } + stream.seek(offset); imageStartPosition.add(Long.valueOf(offset)); - stream.seek(offset); ++index; } - } catch (IOException e) { - throw new IIOException("Couldn't seek!", e); + } catch (EOFException eofe) { + forwardWarningMessage("Ignored " + eofe); + + // Ran off the end of stream: decrement index + imageIndex = index > 0 ? index - 1 : 0; + } catch (IOException ioe) { + throw new IIOException("Couldn't seek!", ioe); } if (currIndex != imageIndex) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/plugins/tiff/BogusSecondImageTest.java Thu Aug 11 11:35:47 2016 -0700 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8145014 + * @summary Verify reader correctly fails for zero-entry IFDs and EOFs + * encountered in locateImage(). + */ + +import java.awt.Image; +import java.awt.image.*; +import java.io.*; +import java.util.Iterator; +import javax.imageio.*; +import javax.imageio.stream.*; + +public class BogusSecondImageTest { + public static void main(String[] args) throws Throwable { + int failures = 0; + + try { + testZeroEntryIFD(); + } catch (Exception e) { + System.out.printf("Failed testZeroEntryIFD: %s%n", e); + failures++; + } + + try { + testOutOfStreamIFD(); + } catch (Exception e) { + System.out.printf("Failed testOutOfStreamIFD: %s%n", e); + failures++; + } + + if (failures == 0) { + System.out.println("Test succeeded"); + } else { + throw new RuntimeException + ("Test failed with " + failures + " errors"); + } + } + + private static void testZeroEntryIFD() throws Exception { + // Create an image. + File f = createImageFile(); + + ImageOutputStream s = new FileImageOutputStream(f); + long length = s.length(); + + // Skip the endianness and magic number + s.skipBytes(4); + + // Read and seek to offset of 0th IFD + long ifd0 = s.readUnsignedInt(); + s.seek(ifd0); + + // Read number of 0th IFD entries and skip over them + int entries0 = s.readUnsignedShort(); + s.skipBytes(12*entries0); + + // Write the offset of the 1st IFD as the current file length + s.write((int)length); + + // Seek to the 1st IFD and write a zero entry count to it + s.seek(length); + s.writeShort(0); + s.close(); + + try { + Load(f); + } catch (Exception e) { + throw e; + } finally { + f.delete(); + } + } + + private static void testOutOfStreamIFD() throws Exception { + // Create an image. + File f = createImageFile(); + ImageOutputStream s = new FileImageOutputStream(f); + long length = s.length(); + + // Skip the endianness and magic number + s.skipBytes(4); + + // Read and seek to offset of 0th IFD + long ifd0 = s.readUnsignedInt(); + s.seek(ifd0); + + // Read number of 0th IFD entries and skip over them + int entries0 = s.readUnsignedShort(); + s.skipBytes(12*entries0); + + // Write the offset of the 1st IFD as the current file length + 7 + s.write((int)length + 7); + s.close(); + + try { + Load(f); + } catch (Exception e) { + throw e; + } finally { + f.delete(); + } + } + + private static File createImageFile() throws Exception { + BufferedImage im = + new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY); + File f = File.createTempFile("BogusSecondImage", "tif", new File(".")); + f.deleteOnExit(); + if (!ImageIO.write(im, "TIFF", f)) { + throw new RuntimeException("Failed to write " + f); + } + return f; + } + + private final static boolean printTrace = false; + + public static void Load(File file) { + if (!file.exists()) { + throw new IllegalArgumentException(file + " does not exist"); + } else if (!file.isFile()) { + throw new IllegalArgumentException(file + " is not a regular file"); + } else if (!file.canRead()) { + throw new IllegalArgumentException(file + " cannot be read"); + } + + ImageInputStream input = null; + try { + input = ImageIO.createImageInputStream(file); + } catch (Throwable e) { + System.err.println("NOK: createImageInputStream()\t" + e.getMessage()); + if (printTrace) { e.printStackTrace(); } + return; + } + + Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("TIFF"); + if (!readers.hasNext()) { throw new RuntimeException("No readers available for TIFF"); } + ImageReader reader = readers.next(); + reader.setInput(input); + + Image images[] = null; + int numImages = 0; + + int failures = 0; + try { + numImages = reader.getNumImages(true); + images = new Image[numImages]; + } catch (Throwable e) { + failures++; + System.err.println("NOK: getNumImages()\t" + e.getMessage()); + if (printTrace) { e.printStackTrace(); } + } + System.out.printf("numImages %d%n", numImages); + + for (int i = 0; i < numImages; i++) { + System.out.printf("reading image %d%n", i); + try { + images[i] = reader.read(i); + } catch (Throwable e) { + failures++; + System.err.println("NOK: read()\t" + e.getMessage()); + if (printTrace) { e.printStackTrace(); } + } + } + + if (failures == 0) { + System.err.println("OK"); + } else { + throw new RuntimeException("NOK"); + } + } +}