diff --git a/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java b/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java index 1f0068c2048b25a21ff3326f8ed208ff8ce81630..36865df60d740d9ab7e7a2dd03d406e4c1bd7956 100644 --- a/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java +++ b/src/share/classes/com/sun/imageio/plugins/common/ReaderUtil.java @@ -27,6 +27,8 @@ package com.sun.imageio.plugins.common; import java.awt.Point; import java.awt.Rectangle; +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; /** * This class contains utility methods that may be useful to ImageReader @@ -198,4 +200,17 @@ public class ReaderUtil { vals, 1); return vals; } + + public static int readMultiByteInteger(ImageInputStream iis) + throws IOException + { + int value = iis.readByte(); + int result = value & 0x7f; + while((value & 0x80) == 0x80) { + result <<= 7; + value = iis.readByte(); + result |= (value & 0x7f); + } + return result; + } } diff --git a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java index e8da025b3cb0a9ccd90b36ac386a86e47e96ff05..707a5419256b86bd7829d97b16d3dd98a62f9373 100644 --- a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java +++ b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReader.java @@ -45,6 +45,7 @@ import java.util.ArrayList; import java.util.Iterator; import com.sun.imageio.plugins.common.I18N; +import com.sun.imageio.plugins.common.ReaderUtil; /** This class is the Java Image IO plugin reader for WBMP images. * It may subsample the image, clip the image, @@ -141,11 +142,11 @@ public class WBMPImageReader extends ImageReader { metadata.wbmpType = wbmpType; // Read image width - width = readMultiByteInteger(); + width = ReaderUtil.readMultiByteInteger(iis); metadata.width = width; // Read image height - height = readMultiByteInteger(); + height = ReaderUtil.readMultiByteInteger(iis); metadata.height = height; gotHeader = true; @@ -311,17 +312,6 @@ public class WBMPImageReader extends ImageReader { gotHeader = false; } - private int readMultiByteInteger() throws IOException { - int value = iis.readByte(); - int result = value & 0x7f; - while((value & 0x80) == 0x80) { - result <<= 7; - value = iis.readByte(); - result |= (value & 0x7f); - } - return result; - } - /* * This method verifies that given byte is valid wbmp type marker. * At the moment only 0x0 marker is described by wbmp spec. diff --git a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java index 2d882ab6b2ce9b8c46f4c22ef5fb53689ade8380..cb4f3bce205b77c3d73fcb691ffadb840049e1d4 100644 --- a/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java +++ b/src/share/classes/com/sun/imageio/plugins/wbmp/WBMPImageReaderSpi.java @@ -33,9 +33,13 @@ import javax.imageio.spi.ServiceRegistry; import java.io.IOException; import javax.imageio.ImageReader; import javax.imageio.IIOException; +import com.sun.imageio.plugins.common.ReaderUtil; public class WBMPImageReaderSpi extends ImageReaderSpi { + private static final int MAX_WBMP_WIDTH = 1024; + private static final int MAX_WBMP_HEIGHT = 768; + private static String [] writerSpiNames = {"com.sun.imageio.plugins.wbmp.WBMPImageWriterSpi"}; private static String[] formatNames = {"wbmp", "WBMP"}; @@ -79,16 +83,44 @@ public class WBMPImageReaderSpi extends ImageReaderSpi { } ImageInputStream stream = (ImageInputStream)source; - byte[] b = new byte[3]; stream.mark(); - stream.readFully(b); + int type = stream.readByte(); // TypeField + int fixHeaderField = stream.readByte(); + // check WBMP "header" + if (type != 0 || fixHeaderField != 0) { + // while WBMP reader does not support ext WBMP headers + stream.reset(); + return false; + } + + int width = ReaderUtil.readMultiByteInteger(stream); + int height = ReaderUtil.readMultiByteInteger(stream); + // check image dimension + if (width <= 0 || height <= 0) { + stream.reset(); + return false; + } + + long dataLength = stream.length(); + if (dataLength == -1) { + // We can't verify that amount of data in the stream + // corresponds to image dimension because we do not know + // the length of the data stream. + // Assuming that wbmp image are used for mobile devices, + // let's introduce an upper limit for image dimension. + // In case if exact amount of raster data is unknown, + // let's reject images with dimension above the limit. + stream.reset(); + return (width < MAX_WBMP_WIDTH) && (height < MAX_WBMP_HEIGHT); + } + + dataLength -= stream.getStreamPosition(); stream.reset(); - return ((b[0] == (byte)0) && // TypeField == 0 - b[1] == 0 && // FixHeaderField == 0xxx00000; not support ext header - ((b[2] & 0x8f) != 0 || (b[2] & 0x7f) != 0)); // First width byte - //XXX: b[2] & 0x8f) != 0 for the bug in Sony Ericsson encoder. + long scanSize = (width / 8) + ((width % 8) == 0 ? 0 : 1); + + return (dataLength == scanSize * height); } public ImageReader createReaderInstance(Object extension) diff --git a/test/javax/imageio/plugins/wbmp/CanDecodeTest.java b/test/javax/imageio/plugins/wbmp/CanDecodeTest.java new file mode 100644 index 0000000000000000000000000000000000000000..adaecdce419c80bacbb96c3bd6ff736394e52e0e --- /dev/null +++ b/test/javax/imageio/plugins/wbmp/CanDecodeTest.java @@ -0,0 +1,131 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 5101862 + * @summary Test verifies that SPI of WBMP image reader + * does not claims to be able to decode QT movies, + * tga images, or ico files. + * @run main CanDecodeTest + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Vector; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +public class CanDecodeTest { + + public static void main(String[] args) throws IOException { + ImageReader r = + ImageIO.getImageReadersByFormatName("WBMP").next(); + ImageReaderSpi spi = r.getOriginatingProvider(); + + Vector tests = getTestCases(); + for (TestCase t : tests) { + t.doTest(spi); + } + System.out.println("Test passed."); + } + + private static Vector getTestCases() { + Vector v = new Vector(4); + v.add(new TestCase("wbmp", new byte[]{(byte) 0x00, (byte) 0x00, + (byte) 0x60, (byte) 0x14}, 244, true)); + v.add(new TestCase("mov", new byte[]{(byte) 0x00, (byte) 0x00, + (byte) 0x07, (byte) 0xb5, (byte) 0x6d}, 82397, false)); + v.add(new TestCase("tga", new byte[]{(byte) 0x00, (byte) 0x00, + (byte) 0x0a, (byte) 0x00}, 39693, false)); + v.add(new TestCase("ico", new byte[]{(byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x00}, 1078, false)); + return v; + } + + private static class TestCase { + + private String title; + private byte[] header; + private int dataLength; + private boolean canDecode; + + public TestCase(String title, byte[] header, + int dataLength, boolean canDecode) { + this.title = title; + this.dataLength = dataLength; + this.header = header.clone(); + this.canDecode = canDecode; + + } + + public void doTest(ImageReaderSpi spi) throws IOException { + System.out.println("Test for " + title + + (canDecode ? " (can decode)" : " (can't decode)")); + System.out.print("As a stream..."); + ImageInputStream iis = + ImageIO.createImageInputStream(getDataStream()); + + if (spi.canDecodeInput(iis) != canDecode) { + throw new RuntimeException("Test failed: wrong decideion " + + "for stream data"); + } + System.out.println("OK"); + + System.out.print("As a file..."); + iis = ImageIO.createImageInputStream(getDataFile()); + if (spi.canDecodeInput(iis) != canDecode) { + throw new RuntimeException("Test failed: wrong decideion " + + "for file data"); + } + System.out.println("OK"); + } + + private byte[] getData() { + byte[] data = new byte[dataLength]; + Arrays.fill(data, (byte) 0); + System.arraycopy(header, 0, data, 0, header.length); + + return data; + } + public InputStream getDataStream() { + return new ByteArrayInputStream(getData()); + } + + public File getDataFile() throws IOException { + File f = File.createTempFile("wbmp_", "." + title, new File(".")); + FileOutputStream fos = new FileOutputStream(f); + fos.write(getData()); + fos.flush(); + fos.close(); + + return f; + } + } +}