diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index d8f97562c6c..997c3bfd8d9 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -99,22 +99,39 @@ public class MultiPixelPackedSampleModel extends SampleModel * either {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_USHORT}, or * {@code DataBuffer.TYPE_INT} + * @throws IllegalArgumentException if either {@code w} or {@code h} + * is less than or equal to 0 + * @throws RasterFormatException if the number of bits per pixel + * is not a power of 2 or if a power of 2 number of + * pixels do not fit in one data element. */ public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) { - this(dataType,w,h, - numberOfBits, - (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/ - DataBuffer.getDataTypeSize(dataType), - 0); + long size = (long)w * h; + if (w <= 0 || h <= 0) { + throw new IllegalArgumentException("Width ("+w+") and height ("+ + h+") must be > 0"); + } + if (size > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Dimensions (width="+w+ + " height="+h+") are too large"); + } + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT && - dataType != DataBuffer.TYPE_INT) { - throw new IllegalArgumentException("Unsupported data type "+ + dataType != DataBuffer.TYPE_INT) + { + throw new IllegalArgumentException("Unsupported dataType: "+ dataType); } + long sls = ((long)w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/ + DataBuffer.getDataTypeSize(dataType); + if (sls > Integer.MAX_VALUE) { + throw new RasterFormatException("Pixels do not fit"); + } + this(dataType, w, h, numberOfBits, (int)sls, 0); } /** @@ -130,15 +147,23 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param scanlineStride the line stride of the image data * @param dataBitOffset the data bit offset for the region of image * data described - * @throws RasterFormatException if the number of bits per pixel - * is not a power of 2 or if a power of 2 number of - * pixels do not fit in one data element. - * @throws IllegalArgumentException if {@code w} or - * {@code h} is not greater than 0 * @throws IllegalArgumentException if {@code dataType} is not * either {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_USHORT}, or * {@code DataBuffer.TYPE_INT} + * @throws IllegalArgumentException if either {@code w} or {@code h} + * is less than or equal to 0 + * @throws IllegalArgumentException if {@code scanlineStride} + * is less than or equal to 0 + * @throws RasterFormatException if + * {@code ((numberOfBits * (long)w) + DataBuffer.getDataTypeSize(dataType) - 1) + * / DataBuffer.getDataTypeSize(dataType)} + * is greater than {@code scanlineStride} + * @throws RasterFormatException if the number of bits per pixel + * is not a power of 2 or if a power of 2 number of + * pixels do not fit in one data element. + * @throws IllegalArgumentException if {@code dataBitOffset} is less than zero, + * or not a multiple of {@code numberOfBits}. */ public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, @@ -151,11 +176,27 @@ public class MultiPixelPackedSampleModel extends SampleModel throw new IllegalArgumentException("Unsupported data type "+ dataType); } + if ((numberOfBits <= 0) || ((numberOfBits & (numberOfBits - 1)) != 0)) { + throw new RasterFormatException("numberOfBits per pixel must be a power of 2"); + } + if (scanlineStride <= 0) { + throw new IllegalArgumentException("scanlineStride must be > 0"); + } + int dataTypeSize = DataBuffer.getDataTypeSize(dataType); + if ((((numberOfBits * (long)w) + dataTypeSize - 1) / dataTypeSize) > scanlineStride) { + throw new RasterFormatException("scanlineStride is too small for width"); + } + if (dataBitOffset < 0) { + throw new IllegalArgumentException("dataBitOffset must be >= 0"); + } + if ((dataBitOffset % numberOfBits) != 0) { + throw new IllegalArgumentException("dataBitOffset must be a multiple of bits per pixel"); + } this.dataType = dataType; this.pixelBitStride = numberOfBits; this.scanlineStride = scanlineStride; this.dataBitOffset = dataBitOffset; - this.dataElementSize = DataBuffer.getDataTypeSize(dataType); + this.dataElementSize = dataTypeSize; this.pixelsPerDataElement = dataElementSize/numberOfBits; if (pixelsPerDataElement*numberOfBits != dataElementSize) { throw new RasterFormatException("MultiPixelPackedSampleModel " + @@ -320,22 +361,12 @@ public class MultiPixelPackedSampleModel extends SampleModel * subset of the bands of this * {@code MultiPixelPackedSampleModel}. Since a * {@code MultiPixelPackedSampleModel} only has one band, the - * bands argument must have a length of one and indicate the zeroth - * band. - * @param bands the specified bands - * @return a new {@code SampleModel} with a subset of bands of + * bands argument is ignored. + * @param bands the specified bands (ignored) + * @return a new {@code SampleModel} with the same bands as * this {@code MultiPixelPackedSampleModel}. - * @throws RasterFormatException if the number of bands requested - * is not one. - * @throws IllegalArgumentException if {@code w} or - * {@code h} is not greater than 0 */ public SampleModel createSubsetSampleModel(int[] bands) { - if (bands != null) { - if (bands.length != 1) - throw new RasterFormatException("MultiPixelPackedSampleModel has " - + "only one band."); - } SampleModel sm = createCompatibleSampleModel(width, height); return sm; } diff --git a/test/jdk/java/awt/image/MultiPixelPackedSampleModelConstructor.java b/test/jdk/java/awt/image/MultiPixelPackedSampleModelConstructor.java new file mode 100644 index 00000000000..182fc93cba0 --- /dev/null +++ b/test/jdk/java/awt/image/MultiPixelPackedSampleModelConstructor.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2026, 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. + */ + +import static java.awt.image.DataBuffer.TYPE_BYTE; +import static java.awt.image.DataBuffer.TYPE_INT; +import static java.awt.image.DataBuffer.TYPE_SHORT; +import static java.awt.image.DataBuffer.TYPE_USHORT; + +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.RasterFormatException; + +/* + * @test + * @bug 8381007 + * @summary test MultiPixelPackedSampleModel Constructors + */ + +public class MultiPixelPackedSampleModelConstructor { + + public static void main(String[] args) { + for (Args4 a : args4) { + test4(a); + } + for (Args6 a : args6) { + test6(a); + } + + // Also verify createSubsetSampleModel ignores bands. + MultiPixelPackedSampleModel m = + new MultiPixelPackedSampleModel(TYPE_BYTE, 1, 1, 1); + int[] bands = new int[5]; + m.createSubsetSampleModel(bands); + } + + static record Args4(int dType, int w, int h, int bits, Class eType) { } + + static final Args4[] args4 = { + new Args4(TYPE_BYTE, 1, 1, -1, RasterFormatException.class), + new Args4(TYPE_BYTE, 1, 1, 0, RasterFormatException.class), + new Args4(TYPE_BYTE, 1, 1, 1, null), + new Args4(TYPE_BYTE, 1, 1, 3, RasterFormatException.class), + new Args4(TYPE_BYTE, 1, 1, 4, null), + new Args4(TYPE_BYTE, 1, 1, 16, RasterFormatException.class), + new Args4(TYPE_BYTE, -1, 1, 1, IllegalArgumentException.class), + new Args4(TYPE_SHORT, -1, 1, 1, IllegalArgumentException.class), + new Args4(TYPE_SHORT, 1, 1, 16, IllegalArgumentException.class), + new Args4(TYPE_USHORT, 1, 1, 16, null), + new Args4(TYPE_INT, 1, 1, 16, null), + new Args4(TYPE_BYTE, 1, 30, 0, RasterFormatException.class), + new Args4(TYPE_BYTE, 0, 1, 4, IllegalArgumentException.class), + new Args4(TYPE_BYTE, 1<<29, 1, 4, null), + new Args4(TYPE_BYTE, 1<<30, 1, 16, RasterFormatException.class), + new Args4(TYPE_BYTE, 32, 1, 1<<30, RasterFormatException.class), + new Args4(99, 8, 1, 1, IllegalArgumentException.class), + }; + + static record Args6(int dType, int w, int h, int bits, int stride, int bitOffset, Class eType) { } + + static final Args6[] args6 = { + new Args6(TYPE_BYTE, 1, 1, -1, 1, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 1, 1, 0, 1, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 1, 1, 1, 1, 0, null), + new Args6(TYPE_BYTE, 1, 1, 3, 1, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 1, 1, 4, 1, 0, null), + new Args6(TYPE_BYTE, 1, 1, 16, 2, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 9, 1, 1, 1, 0, RasterFormatException.class), + new Args6(TYPE_SHORT, 1, 1, 16, 2, 0, IllegalArgumentException.class), + new Args6(TYPE_USHORT, 1, 1, 16, 2, 0, null), + new Args6(TYPE_INT, 1, 1, 16, 1, 0, null), + new Args6(TYPE_BYTE, 1, 30, 0, 4, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 0, 1, 4, 1, 0, IllegalArgumentException.class), + new Args6(TYPE_BYTE, 1, 1, 2, 1, 0, null), + new Args6(TYPE_BYTE, 4, 1, 4, 1, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 1, 1, 2, 1, 1, IllegalArgumentException.class), + new Args6(TYPE_BYTE, 1, 1, 2, 1, -1, IllegalArgumentException.class), + new Args6(TYPE_BYTE, 1, 1, 1, -1, 1, IllegalArgumentException.class), + new Args6(TYPE_BYTE, -1, 1, 1, 1, 1, IllegalArgumentException.class), + new Args6(TYPE_BYTE, 1, 1, 1, 1, 1, null), + new Args6(TYPE_INT, 77777777, 2, 32, 1, 0, RasterFormatException.class), + new Args6(TYPE_BYTE, 1<<29, 1, 4, 1<<28, 0, null), + new Args6(99, 8, 1, 1, 1, 0, IllegalArgumentException.class), + }; + + static void test4(Args4 a) { + try { + new MultiPixelPackedSampleModel(a.dType, a.w, a.h, a.bits); + } catch (Exception e) { + if (a.eType == null || !(a.eType.isInstance(e))) { + throw new RuntimeException("failed for " + a + " got " + e); + } else { + return; + } + } + if (a.eType != null) { + throw new RuntimeException("No exception for " + a); + } + } + + + static void test6(Args6 a) { + try { + new MultiPixelPackedSampleModel(a.dType, a.w, a.h, a.bits, a.stride, a.bitOffset); + } catch (Exception e) { + if (a.eType == null || !(a.eType.isInstance(e))) { + throw new RuntimeException("failed for " + a + " got " + e); + } else { + return; + } + } + if (a.eType != null) { + throw new RuntimeException("No exception for " + a); + } + } +}