Skip to content

Commit d8ecef5

Browse files
Harshitha Onkarjankratochvil
authored andcommitted
8346465: Add a check in setData() to restrict the update of Built-In ICC_Profiles
Reviewed-by: aivanov, jdv, prr, serb
1 parent 853ca11 commit d8ecef5

File tree

7 files changed

+270
-14
lines changed

7 files changed

+270
-14
lines changed

jdk/src/share/classes/java/awt/color/ICC_Profile.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ public class ICC_Profile implements Serializable {
108108
private static ICC_Profile GRAYprofile;
109109
private static ICC_Profile LINEAR_RGBprofile;
110110

111+
/**
112+
* Set to {@code true} for {@code BuiltInProfile}, {@code false} otherwise.
113+
* This flag is used in {@link #setData(int, byte[])} to prevent modifying
114+
* built-in profiles.
115+
*/
116+
private final transient boolean builtIn;
111117

112118
/**
113119
* Profile class is input.
@@ -729,16 +735,22 @@ public class ICC_Profile implements Serializable {
729735
* Constructs an ICC_Profile object with a given ID.
730736
*/
731737
ICC_Profile(Profile p) {
732-
this.cmmProfile = p;
738+
cmmProfile = p;
739+
builtIn = false;
733740
}
734741

735742

736743
/**
737744
* Constructs an ICC_Profile object whose loading will be deferred.
738745
* The ID will be 0 until the profile is loaded.
746+
*
747+
* <p>
748+
* Note: {@code ProfileDeferralInfo} is used for built-in profile
749+
* creation only, and all built-in profiles should be constructed using it.
739750
*/
740751
ICC_Profile(ProfileDeferralInfo pdi) {
741752
deferralInfo = pdi;
753+
builtIn = true;
742754
}
743755

744756

@@ -1340,17 +1352,34 @@ static byte[] getData(Profile p, int tagSignature) {
13401352
* This method is useful for advanced applets or applications which need to
13411353
* access profile data directly.
13421354
*
1343-
* @param tagSignature The ICC tag signature for the data element
1344-
* you want to set.
1345-
* @param tagData the data to set for the specified tag signature
1346-
* @throws IllegalArgumentException if {@code tagSignature} is not a signature
1347-
* as defined in the ICC specification.
1348-
* @throws IllegalArgumentException if a content of the {@code tagData}
1349-
* array can not be interpreted as valid tag data, corresponding
1350-
* to the {@code tagSignature}.
1355+
* <p>
1356+
* Note: JDK built-in ICC Profiles cannot be updated using this method
1357+
* as it will result in {@code IllegalArgumentException}. JDK built-in
1358+
* profiles are those obtained by {@code ICC_Profile.getInstance(int colorSpaceID)}
1359+
* where {@code colorSpaceID} is one of the following:
1360+
* {@link ColorSpace#CS_sRGB}, {@link ColorSpace#CS_LINEAR_RGB},
1361+
* {@link ColorSpace#CS_PYCC}, {@link ColorSpace#CS_GRAY} or
1362+
* {@link ColorSpace#CS_CIEXYZ}.
1363+
*
1364+
* @param tagSignature the ICC tag signature for the data element you want
1365+
* to set
1366+
* @param tagData the data to set for the specified tag signature
1367+
* @throws IllegalArgumentException if {@code tagSignature} is not a
1368+
* signature as defined in the ICC specification.
1369+
* @throws IllegalArgumentException if the content of the {@code tagData}
1370+
* array can not be interpreted as valid tag data, corresponding to
1371+
* the {@code tagSignature}
1372+
* @throws IllegalArgumentException if this is a built-in profile for one
1373+
* of the pre-defined color spaces, that is those which can be obtained
1374+
* by calling {@code ICC_Profile.getInstance(int colorSpaceID)}
13511375
* @see #getData
1376+
* @see ColorSpace
13521377
*/
13531378
public void setData(int tagSignature, byte[] tagData) {
1379+
if (builtIn) {
1380+
throw new IllegalArgumentException("Built-in profile cannot be modified");
1381+
}
1382+
13541383
if (tagSignature == ICC_Profile.icSigHead) {
13551384
verifyHeader(tagData);
13561385
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8346465
27+
* @summary Tests if setData() throws IAE for BuiltIn profiles
28+
*/
29+
30+
import java.awt.color.ColorSpace;
31+
import java.awt.color.ICC_Profile;
32+
import java.io.ByteArrayInputStream;
33+
import java.io.ByteArrayOutputStream;
34+
import java.io.FileInputStream;
35+
import java.io.ObjectInputStream;
36+
import java.io.ObjectOutputStream;
37+
import java.util.HashMap;
38+
import java.util.Map;
39+
40+
public class BuiltInProfileCheck {
41+
private static final int HEADER_TAG = ICC_Profile.icSigHead;
42+
private static final int INDEX = ICC_Profile.icHdrDeviceClass;
43+
private static final String EXCEPTION_MSG = "Built-in profile cannot be modified";
44+
/**
45+
* {@link #prepareTestProfile(String, boolean, int)}
46+
* stores the profile to test in testProfile.
47+
*/
48+
private static ICC_Profile testProfile;
49+
50+
private static final Map<Integer, String> colorSpace = new HashMap<Integer, String> () {{
51+
put(ColorSpace.CS_sRGB, "CS_sRGB");
52+
put(ColorSpace.CS_PYCC, "CS_PYCC");
53+
put(ColorSpace.CS_GRAY, "CS_GRAY");
54+
put(ColorSpace.CS_CIEXYZ, "CS_CIEXYZ");
55+
put(ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB");
56+
}};
57+
58+
public static void main(String[] args) throws Exception {
59+
System.out.println("CASE 1: Testing BuiltIn Profile");
60+
for (int cs : colorSpace.keySet()) {
61+
prepareTestProfile("Default", true, cs);
62+
testProfile(true, cs);
63+
}
64+
System.out.println("Passed\n");
65+
66+
System.out.println("CASE 2: Testing Custom Profile");
67+
prepareTestProfile("Default", false, ColorSpace.CS_sRGB);
68+
testProfile(false, ColorSpace.CS_sRGB);
69+
System.out.println("Passed\n");
70+
71+
System.out.println("CASE 3: Testing Built-In Profile"
72+
+ " Serialization & Deserialization");
73+
for (int cs : colorSpace.keySet()) {
74+
prepareTestProfile("Serialize", true, cs);
75+
testProfile(true, cs);
76+
}
77+
System.out.println("Passed\n");
78+
79+
System.out.println("CASE 4: Testing Custom Profile"
80+
+ " Serialization & Deserialization");
81+
prepareTestProfile("Serialize", false, ColorSpace.CS_sRGB);
82+
testProfile(false, ColorSpace.CS_sRGB);
83+
System.out.println("Passed\n");
84+
85+
System.out.println("CASE 5: Test reading Built-In profile from .icc file");
86+
prepareTestProfile("ReadFromFile", true, ColorSpace.CS_sRGB);
87+
testProfile(true, ColorSpace.CS_sRGB);
88+
System.out.println("Passed\n");
89+
90+
System.out.println("CASE 6: Test reading Custom profile from .icc file");
91+
prepareTestProfile("ReadFromFile", false, ColorSpace.CS_sRGB);
92+
testProfile(false, ColorSpace.CS_sRGB);
93+
System.out.println("Passed\n");
94+
}
95+
96+
private static void prepareTestProfile(String testCase,
97+
boolean isBuiltIn, int cs) {
98+
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
99+
// if isBuiltIn=true use builtInProfile else create a copy
100+
testProfile = isBuiltIn
101+
? builtInProfile
102+
: ICC_Profile.getInstance(builtInProfile.getData());
103+
104+
switch (testCase) {
105+
case "Default":
106+
// empty case block
107+
// no further processing of testProfile required for default case
108+
break;
109+
case "Serialize":
110+
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
111+
ObjectOutputStream oos = new ObjectOutputStream(baos)) {
112+
oos.writeObject(testProfile);
113+
114+
byte[] array = baos.toByteArray();
115+
try (ObjectInputStream ois =
116+
new ObjectInputStream(new ByteArrayInputStream(array))) {
117+
testProfile = (ICC_Profile) ois.readObject();
118+
}
119+
} catch (Exception e) {
120+
throw new RuntimeException("Test Failed ! Serial-Deserialization"
121+
+ " case failed", e);
122+
}
123+
break;
124+
case "ReadFromFile":
125+
// .icc files serialized on older JDK version
126+
String filename = isBuiltIn ? "builtIn.icc" : "custom.icc";
127+
String testDir = System.getProperty("test.src")
128+
+ System.getProperty("file.separator");
129+
filename = testDir + filename;
130+
131+
try (FileInputStream fileIn = new FileInputStream(filename);
132+
ObjectInputStream ois = new ObjectInputStream(fileIn)) {
133+
testProfile = (ICC_Profile) ois.readObject();
134+
} catch (Exception e) {
135+
throw new RuntimeException("Test Failed ! Unable to fetch"
136+
+ " .icc files", e);
137+
}
138+
break;
139+
}
140+
}
141+
142+
private static void testProfile(boolean isBuiltIn, int cs) {
143+
byte[] headerData = testProfile.getData(HEADER_TAG);
144+
// Set profile class to valid icSigInputClass = 0x73636E72
145+
headerData[INDEX] = 0x73;
146+
headerData[INDEX + 1] = 0x63;
147+
headerData[INDEX + 2] = 0x6E;
148+
headerData[INDEX + 3] = 0x72;
149+
150+
if (isBuiltIn) {
151+
System.out.println("Testing: " + colorSpace.get(cs));
152+
try {
153+
// Try updating a built-in profile, IAE is expected
154+
testProfile.setData(HEADER_TAG, headerData);
155+
throw new RuntimeException("Test Failed! IAE NOT thrown for profile "
156+
+ colorSpace.get(cs));
157+
} catch (IllegalArgumentException iae) {
158+
if (!iae.getMessage().equals(EXCEPTION_MSG)) {
159+
throw new RuntimeException("Test Failed! IAE with exception msg \""
160+
+ EXCEPTION_MSG + "\" NOT thrown for profile "
161+
+ colorSpace.get(cs));
162+
}
163+
}
164+
} else {
165+
// Modifying custom profile should NOT throw IAE
166+
testProfile.setData(HEADER_TAG, headerData);
167+
}
168+
}
169+
}
141 Bytes
Binary file not shown.
6.87 KB
Binary file not shown.

jdk/test/java/awt/color/ICC_Profile/SetHeaderInfo.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,9 @@ public static void main(String[] args) {
3737
ColorSpace.CS_CIEXYZ, ColorSpace.CS_PYCC,
3838
ColorSpace.CS_GRAY};
3939
for (int cspace : cspaces) {
40-
ICC_Profile icc = ICC_Profile.getInstance(cspace);
40+
ICC_Profile builtInProfile = ICC_Profile.getInstance(cspace);
41+
ICC_Profile icc = ICC_Profile.getInstance(builtInProfile.getData());
42+
4143
testSame(icc);
4244
testCustom(icc);
4345
// some corner cases
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import java.awt.color.ColorSpace;
25+
import java.awt.color.ICC_Profile;
26+
import java.util.HashMap;
27+
import java.util.Map;
28+
29+
/**
30+
* @test
31+
* @bug 4823896 7042594
32+
* @summary Test checks behavior of the ICC_Profile.setData(int, byte[])
33+
*/
34+
public final class ICC_ProfileSetNullDataTest {
35+
private static final Map<Integer, String> colorSpace = new HashMap<Integer, String> () {{
36+
put(ColorSpace.CS_sRGB, "CS_sRGB");
37+
put(ColorSpace.CS_PYCC, "CS_PYCC");
38+
put(ColorSpace.CS_GRAY, "CS_GRAY");
39+
put(ColorSpace.CS_CIEXYZ, "CS_CIEXYZ");
40+
put(ColorSpace.CS_LINEAR_RGB, "CS_LINEAR_RGB");
41+
}};
42+
43+
public static void main(String[] args) {
44+
for (int cs : colorSpace.keySet()) {
45+
ICC_Profile builtInProfile = ICC_Profile.getInstance(cs);
46+
ICC_Profile profile = ICC_Profile.getInstance(builtInProfile.getData());
47+
try {
48+
profile.setData(ICC_Profile.icSigCmykData, null);
49+
throw new RuntimeException("IAE expected, but not thrown for "
50+
+ "ColorSpace: " + colorSpace.get(cs));
51+
} catch (IllegalArgumentException e) {
52+
// IAE expected
53+
}
54+
}
55+
}
56+
}

jdk/test/sun/java2d/cmm/ProfileOp/SetDataTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@
2929
* @run main SetDataTest
3030
*/
3131

32-
3332
import java.util.ArrayList;
3433
import java.util.List;
3534
import java.awt.color.ICC_Profile;
@@ -47,7 +46,8 @@ static class TestCase {
4746
static byte[] invalidTRCData;
4847

4948
static {
50-
profile = ICC_Profile.getInstance(CS_GRAY);
49+
ICC_Profile builtInProfile = ICC_Profile.getInstance(CS_GRAY);
50+
profile = ICC_Profile.getInstance(builtInProfile.getData());
5151
validTRCdata = profile.getData(icSigGrayTRCTag);
5252
invalidTRCData = new byte[]{0x42, 0x42, 0x42, 0x42, 1, 3, 4, 6,};
5353
}

0 commit comments

Comments
 (0)