diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java index 5b0e8a55f81..d814777aa4e 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -114,13 +114,14 @@ public ICC_ColorSpace (ICC_Profile profile) { int profileClass = profile.getProfileClass(); /* REMIND - is NAMEDCOLOR OK? */ - if ((profileClass != ICC_Profile.CLASS_INPUT) && - (profileClass != ICC_Profile.CLASS_DISPLAY) && - (profileClass != ICC_Profile.CLASS_OUTPUT) && - (profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION) && - (profileClass != ICC_Profile.CLASS_NAMEDCOLOR) && - (profileClass != ICC_Profile.CLASS_ABSTRACT)) { - throw new IllegalArgumentException("Invalid profile type"); + if (profileClass != ICC_Profile.CLASS_INPUT + && profileClass != ICC_Profile.CLASS_DISPLAY + && profileClass != ICC_Profile.CLASS_OUTPUT + && profileClass != ICC_Profile.CLASS_DEVICELINK + && profileClass != ICC_Profile.CLASS_COLORSPACECONVERSION + && profileClass != ICC_Profile.CLASS_NAMEDCOLOR + && profileClass != ICC_Profile.CLASS_ABSTRACT) { + throw new IllegalArgumentException("Invalid profile class"); } thisProfile = profile; diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index e1424f2cc86..1a3e650a1b7 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, 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 @@ -722,6 +722,7 @@ public class ICC_Profile implements Serializable { */ public static final int icXYZNumberX = 8; /* XYZNumber X */ + private static final int HEADER_SIZE = 128; /** * Constructs an ICC_Profile object with a given ID. @@ -773,6 +774,10 @@ public static ICC_Profile getInstance(byte[] data) { ProfileDataVerifier.verify(data); try { + byte[] theHeader = new byte[HEADER_SIZE]; + System.arraycopy(data, 0, theHeader, 0, HEADER_SIZE); + verifyHeader(theHeader); + p = CMSManager.getModule().loadProfile(data); } catch (CMMException c) { throw new IllegalArgumentException("Invalid ICC Profile Data"); @@ -1092,16 +1097,18 @@ public int getMinorVersion() { * @return One of the predefined profile class constants. */ public int getProfileClass() { - byte[] theHeader; - int theClassSig, theClass; ProfileDeferralInfo info = deferralInfo; if (info != null) { return info.profileClass; } - theHeader = getData(icSigHead); + byte[] theHeader = getData(icSigHead); + return getProfileClass(theHeader); + } + private static int getProfileClass(byte[] theHeader) { + int theClassSig, theClass; theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass); switch (theClassSig) { @@ -1171,6 +1178,11 @@ static int getColorSpaceType(Profile p) { return theColorSpace; } + private static int getColorSpaceType(byte[] theHeader) { + int theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace); + return iccCStoJCS(theColorSpaceSig); + } + /** * Returns the color space type of the Profile Connection Space (PCS). * Returns one of the color space type constants defined by the @@ -1200,6 +1212,29 @@ static int getPCSType(Profile p) { } + private static int getPCSType(byte[] theHeader) { + int thePCSSig = intFromBigEndian(theHeader, icHdrPcs); + int theDeviceClass = intFromBigEndian(theHeader, icHdrDeviceClass); + int thePCSType; + + if (theDeviceClass == icSigLinkClass) { + return iccCStoJCS(thePCSSig); + } else { + switch (thePCSSig) { + case icSigXYZData: + thePCSType = ColorSpace.TYPE_XYZ; + break; + case icSigLabData: + thePCSType = ColorSpace.TYPE_Lab; + break; + default: + throw new IllegalArgumentException("Unexpected PCS type"); + }; + } + + return thePCSType; + } + /** * Write this ICC_Profile to a file. * @@ -1324,12 +1359,49 @@ static byte[] getData(Profile p, int tagSignature) { * @see #getData */ public void setData(int tagSignature, byte[] tagData) { + if (tagSignature == ICC_Profile.icSigHead) { + verifyHeader(tagData); + } activate(); CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData); } + private static void verifyHeader(byte[] data) { + if (data == null || data.length < HEADER_SIZE) { + throw new IllegalArgumentException("Invalid header data"); + } + getProfileClass(data); + getColorSpaceType(data); + getPCSType(data); + checkRenderingIntent(data); + } + + private static boolean checkRenderingIntent(byte[] header) { + int index = ICC_Profile.icHdrRenderingIntent; + + /* According to ICC spec, only the least-significant 16 bits shall be + * used to encode the rendering intent. The most significant 16 bits + * shall be set to zero. Thus, we are ignoring two most significant + * bytes here. Please refer ICC Spec Document for more details. + */ + int renderingIntent = ((header[index+2] & 0xff) << 8) | + (header[index+3] & 0xff); + + switch (renderingIntent) { + case icPerceptual: + case icMediaRelativeColorimetric: + case icSaturation: + case icAbsoluteColorimetric: + break; + default: + throw new IllegalArgumentException("Unknown Rendering Intent"); + } + + return true; + } + /** * Sets the rendering intent of the profile. * This is used to select the proper transform from a profile that diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index 91a9b8e15cc..95df56b04c0 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, 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 @@ -31,43 +31,9 @@ #include "Trace.h" #include "Disposer.h" #include +#include #include "jlong.h" - -#define ALIGNLONG(x) (((x)+3) & ~(3)) // Aligns to DWORD boundary - -#ifdef USE_BIG_ENDIAN -#define AdjustEndianess32(a) -#else - -static -void AdjustEndianess32(cmsUInt8Number *pByte) -{ - cmsUInt8Number temp1; - cmsUInt8Number temp2; - - temp1 = *pByte++; - temp2 = *pByte++; - *(pByte-1) = *pByte; - *pByte++ = temp2; - *(pByte-3) = *pByte; - *pByte = temp1; -} - -#endif - -// Transports to properly encoded values - note that icc profiles does use -// big endian notation. - -static -cmsInt32Number TransportValue32(cmsInt32Number Value) -{ - cmsInt32Number Temp = Value; - - AdjustEndianess32((cmsUInt8Number*) &Temp); - return Temp; -} - #define SigMake(a,b,c,d) \ ( ( ((int) ((unsigned char) (a))) << 24) | \ ( ((int) ((unsigned char) (b))) << 16) | \ @@ -784,16 +750,18 @@ static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) memcpy(&pfHeader, pBuffer, sizeof(cmsICCHeader)); // now set header fields, which we can access using the lcms2 public API - cmsSetHeaderFlags(pf, pfHeader.flags); - cmsSetHeaderManufacturer(pf, pfHeader.manufacturer); - cmsSetHeaderModel(pf, pfHeader.model); - cmsSetHeaderAttributes(pf, pfHeader.attributes); + cmsSetHeaderFlags(pf, _cmsAdjustEndianess32(pfHeader.flags)); + cmsSetHeaderManufacturer(pf, _cmsAdjustEndianess32(pfHeader.manufacturer)); + cmsSetHeaderModel(pf, _cmsAdjustEndianess32(pfHeader.model)); + cmsUInt64Number attributes; + _cmsAdjustEndianess64(&attributes, &pfHeader.attributes); + cmsSetHeaderAttributes(pf, attributes); cmsSetHeaderProfileID(pf, (cmsUInt8Number*)&(pfHeader.profileID)); - cmsSetHeaderRenderingIntent(pf, pfHeader.renderingIntent); - cmsSetPCS(pf, pfHeader.pcs); - cmsSetColorSpace(pf, pfHeader.colorSpace); - cmsSetDeviceClass(pf, pfHeader.deviceClass); - cmsSetEncodedICCversion(pf, pfHeader.version); + cmsSetHeaderRenderingIntent(pf, _cmsAdjustEndianess32(pfHeader.renderingIntent)); + cmsSetPCS(pf, _cmsAdjustEndianess32(pfHeader.pcs)); + cmsSetColorSpace(pf, _cmsAdjustEndianess32(pfHeader.colorSpace)); + cmsSetDeviceClass(pf, _cmsAdjustEndianess32(pfHeader.deviceClass)); + cmsSetEncodedICCversion(pf, _cmsAdjustEndianess32(pfHeader.version)); return TRUE; } diff --git a/test/jdk/java/awt/color/ICC_Profile/SetHeaderInfo.java b/test/jdk/java/awt/color/ICC_Profile/SetHeaderInfo.java new file mode 100644 index 00000000000..89e06c216ef --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/SetHeaderInfo.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021, 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 java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.util.Arrays; + +/** + * @test + * @bug 8263622 + * @summary The ICC_Profile#setData invert the order of bytes for the "head" tag + */ +public final class SetHeaderInfo { + + public static void main(String[] args) { + int[] cspaces = {ColorSpace.CS_sRGB, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_CIEXYZ, ColorSpace.CS_PYCC, + ColorSpace.CS_GRAY}; + for (int cspace : cspaces) { + ICC_Profile icc = ICC_Profile.getInstance(cspace); + testSame(icc); + testCustom(icc); + // some corner cases + negative(icc, null); + negative(icc, new byte[0]); + negative(icc, new byte[1]); + byte[] header = icc.getData(ICC_Profile.icSigHead); + negative(icc, new byte[header.length - 1]); + } + } + + private static void testSame(ICC_Profile icc) { + byte[] expected = icc.getData(ICC_Profile.icSigHead); + icc.setData(ICC_Profile.icSigHead, expected); + byte[] actual = icc.getData(ICC_Profile.icSigHead); + if (!Arrays.equals(expected, actual)) { + System.err.println("Expected: " + Arrays.toString(expected)); + System.err.println("Actual: " + Arrays.toString(actual)); + throw new RuntimeException(); + } + } + + private static void testCustom(ICC_Profile icc) { + byte[] expected = icc.getData(ICC_Profile.icSigHead); + // small modification of the default profile + expected[ICC_Profile.icHdrFlags + 3] = 1; + expected[ICC_Profile.icHdrModel + 3] = 1; + icc.setData(ICC_Profile.icSigHead, expected); + byte[] actual = icc.getData(ICC_Profile.icSigHead); + if (!Arrays.equals(expected, actual)) { + System.err.println("Expected: " + Arrays.toString(expected)); + System.err.println("Actual: " + Arrays.toString(actual)); + throw new RuntimeException(); + } + } + + private static void negative(ICC_Profile icc, byte[] tagData) { + try { + icc.setData(ICC_Profile.icSigHead, tagData); + throw new RuntimeException("IllegalArgumentException expected"); + } catch (IllegalArgumentException iae) { + // expected + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java new file mode 100644 index 00000000000..28831a422b0 --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/ValidateICCHeaderData.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2025, 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 8337703 + * @summary To verify if ICC_Profile's setData() and getInstance() methods + * validate header data and throw IAE for invalid values. + * @run main ValidateICCHeaderData + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; + +public class ValidateICCHeaderData { + private static ICC_Profile profile; + + private static final boolean DEBUG = false; + private static final int VALID_HEADER_SIZE = 128; + private static final int HEADER_TAG = ICC_Profile.icSigHead; + private static final int PROFILE_CLASS_START_INDEX = ICC_Profile.icHdrDeviceClass; + private static final int COLOR_SPACE_START_INDEX = ICC_Profile.icHdrColorSpace; + private static final int RENDER_INTENT_START_INDEX = ICC_Profile.icHdrRenderingIntent; + private static final int PCS_START_INDEX = ICC_Profile.icHdrPcs; + + private static final int[] VALID_PROFILE_CLASS = new int[] { + ICC_Profile.icSigInputClass, ICC_Profile.icSigDisplayClass, + ICC_Profile.icSigOutputClass, ICC_Profile.icSigLinkClass, + ICC_Profile.icSigAbstractClass, ICC_Profile.icSigColorSpaceClass, + ICC_Profile.icSigNamedColorClass + }; + + private static final int[] VALID_COLOR_SPACE = new int[] { + ICC_Profile.icSigXYZData, ICC_Profile.icSigLabData, + ICC_Profile.icSigLuvData, ICC_Profile.icSigYCbCrData, + ICC_Profile.icSigYxyData, ICC_Profile.icSigRgbData, + ICC_Profile.icSigGrayData, ICC_Profile.icSigHsvData, + ICC_Profile.icSigHlsData, ICC_Profile.icSigCmykData, + ICC_Profile.icSigSpace2CLR, ICC_Profile.icSigSpace3CLR, + ICC_Profile.icSigSpace4CLR, ICC_Profile.icSigSpace5CLR, + ICC_Profile.icSigSpace6CLR, ICC_Profile.icSigSpace7CLR, + ICC_Profile.icSigSpace8CLR, ICC_Profile.icSigSpace9CLR, + ICC_Profile.icSigSpaceACLR, ICC_Profile.icSigSpaceBCLR, + ICC_Profile.icSigSpaceCCLR, ICC_Profile.icSigSpaceDCLR, + ICC_Profile.icSigSpaceECLR, ICC_Profile.icSigSpaceFCLR, + ICC_Profile.icSigCmyData + }; + + private static final int[] VALID_RENDER_INTENT = new int[] { + ICC_Profile.icPerceptual, ICC_Profile.icMediaRelativeColorimetric, + ICC_Profile.icSaturation, ICC_Profile.icAbsoluteColorimetric + }; + + private static void createCopyOfBuiltInProfile() { + ICC_Profile builtInProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + //copy of SRGB BuiltIn Profile that can be modified + //using ICC_Profile.setData() + profile = ICC_Profile.getInstance(builtInProfile.getData()); + } + + public static void main(String[] args) throws Exception { + createCopyOfBuiltInProfile(); + + System.out.println("CASE 1: Testing VALID Profile Classes ..."); + testValidHeaderData(VALID_PROFILE_CLASS, PROFILE_CLASS_START_INDEX, 4); + System.out.println("CASE 1: Passed \n"); + + // PCS field validation for Profile class != DEVICE_LINK + System.out.println("CASE 2: Testing VALID PCS Type" + + " for Profile class != DEVICE_LINK ..."); + testValidHeaderData(new int[] {ICC_Profile.icSigXYZData, ICC_Profile.icSigLabData}, + PCS_START_INDEX, 4); + System.out.println("CASE 2: Passed \n"); + + System.out.println("CASE 3: Testing INVALID PCS Type" + + " for Profile class != DEVICE_LINK ..."); + testInvalidHeaderData(ICC_Profile.icSigCmykData, PCS_START_INDEX, 4); + System.out.println("CASE 3: Passed \n"); + + System.out.println("CASE 4: Testing DEVICE LINK PROFILE CLASS ..."); + testValidHeaderData(new int[] {ICC_Profile.icSigLinkClass}, + PROFILE_CLASS_START_INDEX, 4); + //to check if instantiating BufferedImage with + //ICC_Profile device class = CLASS_DEVICELINK does not throw IAE. + BufferedImage img = new BufferedImage(100, 100, + BufferedImage.TYPE_3BYTE_BGR); + System.out.println("CASE 4: Passed \n"); + + // PCS field validation for Profile class == DEVICE_LINK + System.out.println("CASE 5: Testing VALID PCS Type" + + " for Profile class == DEVICE_LINK ..."); + testValidHeaderData(VALID_COLOR_SPACE, PCS_START_INDEX, 4); + System.out.println("CASE 5: Passed \n"); + + System.out.println("CASE 6: Testing INVALID PCS Type" + + " for Profile class == DEVICE_LINK ..."); + //original icSigLabData = 0x4C616220 + int invalidSigLabData = 0x4C616221; + testInvalidHeaderData(invalidSigLabData, PCS_START_INDEX, 4); + System.out.println("CASE 6: Passed \n"); + + System.out.println("CASE 7: Testing VALID Color Spaces ..."); + testValidHeaderData(VALID_COLOR_SPACE, COLOR_SPACE_START_INDEX, 4); + System.out.println("CASE 7: Passed \n"); + + System.out.println("CASE 8: Testing VALID Rendering Intent ..."); + testValidHeaderData(VALID_RENDER_INTENT, RENDER_INTENT_START_INDEX, 4); + System.out.println("CASE 8: Passed \n"); + + System.out.println("CASE 9: Testing INVALID Profile Class ..."); + //original icSigInputClass = 0x73636E72 + int invalidSigInputClass = 0x73636E70; + testInvalidHeaderData(invalidSigInputClass, PROFILE_CLASS_START_INDEX, 4); + System.out.println("CASE 9: Passed \n"); + + System.out.println("CASE 10: Testing INVALID Color Space ..."); + //original icSigXYZData = 0x58595A20 + int invalidSigXYZData = 0x58595A21; + testInvalidHeaderData(invalidSigXYZData, COLOR_SPACE_START_INDEX, 4); + System.out.println("CASE 10: Passed \n"); + + System.out.println("CASE 11: Testing INVALID Rendering Intent ..."); + //valid rendering intent values are 0-3 + int invalidRenderIntent = 5; + testInvalidHeaderData(invalidRenderIntent, RENDER_INTENT_START_INDEX, 4); + System.out.println("CASE 11: Passed \n"); + + System.out.println("CASE 12: Testing INVALID Header Size ..."); + testInvalidHeaderSize(); + System.out.println("CASE 12: Passed \n"); + + System.out.println("CASE 13: Testing ICC_Profile.getInstance(..)" + + " with VALID profile data ..."); + testProfileCreation(true); + System.out.println("CASE 13: Passed \n"); + + System.out.println("CASE 14: Testing ICC_Profile.getInstance(..)" + + " with INVALID profile data ..."); + testProfileCreation(false); + System.out.println("CASE 14: Passed \n"); + + System.out.println("CASE 15: Testing Deserialization of ICC_Profile ..."); + testDeserialization(); + System.out.println("CASE 15: Passed \n"); + + System.out.println("Successfully completed testing all 15 cases. Test Passed !!"); + } + + private static void testValidHeaderData(int[] validData, int startIndex, + int fieldLength) { + for (int value : validData) { + setTag(value, startIndex, fieldLength); + } + } + + private static void testInvalidHeaderData(int invalidData, int startIndex, + int fieldLength) { + try { + setTag(invalidData, startIndex, fieldLength); + throw new RuntimeException("Test Failed ! Expected IAE NOT thrown"); + } catch (IllegalArgumentException iae) { + System.out.println("Expected IAE thrown: " + iae.getMessage()); + } + } + + private static void setTag(int value, int startIndex, int fieldLength) { + byte[] byteArray; + if (startIndex == RENDER_INTENT_START_INDEX) { + byteArray = ByteBuffer.allocate(4).putInt(value).array(); + } else { + BigInteger big = BigInteger.valueOf(value); + byteArray = (big.toByteArray()); + } + + if (DEBUG) { + System.out.print("Byte Array : "); + for (int i = 0; i < byteArray.length; i++) { + System.out.print(byteArray[i] + " "); + } + System.out.println("\n"); + } + + byte[] iccProfileHeaderData = profile.getData(HEADER_TAG); + System.arraycopy(byteArray, 0, iccProfileHeaderData, startIndex, fieldLength); + profile.setData(HEADER_TAG, iccProfileHeaderData); + } + + private static void testProfileCreation(boolean validCase) { + ICC_Profile builtInProfile = ICC_Profile.getInstance(ColorSpace.CS_GRAY); + byte[] profileData = builtInProfile.getData(); + + int validDeviceClass = ICC_Profile.icSigInputClass; + BigInteger big = BigInteger.valueOf(validDeviceClass); + //valid case set device class to 0x73636E72 (icSigInputClass) + //invalid case set device class to 0x00000000 + byte[] field = validCase ? big.toByteArray() + : ByteBuffer.allocate(4).putInt(0).array(); + System.arraycopy(field, 0, profileData, PROFILE_CLASS_START_INDEX, 4); + + try { + ICC_Profile.getInstance(profileData); + if (!validCase) { + throw new RuntimeException("Test Failed ! Expected IAE NOT thrown"); + } + } catch (IllegalArgumentException iae) { + if (!validCase) { + System.out.println("Expected IAE thrown: " + iae.getMessage()); + } else { + throw new RuntimeException("Unexpected IAE thrown"); + } + } + } + + private static void testInvalidHeaderSize() { + byte[] iccProfileHeaderData = profile.getData(HEADER_TAG); + byte[] invalidHeaderSize = new byte[VALID_HEADER_SIZE - 1]; + System.arraycopy(iccProfileHeaderData, 0, + invalidHeaderSize, 0, invalidHeaderSize.length); + try { + profile.setData(HEADER_TAG, invalidHeaderSize); + throw new RuntimeException("Test Failed ! Expected IAE NOT thrown"); + } catch (IllegalArgumentException iae) { + System.out.println("Expected IAE thrown: " + iae.getMessage()); + } + } + + private static void testDeserialization() throws IOException { + //invalidSRGB.icc is serialized on older version of JDK + //Upon deserialization, the invalid profile is expected to throw IAE + try { + ICC_Profile.getInstance("./invalidSRGB.icc"); + throw new RuntimeException("Test Failed ! Expected IAE NOT thrown"); + } catch (IllegalArgumentException iae) { + System.out.println("Expected IAE thrown: " + iae.getMessage()); + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/invalidSRGB.icc b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/invalidSRGB.icc new file mode 100644 index 00000000000..1520dac1f1a Binary files /dev/null and b/test/jdk/java/awt/color/ICC_Profile/ValidateICCHeaderData/invalidSRGB.icc differ