8346465: Add a check in setData() to restrict the update of Built-In ICC_Profiles
Reviewed-by: aivanov, jdv, prr, serb
This commit is contained in:
parent
af5db51306
commit
3131dd1d5c
@ -107,6 +107,14 @@ public sealed class ICC_Profile implements Serializable
|
||||
*/
|
||||
private transient volatile ProfileDeferralInfo deferralInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Set to {@code true} for {@code BuiltInProfile}, {@code false} otherwise.
|
||||
* This flag is used in {@link #setData(int, byte[])} to prevent modifying
|
||||
* built-in profiles.
|
||||
*/
|
||||
private final transient boolean builtIn;
|
||||
|
||||
/**
|
||||
* The lazy registry of singleton profile objects for specific built-in
|
||||
* color spaces defined in the ColorSpace class (e.g. CS_sRGB),
|
||||
@ -114,8 +122,8 @@ public sealed class ICC_Profile implements Serializable
|
||||
*/
|
||||
private interface BuiltInProfile {
|
||||
/*
|
||||
* Deferral is only used for standard profiles. Enabling the appropriate
|
||||
* access privileges is handled at a lower level.
|
||||
* ProfileDeferralInfo is used for built-in profile creation only,
|
||||
* and all built-in profiles should be constructed using it.
|
||||
*/
|
||||
ICC_Profile SRGB = new ICC_ProfileRGB(new ProfileDeferralInfo(
|
||||
"sRGB.pf", ColorSpace.TYPE_RGB, 3, CLASS_DISPLAY));
|
||||
@ -763,14 +771,20 @@ public sealed class ICC_Profile implements Serializable
|
||||
*/
|
||||
ICC_Profile(Profile p) {
|
||||
cmmProfile = p;
|
||||
builtIn = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an {@code ICC_Profile} object whose loading will be deferred.
|
||||
* The ID will be 0 until the profile is loaded.
|
||||
*
|
||||
* <p>
|
||||
* Note: {@code ProfileDeferralInfo} is used for built-in profile
|
||||
* creation only, and all built-in profiles should be constructed using it.
|
||||
*/
|
||||
ICC_Profile(ProfileDeferralInfo pdi) {
|
||||
deferralInfo = pdi;
|
||||
builtIn = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1131,17 +1145,34 @@ public sealed class ICC_Profile implements Serializable
|
||||
* This method is useful for advanced applications which need to access
|
||||
* profile data directly.
|
||||
*
|
||||
* <p>
|
||||
* Note: JDK built-in ICC Profiles cannot be updated using this method
|
||||
* as it will result in {@code IllegalArgumentException}. JDK built-in
|
||||
* profiles are those obtained by {@code ICC_Profile.getInstance(int colorSpaceID)}
|
||||
* where {@code colorSpaceID} is one of the following:
|
||||
* {@link ColorSpace#CS_sRGB}, {@link ColorSpace#CS_LINEAR_RGB},
|
||||
* {@link ColorSpace#CS_PYCC}, {@link ColorSpace#CS_GRAY} or
|
||||
* {@link ColorSpace#CS_CIEXYZ}.
|
||||
*
|
||||
* @param tagSignature the ICC tag signature for the data element you want
|
||||
* to set
|
||||
* @param tagData the data to set for the specified tag signature
|
||||
* @throws IllegalArgumentException if {@code tagSignature} is not a
|
||||
* signature as defined in the ICC specification.
|
||||
* @throws IllegalArgumentException if a content of the {@code tagData}
|
||||
* @throws IllegalArgumentException if the content of the {@code tagData}
|
||||
* array can not be interpreted as valid tag data, corresponding to
|
||||
* the {@code tagSignature}
|
||||
* @throws IllegalArgumentException if this is a built-in profile for one
|
||||
* of the pre-defined color spaces, that is those which can be obtained
|
||||
* by calling {@code ICC_Profile.getInstance(int colorSpaceID)}
|
||||
* @see #getData
|
||||
* @see ColorSpace
|
||||
*/
|
||||
public void setData(int tagSignature, byte[] tagData) {
|
||||
if (builtIn) {
|
||||
throw new IllegalArgumentException("Built-in profile cannot be modified");
|
||||
}
|
||||
|
||||
if (tagSignature == ICC_Profile.icSigHead) {
|
||||
verifyHeader(tagData);
|
||||
}
|
||||
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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 8346465
|
||||
* @summary Tests if setData() throws IAE for BuiltIn profiles
|
||||
*/
|
||||
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
public class BuiltInProfileCheck {
|
||||
private static final int HEADER_TAG = ICC_Profile.icSigHead;
|
||||
private static final int INDEX = ICC_Profile.icHdrDeviceClass;
|
||||
private static final String EXCEPTION_MSG = "Built-in profile cannot be modified";
|
||||
/**
|
||||
* {@link #prepareTestProfile(String, boolean, int)}
|
||||
* stores the profile to test in testProfile.
|
||||
*/
|
||||
private static ICC_Profile testProfile;
|
||||
|
||||
private static final Map<Integer, String> colorSpace = Map.of(
|
||||
ColorSpace.CS_sRGB, "CS_sRGB",
|
||||
ColorSpace.CS_PYCC, "CS_PYCC",
|
||||
ColorSpace.CS_GRAY, "CS_GRAY",
|
||||
ColorSpace.CS_CIEXYZ, "CS_CIEXYZ",
|
||||
ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB"
|
||||
);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("CASE 1: Testing BuiltIn Profile");
|
||||
for (int cs : colorSpace.keySet()) {
|
||||
prepareTestProfile("Default", true, cs);
|
||||
testProfile(true, cs);
|
||||
}
|
||||
System.out.println("Passed\n");
|
||||
|
||||
System.out.println("CASE 2: Testing Custom Profile");
|
||||
prepareTestProfile("Default", false, ColorSpace.CS_sRGB);
|
||||
testProfile(false, ColorSpace.CS_sRGB);
|
||||
System.out.println("Passed\n");
|
||||
|
||||
System.out.println("CASE 3: Testing Built-In Profile"
|
||||
+ " Serialization & Deserialization");
|
||||
for (int cs : colorSpace.keySet()) {
|
||||
prepareTestProfile("Serialize", true, cs);
|
||||
testProfile(true, cs);
|
||||
}
|
||||
System.out.println("Passed\n");
|
||||
|
||||
System.out.println("CASE 4: Testing Custom Profile"
|
||||
+ " Serialization & Deserialization");
|
||||
prepareTestProfile("Serialize", false, ColorSpace.CS_sRGB);
|
||||
testProfile(false, ColorSpace.CS_sRGB);
|
||||
System.out.println("Passed\n");
|
||||
|
||||
System.out.println("CASE 5: Test reading Built-In profile from .icc file");
|
||||
prepareTestProfile("ReadFromFile", true, ColorSpace.CS_sRGB);
|
||||
testProfile(true, ColorSpace.CS_sRGB);
|
||||
System.out.println("Passed\n");
|
||||
|
||||
System.out.println("CASE 6: Test reading Custom profile from .icc file");
|
||||
prepareTestProfile("ReadFromFile", false, ColorSpace.CS_sRGB);
|
||||
testProfile(false, ColorSpace.CS_sRGB);
|
||||
System.out.println("Passed\n");
|
||||
}
|
||||
|
||||
private static void prepareTestProfile(String testCase,
|
||||
boolean isBuiltIn, int cs) {
|
||||
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
|
||||
// if isBuiltIn=true use builtInProfile else create a copy
|
||||
testProfile = isBuiltIn
|
||||
? builtInProfile
|
||||
: ICC_Profile.getInstance(builtInProfile.getData());
|
||||
|
||||
switch (testCase) {
|
||||
case "Default" -> {
|
||||
// empty case block
|
||||
// no further processing of testProfile required for default case
|
||||
}
|
||||
case "Serialize" -> {
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
oos.writeObject(testProfile);
|
||||
|
||||
byte[] array = baos.toByteArray();
|
||||
try (ObjectInputStream ois =
|
||||
new ObjectInputStream(new ByteArrayInputStream(array))) {
|
||||
testProfile = (ICC_Profile) ois.readObject();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Test Failed ! Serial-Deserialization"
|
||||
+ " case failed", e);
|
||||
}
|
||||
}
|
||||
case "ReadFromFile" -> {
|
||||
// .icc files serialized on older JDK version
|
||||
String filename = isBuiltIn ? "builtIn.icc" : "custom.icc";
|
||||
String testDir = System.getProperty("test.src")
|
||||
+ System.getProperty("file.separator");
|
||||
filename = testDir + filename;
|
||||
|
||||
try (FileInputStream fileIn = new FileInputStream(filename);
|
||||
ObjectInputStream ois = new ObjectInputStream(fileIn)) {
|
||||
testProfile = (ICC_Profile) ois.readObject();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Test Failed ! Unable to fetch"
|
||||
+ " .icc files", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testProfile(boolean isBuiltIn, int cs) {
|
||||
byte[] headerData = testProfile.getData(HEADER_TAG);
|
||||
// Set profile class to valid icSigInputClass = 0x73636E72
|
||||
headerData[INDEX] = 0x73;
|
||||
headerData[INDEX + 1] = 0x63;
|
||||
headerData[INDEX + 2] = 0x6E;
|
||||
headerData[INDEX + 3] = 0x72;
|
||||
|
||||
if (isBuiltIn) {
|
||||
System.out.println("Testing: " + colorSpace.get(cs));
|
||||
try {
|
||||
// Try updating a built-in profile, IAE is expected
|
||||
testProfile.setData(HEADER_TAG, headerData);
|
||||
throw new RuntimeException("Test Failed! IAE NOT thrown for profile "
|
||||
+ colorSpace.get(cs));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (!iae.getMessage().equals(EXCEPTION_MSG)) {
|
||||
throw new RuntimeException("Test Failed! IAE with exception msg \""
|
||||
+ EXCEPTION_MSG + "\" NOT thrown for profile "
|
||||
+ colorSpace.get(cs));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Modifying custom profile should NOT throw IAE
|
||||
testProfile.setData(HEADER_TAG, headerData);
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 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
|
||||
@ -37,7 +37,9 @@ public final class SetHeaderInfo {
|
||||
ColorSpace.CS_CIEXYZ, ColorSpace.CS_PYCC,
|
||||
ColorSpace.CS_GRAY};
|
||||
for (int cspace : cspaces) {
|
||||
ICC_Profile icc = ICC_Profile.getInstance(cspace);
|
||||
ICC_Profile builtInProfile = ICC_Profile.getInstance(cspace);
|
||||
ICC_Profile icc = ICC_Profile.getInstance(builtInProfile.getData());
|
||||
|
||||
testSame(icc);
|
||||
testCustom(icc);
|
||||
// some corner cases
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 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
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @test
|
||||
@ -30,22 +31,25 @@ import java.awt.color.ICC_Profile;
|
||||
* @summary Test checks behavior of the ICC_Profile.setData(int, byte[])
|
||||
*/
|
||||
public final class ICC_ProfileSetNullDataTest {
|
||||
private static final Map<Integer, String> colorSpace = Map.of(
|
||||
ColorSpace.CS_sRGB, "CS_sRGB",
|
||||
ColorSpace.CS_PYCC, "CS_PYCC",
|
||||
ColorSpace.CS_GRAY, "CS_GRAY",
|
||||
ColorSpace.CS_CIEXYZ, "CS_CIEXYZ",
|
||||
ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB"
|
||||
);
|
||||
|
||||
public static void main(String[] args) {
|
||||
test(ICC_Profile.getInstance(ColorSpace.CS_sRGB));
|
||||
test(ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB));
|
||||
test(ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ));
|
||||
test(ICC_Profile.getInstance(ColorSpace.CS_PYCC));
|
||||
test(ICC_Profile.getInstance(ColorSpace.CS_GRAY));
|
||||
}
|
||||
|
||||
private static void test(ICC_Profile profile) {
|
||||
byte[] tagData = null;
|
||||
try {
|
||||
profile.setData(ICC_Profile.icSigCmykData, tagData);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return;
|
||||
for (int cs : colorSpace.keySet()) {
|
||||
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
|
||||
ICC_Profile profile = ICC_Profile.getInstance(builtInProfile.getData());
|
||||
try {
|
||||
profile.setData(ICC_Profile.icSigCmykData, null);
|
||||
throw new RuntimeException("IAE expected, but not thrown for "
|
||||
+ "ColorSpace: " + colorSpace.get(cs));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// IAE expected
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("IllegalArgumentException expected");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 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
|
||||
@ -29,7 +29,6 @@
|
||||
* @run main SetDataTest
|
||||
*/
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.awt.color.ICC_Profile;
|
||||
@ -47,7 +46,8 @@ public class SetDataTest {
|
||||
static byte[] invalidTRCData;
|
||||
|
||||
static {
|
||||
profile = ICC_Profile.getInstance(CS_GRAY);
|
||||
ICC_Profile builtInProfile = ICC_Profile.getInstance(CS_GRAY);
|
||||
profile = ICC_Profile.getInstance(builtInProfile.getData());
|
||||
validTRCdata = profile.getData(icSigGrayTRCTag);
|
||||
invalidTRCData = new byte[]{0x42, 0x42, 0x42, 0x42, 1, 3, 4, 6,};
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user