8152672: IIOException while getting second image properties for JPEG
authorjdv
Fri, 01 Jul 2016 13:58:55 +0530
changeset 39545 1b92907cf159
parent 39544 263c59f6ca01
child 39546 3700a488c267
8152672: IIOException while getting second image properties for JPEG Reviewed-by: prr, flar Contributed-by: jayathirth.d.v@oracle.com
jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
jdk/test/javax/imageio/plugins/jpeg/JpegMultipleEOI.jpg
jdk/test/javax/imageio/plugins/jpeg/JpegMultipleEOITest.java
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java	Fri Jul 01 10:54:18 2016 +0530
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java	Fri Jul 01 13:58:55 2016 +0530
@@ -519,28 +519,129 @@
     /**
      * Skip over a complete image in the stream, leaving the stream
      * positioned such that the next byte to be read is the first
-     * byte of the next image.  For JPEG, this means that we read
+     * byte of the next image. For JPEG, this means that we read
      * until we encounter an EOI marker or until the end of the stream.
-     * If the stream ends before an EOI marker is encountered, an
-     * IndexOutOfBoundsException is thrown.
+     * We can find data same as EOI marker in some headers
+     * or comments, so we have to skip bytes related to these headers.
+     * If the stream ends before an EOI marker is encountered,
+     * an IndexOutOfBoundsException is thrown.
      */
     private void skipImage() throws IOException {
         if (debug) {
             System.out.println("skipImage called");
         }
+        // verify if image starts with an SOI marker
+        int initialFF = iis.read();
+        if (initialFF == 0xff) {
+            int soiMarker = iis.read();
+            if (soiMarker != JPEG.SOI) {
+                throw new IOException("skipImage : Invalid image doesn't "
+                        + "start with SOI marker");
+            }
+        } else {
+            throw new IOException("skipImage : Invalid image doesn't start "
+                    + "with 0xff");
+        }
         boolean foundFF = false;
+        String IOOBE = "skipImage : Reached EOF before we got EOI marker";
+        int markerLength = 2;
         for (int byteval = iis.read();
              byteval != -1;
              byteval = iis.read()) {
 
             if (foundFF == true) {
-                if (byteval == JPEG.EOI) {
-                    return;
+                switch (byteval) {
+                    case JPEG.EOI:
+                        if (debug) {
+                            System.out.println("skipImage : Found EOI at " +
+                                    (iis.getStreamPosition() - markerLength));
+                        }
+                        return;
+                    case JPEG.SOI:
+                        throw new IOException("skipImage : Found extra SOI"
+                                + " marker before getting to EOI");
+                    case 0:
+                    // markers which doesn't contain length data
+                    case JPEG.RST0:
+                    case JPEG.RST1:
+                    case JPEG.RST2:
+                    case JPEG.RST3:
+                    case JPEG.RST4:
+                    case JPEG.RST5:
+                    case JPEG.RST6:
+                    case JPEG.RST7:
+                    case JPEG.TEM:
+                        break;
+                    // markers which contains length data
+                    case JPEG.SOF0:
+                    case JPEG.SOF1:
+                    case JPEG.SOF2:
+                    case JPEG.SOF3:
+                    case JPEG.DHT:
+                    case JPEG.SOF5:
+                    case JPEG.SOF6:
+                    case JPEG.SOF7:
+                    case JPEG.JPG:
+                    case JPEG.SOF9:
+                    case JPEG.SOF10:
+                    case JPEG.SOF11:
+                    case JPEG.DAC:
+                    case JPEG.SOF13:
+                    case JPEG.SOF14:
+                    case JPEG.SOF15:
+                    case JPEG.SOS:
+                    case JPEG.DQT:
+                    case JPEG.DNL:
+                    case JPEG.DRI:
+                    case JPEG.DHP:
+                    case JPEG.EXP:
+                    case JPEG.APP0:
+                    case JPEG.APP1:
+                    case JPEG.APP2:
+                    case JPEG.APP3:
+                    case JPEG.APP4:
+                    case JPEG.APP5:
+                    case JPEG.APP6:
+                    case JPEG.APP7:
+                    case JPEG.APP8:
+                    case JPEG.APP9:
+                    case JPEG.APP10:
+                    case JPEG.APP11:
+                    case JPEG.APP12:
+                    case JPEG.APP13:
+                    case JPEG.APP14:
+                    case JPEG.APP15:
+                    case JPEG.COM:
+                        // read length of header from next 2 bytes
+                        int lengthHigherBits, lengthLowerBits, length;
+                        lengthHigherBits = iis.read();
+                        if (lengthHigherBits != (-1)) {
+                            lengthLowerBits = iis.read();
+                            if (lengthLowerBits != (-1)) {
+                                length = (lengthHigherBits << 8) |
+                                        lengthLowerBits;
+                                // length contains already read 2 bytes
+                                length -= 2;
+                            } else {
+                                throw new IndexOutOfBoundsException(IOOBE);
+                            }
+                        } else {
+                            throw new IndexOutOfBoundsException(IOOBE);
+                        }
+                        // skip the length specified in marker
+                        iis.skipBytes(length);
+                        break;
+                    case (-1):
+                        throw new IndexOutOfBoundsException(IOOBE);
+                    default:
+                        throw new IOException("skipImage : Invalid marker "
+                                + "starting with ff "
+                                + Integer.toHexString(byteval));
                 }
             }
-            foundFF = (byteval == 0xff) ? true : false;
+            foundFF = (byteval == 0xff);
         }
-        throw new IndexOutOfBoundsException();
+        throw new IndexOutOfBoundsException(IOOBE);
     }
 
     /**
Binary file jdk/test/javax/imageio/plugins/jpeg/JpegMultipleEOI.jpg has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/jpeg/JpegMultipleEOITest.java	Fri Jul 01 13:58:55 2016 +0530
@@ -0,0 +1,75 @@
+/*
+ * 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     8152672
+ * @summary When jpeg file has more than one set of EOI-SOI markers,
+ *          test verifies whether we calculate EOI markers of all images
+ *          properly skipping EOI markers present in application headers.
+ * @run     main JpegMultipleEOITest
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
+public class JpegMultipleEOITest {
+    public static void main (String[] args) throws IOException {
+        Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
+        ImageReader reader = null;
+        while(readers.hasNext()) {
+            reader = (ImageReader)readers.next();
+            if(reader.canReadRaster()) {
+                break;
+            }
+        }
+
+        if (reader != null) {
+            String fileName = "JpegMultipleEOI.jpg";
+            String sep = System.getProperty("file.separator");
+            String dir = System.getProperty("test.src", ".");
+            String filePath = dir+sep+fileName;
+            System.out.println("Test file: " + filePath);
+            File imageFile = new File(filePath);
+            ImageInputStream stream = ImageIO.
+                createImageInputStream(imageFile);
+            reader.setInput(stream);
+            int pageNum = 1;
+            try {
+                // read width of image index 1
+                reader.getWidth(pageNum + reader.getMinIndex());
+            } catch (IndexOutOfBoundsException e) {
+                /*
+                 * do nothing, we are supposed to get IndexOutofBoundsException
+                 * as number of image is 1 and we are trying to get width of
+                 * second image. But we should not see IIOException with
+                 * message "Not a JPEG file: starts with 0xff 0xe2"
+                 */
+            }
+        }
+    }
+}